Loading Textures Once ONLY...

OK, now that the 3D engine is running nicely, I am having a big problem figuring out how to load textures only once. Afterwards, how do I refer to a texture since it’s given a number, yet the polygons refer to the bitmap filename? Here is an example:

//Bitmap loading Routine

BOOL LoadBMP(char *texname)
{
char texbuf[256];
GLubyte fixer, image[32][32][3];
FILE *texfile;
BITMAPFILEHEADER bmfh;
BITMAPINFOHEADER bmih;

sprintf(texbuf, “…\Textures\%s”, texname);
if((texfile = fopen(texbuf, “rb”)) == NULL)
return FALSE;

fread(&bmfh, sizeof(BITMAPFILEHEADER), 1, texfile);
fread(&bmih, sizeof(BITMAPINFOHEADER), 1, texfile);
fread(&image, sizeof(image), 1, texfile);
fclose(texfile);

for(short int x_loop = 0; x_loop < 32; x_loop++)
{
for(short int y_loop = 0; y_loop < 32; y_loop++)
{
fixer = image[y_loop][x_loop][0];
image[y_loop][x_loop][0] = image[y_loop][x_loop][2];
image[y_loop][x_loop][2] = fixer;
}
}

glGenTextures(1, &texture[0]);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 32, 32, 0, GL_RGB, GL_UNSIGNED_BYTE, image);

texnum++;
return TRUE;
}

//Level Loading Routine

BOOL LoadWorld(char *map)
{
int numObjTri;
FILE *worldfile;

FreeWorld();
texnum = 0;

if((worldfile = fopen(map, “rb”)) == NULL)
return FALSE;

fread(&area.numObjects, sizeof(unsigned long), 1, worldfile);
fread(&area.numSprites, sizeof(unsigned long), 1, worldfile);
fread(&area.numLights, sizeof(unsigned long), 1, worldfile);

area.object = new OBJECT[area.numObjects];

for(unsigned long loop = 0; loop < area.numObjects; loop++)
{
fread(&area.object[loop].Type, sizeof(char), 1, worldfile);
fread(&area.object[loop].Texture, sizeof(char[16]), 1, worldfile);
fread(&numObjTri, sizeof(int), 1, worldfile);
area.object[loop].triangle = new TRIANGLE[numObjTri];
area.object[loop].numTriangles = numObjTri;
for(int t_loop = 0; t_loop < numObjTri; t_loop++)
{
fread(&area.object[loop].triangle[t_loop], sizeof(TRIANGLE), 1, worldfile);
}
}

fclose(worldfile);

for(unsigned long loop = 0; loop < area.numObjects; loop++)
if(!LoadBMP(area.object[loop].Texture))
return FALSE;

return TRUE;
}

As you can see, that is a horrible way to load textures, since the level may have “Tiles.bmp” on six objects. This means that each object would trigger a load! Now texnum is a globaly declared int, and texture is a global GLuint. Even after I get the repeat texture loading problem solved, how will I tell OpenGL what texture to bind to in the drawing routine, since it references the bitmap name? Thanks for the help, since i can see no way to do this that wouldn’t result in a MAJOR performance decrease.

Something I just noticed. When I typed in my routines, I accidentally made two errors. In the LoadBMP() function, wher eit binds and generates the texture, it isnt “texture[0]”, it is “texture[texnum]”. Sorry about that.

It doesn’t matter how you load it, OpenGL will never keep track of names for you, so you’re gonna have to do it yourself. What you do is, in your loader, create an indice in an array of structs for textures and set the name and OpenGL texture ID so that you don’t “lose” the texture. A little psuedo code might help:

typedef unsigned long ulong

struct __texture {
char name[16]; //15 character string
ulong texhandle; //OpenGL texture handle
};

#define MAX_TEXTURES 10
__textures GTextures[MAX_TEXTURES];

long LoadTexture(char *filename)
{
ulong GLTexHandle;
glGenTextures(1, &GLTexHandle);
load_your_texture;
GTextures[internal_handle].name = *filename; //I keep forgetting if this will work or not… some coder I am :stuck_out_tongue:
GTextures[internal_handle].texhandle = GLTexHandle;

return 0;
}

