Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

ncl

macrumors member
Aug 16, 2008
58
0
But it seems this method can load virtually any bitmap image data.

More exactly, any image format supported by Cocoa. DDS files, for example, won't work. Unless you include a NSImageRep for the DDS file format.

I find it hard to understand the role of NSBitmapRep and NSBitmapImageRep. I can't understand how does this code converts the image data from tga or jpg or anything else to plain unsigned bytes that OpenGL needs.

To be honest, I never took the time to try to understand: it worked :)
I just read the NSImage and NSBitmapImageRep documentation, here is what I understand:
when using -initWithContentsOfFile, NSImage will look for a NSImageRep capable of loading the image file, based on the file extension. So, NSImage is a class to handle any kind of images, and it is NSImageRep that actually deals with the various file format. And, unless you want to load an image in a format not supported by Cocoa, you don't have to deal with NSImageRep.
Next, the code gets a NSBitmapImageRep from the NSImage. As the name implies, NSBitmapImageRep is a bitmap, and will let you access the raw pixels. -TIFFRepresentation returns a TIFF bitmap using no compression. Which means that the NSBitmapImageRep contains "the plain unsigned bytes" that can be sent to GL.
 

Soulstorm

macrumors 68000
Original poster
Feb 1, 2005
1,887
1
In my code I am creating a memory leak, right? I am not calling glDeleteTextures() to free the allocated memory. But when I tried doing that, the program crashed when I was loading another model. I only changed the reset() function.

When the program runs, the new object is displayed without textures at all. The first model is displayed correctly. What can I do to completely deallocate the resources I use for each model?

Code:
void OBJModel::reset(){
	NSLog(@"resetting model...");
	for (int i=0; i<textures.size(); i++) {
		glDeleteTextures(1, &this->textures[i].texture.texID);
	}
	this->vertices.clear();
	this->vertexNormals.clear();
	this->textureVertices.clear();
	this->triangles.clear();
	this->mtlFileLocations.clear();
	this->materials.clear();
	this->groups.clear();
	this->textures.clear();
	
	hasTextures = false;
	hasNormals = false;
	
	xMaxSize = 0.0f;
	xMinSize = 0.0f;
	yMaxSize = 0.0f;
	yMinSize = 0.0f;
	zMaxSize = 0.0f;
	zMinSize = 0.0f;
	directoryPrefix = "";
}

EDIT: I also tried changing the destructor on the Texture class

Code:
~Texture(){
		glDeleteTextures(1, &texID);
}

which had the same effect.
 

ncl

macrumors member
Aug 16, 2008
58
0
That is weird. glDeleteTextures shouldn't cause a crash, even if the texture is invalid. If I remember your project correctly, the only texture operation that could crash the application is glTexImage. But I don't see how a glDeleteTextures could have any effect on a subsequent glTexImage.
The problem must be elsewhere. I don't have your project anymore, so I can't test it.

EDIT: just thought about this:
Are you doing a glGenTextures before glTexImage ? Otherwise, you may be doing a glTexImage with an invalid texture currently bound (the one previously deleted), and I don't know what kind of effect it could have.
 

Soulstorm

macrumors 68000
Original poster
Feb 1, 2005
1,887
1
That is weird. glDeleteTextures shouldn't cause a crash, even if the texture is invalid. If I remember your project correctly, the only texture operation that could crash the application is glTexImage. But I don't see how a glDeleteTextures could have any effect on a subsequent glTexImage.
The problem must be elsewhere. I don't have your project anymore, so I can't test it.

EDIT: just thought about this:
Are you doing a glGenTextures before glTexImage ? Otherwise, you may be doing a glTexImage with an invalid texture currently bound (the one previously deleted), and I don't know what kind of effect it could have.

Actually, it just produces a textureless object. It doesn't crash anymore. I used the code you gave me for loading textures, but the problem was still apparent with the old code. I will point you in the location of the problem:

TextureLoaders.mm:
Code:
void BitmapTexture::loadImage(NSString* imagePath){
	NSImage *image = [[NSImage alloc] initWithContentsOfFile:imagePath];
	NSBitmapImageRep *bitmap = [NSBitmapImageRep imageRepWithData:[image TIFFRepresentation]];
	if (bitmap == nil){
		NSLog([@"LoadGLTextures : could not load " stringByAppendingString:imagePath]);
		return;
	}
	glGenTextures(1, &texID);
	glBindTexture(GL_TEXTURE_2D, texID);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST);
	this->height = [bitmap size].height;
	this->width = [bitmap size].width;
	gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA8, [bitmap size].width, [bitmap size].height, [bitmap hasAlpha] ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, [bitmap bitmapData]);
	[image release];
}

