Sign in to follow this  
Shamino

Loading a bitmap texture (OpenGL)

Recommended Posts

Shamino    100
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
Bob Janova    769
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
Shamino    100
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
Rob Loach    1504
Quote:
Original post by Shamino
// Do loading stuff, return a true if success, false if fail..
I personally prefer thrown exceptions, but that's just me [wink].

Share this post


Link to post
Share on other sites
Shamino    100
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   
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
Shamino    100
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