Thread: Loading a bitmap (Without using glaux)

  1. #1
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968

    Loading a bitmap (Without using glaux)

    Okay, so I got this bit of code from NeHe, it works alright, havn't had any problems with it so far..

    Code:
    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

    Code:
    class BMPTexture
    {
    // storage structs
    // Loading Code
    };
    I kinda want to mirror this setup (snipped from my MS3DModel definition)

    Code:
    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:

    Code:
    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&lt;BMPTexture&gt; 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.

    EDIT: Really I just need to know how to load a bitmap without using auxDIBImageLoad..
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  2. #2
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    So far this is what I've come up with..

    Header
    Code:
    #ifndef BITMAP_H
    #define BITMAP_H
    
    #include <windows.h>        // Windows header file.
    #include <stdio.h>          // Standard input/output.
    #include <gl\gl.h>
    #define BITMAP_ID 0x4D42	// The universal bitmap ID
    
    
    class Bitmap
    {
       public:
          Bitmap();
          ~Bitmap();
    
          bool Load(const 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
    Source
    Code:
    #include "Bitmap.h"
    
    
    Bitmap::Bitmap()
    {
       // Give everything default values.
      image = 0;
      TRANimage = 0;
      imageWidth = 0;
      imageHeight = 0;
    }
    
    
    Bitmap::~Bitmap()
    {
       FreeImage();
    }
    
    
    bool Bitmap::Load(const 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 Bitmap::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 Bitmap::FreeImage()
    {
       // When the application is done delete all memory.
       if(image)
          {
             delete[] image;
             image = NULL;
          }
    
        if(TRANimage)
          {
             delete[] TRANimage;
             TRANimage = NULL;
          }
    }
    Now, I need to make it so ID is equal to whatever glGenTexture spits out, and then provide an access function to get the ID of the texture...

    So, with my resource manager, I'll be able to pass a texture filename, and it will return a pointer, which I can use to get the ID..

    No repeating textures, no dangling memory anywhere..

    Hurrah for my resource manager!
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  3. #3
    Crazy Fool Perspective's Avatar
    Join Date
    Jan 2003
    Location
    Canada
    Posts
    2,640
    >>EDIT: Really I just need to know how to load a bitmap without using auxDIBImageLoad..

    http://gpwiki.org/index.php/LoadBMPCpp

  4. #4
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    Hmm, that might work...

    I'd need to modify the main object to store a GL tex id though, shouldn't be difficult..
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  5. #5
    Registered User
    Join Date
    Mar 2006
    Posts
    3
    Sometimes BMPs will have spacefillers of a couple of byte at the ends of each row of pixel data. I don't see any compensation for that in the wiki code, it may not be required though since it's reading the BMP data differently than I did. When I wrote my BMP loader I read it in by bytes (it was a while ago...) and I had to calculate how much blank space was at the end of each line to skip over it.

    If the images are messing up (diagonally skewed) you'll need to skip over these non-data bytes. In one of the header variables it says how long the image data is. You also have height and width in pixels. If image data length != height * width, you read each rox of pixels to the width of the image, then skip a number of bytes equal to [(data length) - (height * width)]/width

    I wish I had my code here, unfortunately it's on a different computer. The wiki code looks much nicer though anyways

    ~Mith

  6. #6
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    Thanks for the heads up Mith
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  7. #7
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Each row in a BMP is zero-padded to the nearest 4 byte boundary.
    BMPs are stored in exact reverse color order as the hardware expects.
    BMPs are stored using bottom right corner as starting place or 0.

  8. #8
    The Right Honourable psychopath's Avatar
    Join Date
    Mar 2004
    Location
    Where circles begin.
    Posts
    1,071
    "BMPs are stored in exact reverse color order as the hardware expects."

    Naturally.
    M.Eng Computer Engineering Candidate
    B.Sc Computer Science

    Robotics and graphics enthusiast.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Loading bitmap file into a HBITMAP
    By wind_addict in forum Windows Programming
    Replies: 9
    Last Post: 11-17-2007, 10:42 AM
  2. OpenGL -- Bitmaps
    By HQSneaker in forum Game Programming
    Replies: 14
    Last Post: 09-06-2004, 04:04 PM
  3. Loading a Bitmap resource for OpenGL Texture[x]
    By the dead tree in forum Game Programming
    Replies: 4
    Last Post: 08-26-2004, 01:12 PM
  4. Loading bitmap in dll
    By Mithoric in forum Windows Programming
    Replies: 2
    Last Post: 12-22-2003, 01:53 PM
  5. No one can seem to help me, loading bitmap
    By Shadow12345 in forum C++ Programming
    Replies: 7
    Last Post: 12-28-2002, 01:22 PM