BitmapTexture::~BitmapTexture(){
	//glDeleteTextures(1, &this->texID);
}

If you change the code at the destructor and remove the commends, the output will be a textureless object. Otherwise, everything is displayed correctly. I am attaching the entire project for your convenience.
 

Attachments

  • OBJ_MODEL_LOADER_TEST.zip
    970.9 KB · Views: 161

ncl

macrumors member
Aug 16, 2008
58
0
I changed 2 things. First, in your BitmapTexture class, I added a constructor:
Code:
BitmapTexture() : texID(0), data(0) {}
Otherwise, texID could be uninitialized when the destructor is called. The destructor could then try to delete an invalid texture or worse, a texture currently used by another model.
Also, the other attributes (the data pointer, width, height and type) don't seem to be used at all.

Next, this:
Code:
BitmapTexture alpha;
alpha.loadImage(entireTextureFileNameNsstring);
textures.push_back(alpha);
Here is what happens: alpha loads the texture and stores its id in texID. Then a copy of alpha is pushed in the vector. And, finally, alpha is destroyed, destroying the model's texture. A simple way to fix this:
Code:
BitmapTexture alpha;
textures.push_back(alpha);
textures[textures.size()-1].loadImage(entireTextureFileNameNsstring);
Here, a copy of alpha is pushed in the vector (with texID = 0). The copy in the vector loads the image. When alpha is destroyed, it tries to delete the texture 0, which isn't a valid texture id, and thus nothing happens (in the man page: "glDeleteTextures silently ignores 0's and names that do not correspond to existing textures.").

With these 2 changes, your program works fine (at least, on my machine).
 

Soulstorm

macrumors 68000
Original poster
Feb 1, 2005
1,887
1
I changed 2 things. First, in your BitmapTexture class, I added a constructor:
Code:
BitmapTexture() : texID(0), data(0) {}
Otherwise, texID could be uninitialized when the destructor is called. The destructor could then try to delete an invalid texture or worse, a texture currently used by another model.
Also, the other attributes (the data pointer, width, height and type) don't seem to be used at all.

Next, this:
Code:
BitmapTexture alpha;
alpha.loadImage(entireTextureFileNameNsstring);
textures.push_back(alpha);
Here is what happens: alpha loads the texture and stores its id in texID. Then a copy of alpha is pushed in the vector. And, finally, alpha is destroyed, destroying the model's texture. A simple way to fix this:
Code:
BitmapTexture alpha;
textures.push_back(alpha);
textures[textures.size()-1].loadImage(entireTextureFileNameNsstring);
Here, a copy of alpha is pushed in the vector (with texID = 0). The copy in the vector loads the image. When alpha is destroyed, it tries to delete the texture 0, which isn't a valid texture id, and thus nothing happens (in the man page: "glDeleteTextures silently ignores 0's and names that do not correspond to existing textures.").

With these 2 changes, your program works fine (at least, on my machine).

Thanks a lot. I am now beginning to understand the way OpenGL handles internally the textures... So the problem was that when the original 'alpha' was destroyed, the specified texture with that texture ID was destroyed, so the copy on the vector was pointing to nowhere... Thanks a lot for taking a look at my code... (again).

I would like to know where can I find books that will help me on projects like this. I have OpenGL red book, but it's more like a reference than anything else... Is there a good book with tutorials and examples that may help me?
 

ncl

macrumors member
Aug 16, 2008
58
0
So the problem was that when the original 'alpha' was destroyed, the specified texture with that texture ID was destroyed, so the copy on the vector was pointing to nowhere.

Only because glDeleteTextures was called in the destructor of alpha. Otherwise, the texture wouldn't be destroyed at all (which would cause a leak).
It is exactly the same thing as having 2 pointers to the same address in memory, and freeing the memory through one of them and then accessing that memory through the other. The main difference is that, with texture ids, it rarely causes a crash because GL can usually recognise an invalid texture id.

Thanks a lot for taking a look at my code... (again).
You're welcome :)

I would like to know where can I find books that will help me on projects like this. I have OpenGL red book, but it's more like a reference than anything else... Is there a good book with tutorials and examples that may help me?
Well I started with the NeHe site and the OpenGL Redbook. The Redbook actually explains a lot of things.
"The OpenGL SuperBible" is also a good book. It's a bunch of tutorials (going from the basics like drawing points to more advanced topics like shaders), followed by the OpenGL reference.
Currently, I mainly use the man pages and google if I need to look something up.
Also, I read some books like "Real-time rendering" and "Mathematics for 3D game programming and computer graphics". They are not about GL specifically but explain all the theory behind it, and more (in the case of "Real-time rendering", a lot more).
Some websites like Gamasutra, GameDev and DevMaster contains a lot of useful articles.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.