tutorial 3

In this tutorial, we will explore textures. Please note that the zip file for this tutorial has not yet been updated.

First we must turn textures on in our OpenGL context. We do this in initGL with the simple statement:


glEnable(GL_TEXTURE_2D);

If we also wish to be able to modify the color of the texture (or any other simple colored objects), we must also write:


glEnable(GL_COLOR_MATERIAL);

We will need to load the textures into texture space. First, we generate texture identifiers with glGenTextures. texture is an array of GLint with size NUMTEXTURES defined in the kGLView class. In this case, we need space for 6 textures (for 6 sides of the die) so NUMTEXTURES is defined as 6.


- (void)getTextures {
// generate the texture objects references
glGenTextures( NUMTEXTURES, texture );
// first we will be working on the each texture individually // we aren't using mipmaps or anything, so we'll just do everything // in a separate method
glBindTexture( GL_TEXTURE_2D, texture[0] ); [self loadPicture: @"one"];
// the other textures are loaded in afterwards


glBindTexture tells OpenGL what kind of texture we will be using (in this case, a 2D texture) and what identifier to use.

We will define a new method called loadPicture. It takes one argument, namely the name of the image to load. Load picture will accept any named picture, which includes pictures that were loaded into the NIB and pictures that had a name set with NSImage's setName method.


- (void) loadPicture: (NSString *) name { NSBitmapImageRep *bitmap; NSImage *image;
// to use a picture, it must be included in the resources (under groups and files) // or alternatively, it may have been loaded as an image and then had a name set // initialize the image to the correct file (name)
image = [ NSImage imageNamed: name ];
// create a bitmap with the correct image data
bitmap = [[NSBitmapImageRep alloc]initWithData: [image TIFFRepresentation]];
// if this bitmap is null, we should really free the texture
if (bitmap == nil) { NSLog(@"in LoadGLTextures : NSBitmapImageRep not loaded"); return; }
// check for yourself about the samples per pixel
NSLog(@"spp: %d, bps: %d, brp: %d", [bitmap samplesPerPixel], [bitmap bitsPerSample], [bitmap bytesPerRow]); NSBitmapImageRep *destinationBitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL pixelsWide:[bitmap pixelsWide] pixelsHigh:[bitmap pixelsHigh] bitsPerSample:8 samplesPerPixel:3 hasAlpha:NO isPlanar:YES colorSpaceName:NSCalibratedRGBColorSpace bytesPerRow:4*[bitmap pixelsWide] bitsPerPixel:32];
// fix the image if it wasn't loaded as RGB
// greyscale
if ([bitmap samplesPerPixel] == 2 && [bitmap bitsPerSample] == 8 ) { for ( i = 0; i < [bitmap pixelsWide]*[bitmap pixelsHigh]; i++ ) { dstBuffer[i*3] = srcBuffer[i*2]; //put grayscale value into R dstBuffer[i*3+1] = srcBuffer[i*2]; //put grayscale value into G dstBuffer[i*3+2] = srcBuffer[i*2]; //put grayscale value into B } }
// b&w
else if( [bitmap samplesPerPixel] == 1 && [bitmap bitsPerSample] == 8 ) { for ( i = 0; i < [bitmap pixelsWide]*[bitmap pixelsHigh]; i++ ) { dstBuffer[i*3] = srcBuffer[i]; //put grayscale value into R dstBuffer[i*3+1] = srcBuffer[i]; //put grayscale value into G dstBuffer[i*3+2] = srcBuffer[i]; //put grayscale value into B } }
// what we want in this case
else if( [bitmap samplesPerPixel] == 3 && [bitmap bitsPerSample] == 8 ) { destinationBitmap = bitmap; }
// we are aligned by BYTES in an NSBitmapImageRep
glPixelStorei(GL_UNPACK_ALIGNMENT, 1 );
// put the image into texture memory // the image has Red-Green-Blue-Alpha chanels, is width*height in size // and is made up of unsigned bytes
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, [destinationBitmap size].width, [destinationBitmap size].height, 0,
// here's where we have the format of the item which is RGB
GL_RGB, GL_UNSIGNED_BYTE, [destinationBitmap bitmapData]);
// when we make the image smaller, use a linear filter on this texture
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// when we magnify the image, use a linear filter on this texture
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); }

We will need to load the textures into texture space. First, we generate texture identifiers with glGenTextures. texture is an array of GLint with size NUMTEXTURES defined in the kGLView class. In this case, we need space for 6 textures (for 6 sides of the die) so NUMTEXTURES is defined as 6.


// draw the first die in its normal colors
glTranslatef(-2.0,0.0,-10.0); glRotatef(dieangle,1,1.4,0.1); dieangle += 1; glColor3f(1.0,1.0,1.0); [self drawDie];

// load the identity so that we aren't adding the translations/rotations
glLoadIdentity();

// draw the second die, tinted with blue
glTranslatef(2.0,0.0,-15.0); glRotatef(dieangle,-1,1,-0.1); glColor3f(0.5,0.5,1.0); [self drawDie];

The drawDie method is the same as the drawCube method from the last lesson, except that we will now add some additional code for the textures. We first bind the texture, so that OpenGL knows what texture we are refering to in the subsequent calls. After binding the texture, we draw each face as we normally would. At each of the vertices, we add a texture coordinate. This is just like putting a different color on each vertex.


// glBindTexture is one of the commands that doesn't work within a glBegin - glEnd sequence
glBindTexture(GL_TEXTURE_2D, texture[0]); glBegin(drawing_type);
// glTexCoord2f is sized [0.0,1.0]
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, 1.0f,-1.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, 1.0f,-1.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glEnd();




     Download the project builder files

 

return to deep cocoa / cocoagl tutorials