Skip to main content
gamedev.net
🔒 Locked

multiple textures = one texture

Started by yahn 13 replies 1.9k views
Original Post
yahn
yahn
I want to put a bunch of textures into one texture, for example, to render static strings. I've tried a couple ways to do this, but I can't get it done. How do I do this in OpenGL? [Edited by - yahn on February 23, 2008 11:32:45 AM]
snoutmate
snoutmate
Google for 'Texture atlas'. There is not much opengl specific for this one, you can use glTexSubImage2D to load images as part of larger texture.
yahn
yahn
I've tried glTexSubImage2D() several times and I cannot get it to do what I want. I've been told before that glTexSubImage2D() actually does not do this, but from the documentation it would appear as though it does. Maybe I was just using the function wrong. I googled texture atlas and found out what it is, but I didn't see anything on how to implement one.

Let me make sure that I'm using glTexSubImage2D() correctly before I rule it out.
I'd create the textures that I want to put into one texture, create a texture big enough to fit all of those textures, bind the big texture, then call glTexSubImage2D(GL_TEXTURE_2D, ___texture_I_want_to_put_into_big_texture____, xOffset, yOffset, width, height , GL_RGBA, GL_UNSIGNED_BYTE, ___pixels_of_texture_I_want_to_put_into_big_texture____);, right?
Brother Bob
Brother Bob
Quote:
Original post by yahn
Let me make sure that I'm using glTexSubImage2D() correctly before I rule it out.
I'd create the textures that I want to put into one texture, create a texture big enough to fit all of those textures, bind the big texture, then call glTexSubImage2D(GL_TEXTURE_2D, ___texture_I_want_to_put_into_big_texture____, xOffset, yOffset, width, height , GL_RGBA, GL_UNSIGNED_BYTE, ___pixels_of_texture_I_want_to_put_into_big_texture____);, right?

Second parameter is which mipmap level of the big texture you want to update. If your texture doesn't have mipmaps, this parameter must be zero (the base level texture, which is the only one present if you're not using mipmaps). I'm not sure what you mean you pass into it, but it does look suspicious.
yahn
yahn
I don't see what I am doing. I can render it fine when I render each glyph individually, but when I try:
glTexSubImage2D(GL_TEXTURE_2D, 0, ox, oy, f->glyph->bitmap.width, f->glyph->bitmap.rows, GL_RGBA, GL_UNSIGNED_BYTE, f->glyph->bitmap.buffer);


on each glyph it doesn't work. ox and oy are the x and y offsets. f->glyph->bitmap.width is the width, f->gly->bitmap.rows is the height, and f->glyph->bitmap.buffer is the pixel data. When I render the texture that is bound, nothing happens.

[Edited by - yahn on February 27, 2008 2:32:34 PM]
Brother Bob
Brother Bob
What do you mean by "nothing happens"? Does the textured primitive appear without texture, or does it not appear at all? If it doesn't appear at all, then there are other things that just the texturing that is wrong. Post some relevant code.
samoth
samoth
Unless your many small textures are generated programmatically, I'd recommend that you use an offline tool to put the many small textures into one, rather than copying them together by hand using glTexSubImage2D.
Not only does this save you an awful lot of startup time (and coding work), but it also allows you to properly generate mip levels (this is *not* as simple as scaling everything down).

nVidia offers a commandline tool for texture atlasses. If you mostly want to pack characters for displaying text, BMFont (from the Angelcode site) is quite nice.
yahn
yahn
By nothing happens, I mean when I render the texture nothing is showing up. I figure I probably have something wrong in there, but shouldn't SOMETHING show up?

