Sign in to follow this  
Shamino

Loading a bitmap texture (OpenGL)

Recommended Posts

Okay, so I got this bit of code from NeHe, it works alright, havn't had any problems with it so far..
LRESULT	CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);				// Declaration For WndProc

AUX_RGBImageRec *LoadBMP(const char *Filename)						// Loads A Bitmap Image
{
	FILE *File=NULL;												// File Handle

	if (!Filename)													// Make Sure A Filename Was Given
	{
		return NULL;												// If Not Return NULL
	}

	File=fopen(Filename,"r");										// Check To See If The File Exists

	if (File)														// Does The File Exist?
	{
		fclose(File);												// Close The Handle
		return auxDIBImageLoad(Filename);							// Load The Bitmap And Return A Pointer
	}

	return NULL;													// If Load Failed Return NULL
}

GLuint LoadGLTexture( const char *filename )						// Load Bitmaps And Convert To Textures
{
	AUX_RGBImageRec *pImage;										// Create Storage Space For The Texture
	GLuint texture = 0;												// Texture ID

	pImage = LoadBMP( filename );									// Loads The Bitmap Specified By filename

	// Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit
	if ( pImage != NULL && pImage->data != NULL )					// If Texture Image Exists
	{
		glGenTextures(1, &texture);									// Create The Texture

		// Typical Texture Generation Using Data From The Bitmap
		glBindTexture(GL_TEXTURE_2D, texture);
		glTexImage2D(GL_TEXTURE_2D, 0, 3, pImage->sizeX, pImage->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, pImage->data);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

		free(pImage->data);											// Free The Texture Image Memory
		free(pImage);												// Free The Image Structure
	}

	return texture;													// Return The Status
}

I notice that it uses auxDIBImageLoad to actually load the bitmap... The way my program is set up, I want to create a texture object with its own loading function.. Something like
class BMPTexture
{
// storage structs
// Loading Code
};
I kinda want to mirror this setup (snipped from my MS3DModel definition)
class MS3DModel
{
public:

	MS3DModel();

	virtual ~MS3DModel();

	struct Vertex
	{
		char BoneID;
		float Location[3];
	};

	int NumVertices;
	Vertex *Vertices;

	struct Triangle
	{
		float VertexNormals[3][3];
		float Textures1[3], Textures2[3];
		int VertexIndices[3];
	};

	int NumTriangles;
	Triangle *Triangles;

	struct Mesh
	{
		int MaterialIndex;
		int NumTriangles;
		int *TriangleIndices;
	};

	int NumMeshes;
	Mesh *Meshes;

	struct Material
	{
		float Ambient[4], Diffuse[4], Specular[4], Emissive[4];
		float Shininess;
		GLuint Texture;
		char *TextureFilename;
	};

	int NumMaterials;
	Material *Materials;

	bool Load( const std::string & name );
	void ReloadTextures();
	void Draw();
};

Aside from the drawing function and reloadTextures function, and of course different storage structures, I want to mirror this setup, I find it works quite nicely with the resource manager I've created, shown here:
template< typename T_ >
class Resource_Manager
{  

public:

	typedef T_ value_type; // std library convention 

	typedef boost::shared_ptr<T_> Resource_Ptr;
	typedef boost::weak_ptr<T_> Resource_Observer;
	typedef std::map< std::string, Resource_Ptr > Resource_Map;

	Resource_Manager<T_>() {};
	~Resource_Manager<T_>() {};

	Resource_Observer Request_Resource(const std::string & name)
	{
		Resource_Map::iterator  it = mResources.find(name);

		if (it == mResources.end())
		{
			Resource_Ptr Raw_Resource(new T_);
			Raw_Resource->Load(name);
			mResources.insert(std::make_pair(name, Raw_Resource));
			Resource_Observer Resource(Raw_Resource);
			return Resource;
		}
		else
		{
			return Resource_Observer(it->second);
		}
	}

	void Request_Resource_Removal(const std::string & name)
	{
		Resource_Map::iterator it = mResources.find(name);

		if (it != mResources.end())
		{
			mResources.erase(it);
		}
	}

private:
	Resource_Map  mResources;
};

As you can see, it returns a resource observer weak pointer, but the actual loading of the bitmap returns a texture ID. While applying textures via ID is what I want to be able to do, you kinda have to in opengl. HMmmm... Looking at the loading code more closely, LoadBMP actually returns a pointer to the actual bitmap, while the GLLoadTexture func creates the texID.. The reason I want to use my manager to do all this stuff is, not to sound boastful, basically that my resource manager can do a cleaner job than the auxDIBImageLoad function. I don't really have to worry about deleting stuff with my resource manager, it is a nice way to do things IMO.. I guess my dilemma is this.. My resource manager handles pointers, it doesn't handle ID's, thus I can't mix ID creation in with my texture manager, unless maybe I'm returning an observer with a tex ID in it..... Ah yes, that's it. If I mirror the MS3D setup I can easily add an ID in the info structs and then access the ID of the texture object with methods in that class.. So I'm guessing when I get down to it, it looks like this: Resource_Manager<BMPTexture> Textures; Textures.Request_Resource("texture name here"); Then I can access the ID via the return value of the request resource method, which is a resource observer.. Okay, is this making sense to you guys? Am I in rightful reason to want to avoid the auxDIBImageLoad function? Is what I'm proposing making sense to you guys? Thanks.

Share this post