long findtexture(char *name)
{
for (ulong i=0; i<MAX_TEXTURES; i++) {
if (GTextures[i].name == *name) //this line may not work either, but it should )
return i;
}
}

void Draw()
{
glBindTexture(GL_TEXTURE_2D, findtexture(“texture00.bmp”));

drawpoly();
}

Anyway, you get the idea… right? :stuck_out_tongue: Anyway, have fun. And don’t try this code; it will not compile. The prefix ‘psuedo’ means ‘false’, right?

Perfect reason to use a STL map (or sometimes generically known as a dictionary).

GTextures[internal_handle].name = *filename; //I keep forgetting if this will work or not… some coder I am :stuck_out_tongue:

strcpy(A,B)
i suggest downloading the c spec it details all the c library commands

Yeah, I use sprintf(), in case I have to add something of my own to the buffer. Anyways, I can’t test my new code! When I read the level file (a plain text file right now, for debug purposes), it adds a carriage return or something at the end of the bitmap filename! This of course causes an error when trying to open the file. Here is an example:

//World File
NUMOBJECTS 1
//Object I
NUMTRI 1
Carved Stone.bmp
…Triangle Data…

//
//Reading Function
void readstr(FILE *f, char *string)
{
do
{
fgets(string, 255, f);
} while((string[0] == ’
') | | (string[0] == ‘/’));
return;
}
//
//How It Is Called
BOOL SetupWorld(char *map)
{
char oneline[128];
int numObjTri;
FILE *worldfile;

FreeWorld();
texnum = 0;

if((worldfile = fopen(map, “rt”)) == NULL)
return FALSE;

//Start Obsolete Code
area.object = new OBJECT[1];
area.numObjects = 1;

readstr(worldfile, oneline);
sscanf(oneline, "NUMOBJECTS %d
", &area.numObjects);
MessageBox(glwnd, oneline, “Debug”, MB_OK);
readstr(worldfile, oneline);
readstr(worldfile, oneline);

area.object = new OBJECT[area.numObjects];

for(short int loop = 0; loop < area.numObjects; loop++)
{
readstr(worldfile, oneline);
sscanf(oneline, “%i”, &area.object[loop].Type);
readstr(worldfile, oneline);
sprintf(area.object[loop].Texture, “%s”, oneline);
readstr(worldfile, oneline);
sscanf(oneline, “%i”, &numObjTri);
area.object[loop].numTriangles = numObjTri;
area.object[loop].triangle = new TRIANGLE[numObjTri];
for(char t_loop = 0; t_loop < numObjTri; t_loop++)
{
for(char v_loop = 0; v_loop < 3; v_loop++)
{
readstr(worldfile, oneline);
sscanf(oneline, “%f %f %f %f %f”, &area.object[loop].triangle[t_loop].vertex[v_loop].x, &area.object[loop].triangle[t_loop].vertex[v_loop].y, &area.object[loop].triangle[t_loop].vertex[v_loop].z, &area.object[loop].triangle[t_loop].vertex[v_loop].u, &area.object[loop].triangle[t_loop].vertex[v_loop].v);
}
}
}
fclose(worldfile);

for(unsigned long loop = 0; loop < area.numObjects; loop++)
{
MessageBox(glwnd, area.object[loop].Texture, “LoadWorld();”, MB_OK);
if(!LoadBMP(area.object[loop].Texture))
return FALSE;
}

return TRUE;
}

The file in the reading routine is an open one, which is why the function doesn’t open it itself. Saves time from opening, reading, closing, repeat 4000 times, haha! Anyways, how can I read in a string without getting the end carriage return? I’ve tried a ton of things and it won’t work. Thanks for the help.

It has been a while but you can try …

char s[8096];

while (fgets(in, s)){
// s should contain the the line, if it is less than the 8095 bytes that you specified above.

}

The other way you can do is since the carriage return (
) will have to read from the file anyway is to assign the byte that contains the carriage return to end of string (0).

s[strlen(s)] = 0;

Hope this helps.