Textures

Images in OpenGL generally take the form of textures, and Cinder exposes this functionality through the class gl::Texture2d and its siblings. Let's look at a basic example:


class BasicApp : public App {
  public:
	void setup() override;
	void draw() override;
	
	gl::Texture2dRef		mTex;
};

void BasicApp::setup()
{
	auto img = loadImage( loadAsset( "clouds.jpg" ) );
	mTex = gl::Texture2d::create( img );
}

void BasicApp::draw()
{
	gl::clear();

	gl::draw( mTex );
}

We're using an image from Trey Ratcliff that's saved in our application's assets directory as "clouds.jpg". We call loadImage() using this asset and then pass the result to the variant of gl::Texture2d::create() which accepts an ImageSource.

Besides simply drawing a texture, we often want to apply one (or more) to the vertices of a 2D or 3D model - a process known as texturemapping. Let's look at a simple example of this in Cinder:


class BasicApp : public App {
  public:	
	void	setup() override;
	void	draw() override;
	
	CameraPersp			mCam;
	gl::BatchRef		mSphere;
	gl::TextureRef		mTexture;
	gl::GlslProgRef		mGlsl;
};

void BasicApp::setup()
{
	mCam.lookAt( vec3( 3, 2, 4 ), vec3( 0 ) );
	
	auto img = loadImage( loadAsset( "checkerboard.png" ) );
	mTexture = gl::Texture::create( img );
	mTexture->bind();

	auto shader = gl::ShaderDef().texture().lambert();
	mGlsl = gl::getStockShader( shader );
	auto sphere = geom::Sphere().subdivisions( 50 );
	mSphere = gl::Batch::create( sphere, mGlsl );
	
	gl::enableDepthWrite();
	gl::enableDepthRead();
}

void BasicApp::draw()
{
	gl::clear( Color( 0.2f, 0.2f, 0.2f ) );
	gl::setMatrices( mCam );

	mSphere->draw();

	// draw the texture itself in the upper right corner	
	gl::setMatricesWindow( getWindowSize() );
	Rectf drawRect( 0, 0, mTexture->getWidth() / 3,
						mTexture->getHeight() / 3 );
	gl::draw( mTexture, drawRect );
}

In this example we load the texture from a file called checkerboard.png, similar to the previous example. However in this case, we're setting up a gl::GlslProg from a gl::ShaderDef with both lambert() and texture() applied. Another key distinction is that we're calling the bind() method on mTexture. Binding a texture is simply making it the active texture. We do this from setup() because we only ever bind one texture. In the draw() method we draw the sphere by calling mSphere->draw(). Finally, we draw the texture itself for illustration purposes. Notice that before we do so, we use gl::setMatricesWindow() to restore our View and Perspective matrices to the window-aligned defaults. Also note that we're using the gl::draw() variant that accepts a Rectf which the texture is mapped to.