Link to post
Share on other sites
I can't comment on whether using your resource manager is better, but since you seem to think so I'll believe you =). The answer to your problem is to have GLLoadImage return a struct containing the texture ID and the data, and maybe some metadata as well if you need it later.

My TexInfo structure (Delphi) looked like this:
TTexInfo = record  // returned by GLLoadTexture
TexInx: Integer;
Data: Pointer;
DataSize: Integer;
end;

TTexture = record // created by the level loader
TexInfo: TTexInfo;
Height, Width: Integer;
end;

Share this post


Link to post
Share on other sites
I'm thinking something like this...



class BitmapTexture
{
public:
struct BMTexture
{
// low level information
};
struct TextureInfo
{
GLuint TexID;
GLuint TexWidth;
GLuint TexHeight;
// high level information
};

private:
bool Load(std::string & name)
{
// Do loading stuff, return a true if success, false if fail..
}
};


Thanks for the bit of insight :)

Share this post


Link to post
Share on other sites
So does anyone know where I can some generic code that loads a bitmap and fills out some structs of information? The idea here is to get away from auxDIBImageLoad...

Anyone? :)

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Header:


#ifndef CTEXTURE_H
#define CTEXTURE_H

#include <windows.h> // Windows header file.
#include <stdio.h> // Standard input/output.

#define BITMAP_ID 0x4D42 // The universal bitmap ID


class CBMPLoader
{
public:
CBMPLoader();
~CBMPLoader();

bool LoadBitmap(char *filename); // Load a .bmp image file.
void FreeImage(); // Delete a image.
void transparent(int* g_keyColor);

unsigned int ID; // Texture ID.
int imageWidth; // Width of a texture.
int imageHeight; // Height of a texture.
unsigned char *image; // Texture image.
unsigned char *TRANimage;
};

#endif




Footer Source:


#include "CBMPLoader.h"


CBMPLoader::CBMPLoader()
{
// Give everything default values.
image = 0;
TRANimage = 0;
imageWidth = 0;
imageHeight = 0;
}


CBMPLoader::~CBMPLoader()
{
FreeImage();
}


bool CBMPLoader::LoadBitmap(char *file)
{
FILE *pFile = 0;

// These will hold the bitmap header and file information.
BITMAPINFOHEADER bitmapInfoHeader;
BITMAPFILEHEADER header;

// This will be used to swap the image colors from BGR to RGB.
unsigned char textureColors = 0;

// Open the file and make sure no errors.
pFile = fopen(file, "rb");
if(pFile == 0) return false;

// Read in the bitmap header info into the BITMAPFILEHEADER variable.
fread(&header, sizeof(BITMAPFILEHEADER), 1, pFile);

// Make sure this is a real bitmap by checking the ID.
if(header.bfType != BITMAP_ID)
{
fclose(pFile);
return false;
}

// Read in the second header info into the BITMAPINFOHEADER variable.
fread(&bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, pFile);

// Save the width and height.
imageWidth = bitmapInfoHeader.biWidth;
imageHeight = bitmapInfoHeader.biHeight;

// Make sure we read a size out of it.
if(bitmapInfoHeader.biSizeImage == 0)
bitmapInfoHeader.biSizeImage = bitmapInfoHeader.biWidth *
bitmapInfoHeader.biHeight * 3;

// Place the pointer in front of where the image data starts.
fseek(pFile, header.bfOffBits, SEEK_SET);

// Dynamically create enough memory for the image.
image = new unsigned char[bitmapInfoHeader.biSizeImage];

// Error checking. Make sure the memory was allocated.
if(!image)
{
delete[] image;
fclose(pFile);
return false;
}

// Read in the image.
fread(image, 1, bitmapInfoHeader.biSizeImage, pFile);

// Bitmaps are saved in BGR format so we will make the image RGB by...
for(int index = 0; index < (int)bitmapInfoHeader.biSizeImage; index+=3)
{
textureColors = image[index];
image[index] = image[index + 2];
image[index + 2] = textureColors;
}

// Close the file and return the image.
fclose(pFile);
return true;
}


void CBMPLoader::transparent(int* g_keyColor)
{

int imageSize_RGB = imageWidth * imageHeight * 3;
int imageSize_RGBA = imageWidth * imageHeight * 4;

//allocate buffer for a RGBA image
TRANimage = new unsigned char[imageSize_RGBA];


// Loop through the original RGB image buffer and copy it over to the
// new RGBA image buffer setting each pixel that matches the key color
// transparent.


int i, j;
for(i = 0, j = 0; i < imageSize_RGB; i += 3, j += 4 )
{
// Does the current pixel match the selected color key?
if( image[i] == g_keyColor[0] &&
image[i+1] == g_keyColor[1] &&
image[i+2] == g_keyColor[2] )
{
TRANimage[j+3] = 0; // If so, set alpha to fully transparent.
}
else
{
TRANimage[j+3] = 255; // If not, set alpha to fully opaque.
}

TRANimage[j] = image[i];
TRANimage[j+1] = image[i+1];
TRANimage[j+2] = image[i+2];
}
}


void CBMPLoader::FreeImage()
{
// When the application is done delete all memory.
if(image)
{
delete[] image;
image = NULL;
}

if(TRANimage)
{
delete[] TRANimage;
TRANimage = NULL;
}
}

Share this post


Link to post
Share on other sites
Very cool response, was a shame you're anonymous, no rate++ :(...

Anyways, thanks for the code snippets, I should be able to add this to my manager quite easily.. All I gotta do is modify the load function to actually create an openGL texture ID :d..

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this