int String::render_glyph(char c, Texture *tex, int ox, int oy){	if (face == NULL)	{		return -1;	}	FT_Face f = *face;	FT_UInt glyph_index = FT_Get_Char_Index(f, c);	FT_UInt error = FT_Load_Glyph(f, glyph_index, FT_LOAD_DEFAULT);	if (error)	{		return -1;	}	error = FT_Render_Glyph(f->glyph, FT_RENDER_MODE_NORMAL);	if (error)	{		return -1;	}	int width  = power2(f->glyph->bitmap.width);	int height = power2(f->glyph->bitmap.rows);	GLubyte *pad = new GLubyte[2*width*height];	int h = 0, w = 0;	while (h < height)	{		while (w < width)		{			pad[2*(w + h*width)] = pad[2*(w + h*width) + 1] = (w >= f->glyph->bitmap.width || h >= f->glyph->bitmap.rows) ? 0 : f->glyph->bitmap.buffer[w + f->glyph->bitmap.width*h];			w++;		}		w = 0;		h++;	}	tex->width  = width;	tex->height = height;	tex->load(pad, GL_RGBA, GL_LUMINANCE_ALPHA);	delete [] pad;	glTranslatef(f->glyph->bitmap_left, 0, 0);	glTranslatef(0, -f->glyph->bitmap_top, 0);	float x = (float)f->glyph->bitmap.width/(float)width;	float y = (float)f->glyph->bitmap.rows/(float)height;	//tex->render(ox + x + f->glyph->bitmap_left, oy + y + 16);	glTexSubImage2D(GL_TEXTURE_2D, 0, ox, oy, f->glyph->bitmap.width, f->glyph->bitmap.rows, GL_RGBA, GL_UNSIGNED_BYTE, f->glyph->bitmap.buffer);	return f->glyph->advance.x >> 6;}bool String::build(){	int i = 0;	int l = string.length();	int o = 0;	std::vector<Texture *> textures;	glBindTexture(GL_TEXTURE_2D, texture->texture);	for (i < 0; i < l; i++)	{		Texture *tex = new Texture;		textures.push_back(tex);		o += render_glyph(string, tex, o, 0);		if (o == -1)		{			int s = textures.size();			int j = 0;			while (j < s)			{				delete textures[j];				j++;			}			return false;		}	}	l = textures.size();	for (i < 0; i < l; i++)	{		delete textures;		i++;	}	built = true;	return true;}


Basically I set the string member of the String class equal to the static string I want to render. I go through the loop to create a glyph for each character, which works, because when I uncomment the tex->render() at the end, everything works fine. I just don't want to build the glyphs constantly when I don't need to. If anything else needs clarified, I will, but there isn't much code to clarify.

Can anyone help me? I've been stuck on this for a while. Thank you.

[Edited by - yahn on February 27, 2008 2:54:30 PM]
yahn
yahn
I'll simplify that code a lot in hopes that someone can tell me what I'm doing wrong. I know that the problem is with how I'm using glTexSubImage2D(), but I just cannot get it right.

I want to use freetype to render glyphs and then put them inside one texture to make a string. The pixel data from each of those images is stored in a variable called pad. So, in a pseudo code can someone tell me what I want to do?

I think it is:
String string = "Hello, World!";glBindTexture(GL_TEXTURE_2D, texture); // texture being the texture for the stringfor (i = 0; i < string.length(); i++){     char *pad = render_glyph(string);     glTexSubImage2D(GL_TEXTURE_2D, 0, xOffSet, yOffSet, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pad);}


I know that has a memory leak, but I'm trying to keep it as simple as possible.

That seems like it should be right, but it's just rendering a white rectangle as if nothing is in pad, but there is because when I render pad with glTexImage2D() it works.

nmi
nmi
Did you initially call glTexImage() once to create a texture, before you start calling glTexSubImage() to modify it ?
yahn
yahn
No, do I need to call that on each of the glyphs I want to add to the texture or the texture that I want to add the glyphs too or both?
nmi
nmi
The initial call to glTexImage() is similar to calling malloc in C or new in C++. It performs allocation of the memory for the texture, that was bound previously by calling glBindTexture().

Later on you can call glTexSubImage() to modify part or all of that texture. The size of the texture will not change by doing this, only its contents.

Consider for instance the case where your glyphs are of size 32x32 pixels each. If you allocated a texture with a size of 256x256 pixels by calling glTexImage(), then you can store 8x8=64 of those glyphs in that texture later on by calling glTexSubImage() for each glyph.
yahn
yahn
You mean glTexImage2D(), right? I don't see a function called glTexImage(). I changed the process to this:

String string = "Hello, World!";glBindTexture(GL_TEXTURE_2D, texture); // texture being the texture for the stringglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);for (i = 0; i < string.length(); i++){     char *pad = render_glyph(string);     glTexSubImage2D(GL_TEXTURE_2D, 0, xOffSet, yOffSet, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pad);}


It is still drawing a white rectangle to the screen.
nmi
nmi
When allocating textures never forget to call glTexParameter(), for instance like this:
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

Also look into this tutorial:
http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=06
yahn
yahn
That was what I was forgetting to do. Thank you so much. I had been stuck on this for weeks and I just did not see what I was doing wrong.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.