Results 1 to 3 of 3

Thread: Loading a image

  1. #1
    Junior Member Newbie
    Join Date
    Dec 2010
    Posts
    2

    Loading a image

    I've manages to create a image loading function that works. As references here it is with comments.
    Code :
     
    ImageBMP::ImageBMP(){
    	/*
    		Zero everything out
    	*/
    	mBitmap	= NULL;
    	mWidth	= 0;
    	mHeight	= 0;
    	mStride	= 0;
    	mType	= 0;
     
    	GdiFlush();
    }
    ImageBMP::~ImageBMP(){
    	FreeBMP();
    }
    void ImageBMP::FreeBMP(){
    	if(mBitmap)
    		DeleteObject(mBitmap);
     
    	mBitmap	= NULL;
    	mWidth	= 0;
    	mHeight	= 0;
    	mStride = 0;
    	mType	= 0;
    	imgData	= NULL;
    }
    unsigned char* ImageBMP::GetImageData(int which_line){
    	return (imgData + mStride * which_line);
    }
    bool ImageBMP::SizeImg(int w, int h, int channels){
    	/*
    		To begin with, we clear the memory of the image incase anything
    			was already loaded in. We then create a temporary device
    			context and initialize our width, height, and type variables.
    			We also initialize our stride variable, but read further down for
    			more information on that.
    	*/
    	FreeBMP();
    	HDC tmpDC = CreateCompatibleDC(NULL);
    	if(!tmpDC){
    		MessageBox(NULL, "CreateCompatibleDC() failed!", "Error SizeImg()", MB_OK);
    		return false;
    	}
     
    	mWidth	= w;
    	mHeight	= h;
    	mType	= channels;
     
    	/*
    		In windows and most other OS's. Some things are far easier
    			to accomplish when the data is dword aligned. dword = 2 words
    			or 2 words = 4 bytes (Some asm knowledge there). Anyhow, this
    			helps speed up drawing to the screen, we we get the true stride, 
    			then modify it until it is evenly divided by 4. IF you ever 
    			wondered when the hell you would use the modulus symbol, here it
    			is!
    	*/
    	mStride = mWidth * mType;
    	while((mStride % 4) != 0)
    		mStride++;
     
    	BITMAPINFO bInfo = {0};
     
    	/*
    		We set up the bitmap data here for when we create the image itself 
    			from the file data. biSize is the size of the header. WE just pass
    			in the BitmapInfoHeader struct for this. biWidth and biHeight should
    			not need explanation. biPlanes will always be 1 regardless of what type
    			of image you load. Even MSDN says it MUST be 1. Next we have biBitCount 
    			which is just the number of channels we have multiplied by 8 (8 bits per byte).
    			If you wanted to be an [censored] to someone, you could always ask "Hey, can you
    				save that in 3 byte format?" (24bit)
    			Anyways, moving along... We come across biCompression. Since no compression
    			should have happened to the image we are loading, we just tell it no compression
    			occured to the image data. Finally, biClrUsed is just a indicies tracker for images
    			in the 8 bit range for color platelets. We don't need it though so set it to 0.
    	*/
    	bInfo.bmiHeader.biSize			= sizeof BITMAPINFOHEADER;
    	bInfo.bmiHeader.biWidth			= mWidth;
    	bInfo.bmiHeader.biHeight		= mHeight;
    	bInfo.bmiHeader.biPlanes		= 1;			// This will always be 1
    	bInfo.bmiHeader.biBitCount		= mType * 8;	// 3 channels = 24, 4 = 32
    	bInfo.bmiHeader.biCompression	= BI_RGB;		// No compression
    	bInfo.bmiHeader.biClrUsed		= 0;			// Always 0 when working with 24/32 bit bmps
     
     
    	/*
    		Finally, we actually create the image to store our data into. After creating it, we
    			check to see if it finished properly, then we delete the temporary device
    			context created earlier. Do a final check to make sure all is okay, then return true!
    	*/
    	mBitmap = CreateDIBSection(tmpDC, &bInfo, DIB_RGB_COLORS, (void**)&imgData, 0, 0);
     
    	DeleteDC(tmpDC);
    	if(!mBitmap){
    		MessageBox(NULL, "CreateDIBSection() failed!", "Error SizeImg()", MB_OK);
    		return false;
    	}
    	return true;
    }
    bool ImageBMP::LoadBMP(const char *filename){
    	/*
    		To start off, we erase any memory or garbage memory that might be in the
    			bitmap class already. After that we proceed to check and ensure a filename was
    			ACTUALLY passed into the function, if it was, we open the file and proceed to 
    			read the data into our holder and then into OpenGL.
    	*/
    	FreeBMP();
    	if(!filename){
    		MessageBox(NULL, "Bad file name!", "Error LoadBMP()", MB_OK);
    		return false;
    	}
     
    	FILE * img = NULL;
    	fopen_s(&img, filename, "rb");	// Notice we read the file in  byte by byte. 'rb' means Read Byte mode.	
     
    	if(!img){
    		MessageBox(NULL, "fopen() failed!", "Error LoadBMP()", MB_OK);
    		return false;
    	}
     
    	// Stores information on the bitmap header when we load it in.
    	BITMAPFILEHEADER bHeader;
     
    	if(!fread(&bHeader, sizeof bHeader, 1, img)){
    		MessageBox(NULL, "fread() [BITMAPFILEHEADER] failed!", "Error LoadBMP()", MB_OK);
    		return false;
    	}
     
    	/*
    		Here, we check to make sure this is ACTUALLY a bmp file. You can rename a .jpg
    			to .bmp, but the compression still exists inside it. If we tried to load it 
    			while it was still compressed, bad things will happen. We check to avoid that
    			bad situation. Note that memcmp returns true if the memory does NOT match. Don't 
    			ask me why.
    	*/
    	if(memcmp(&bHeader.bfType, "BM", 2)){
    		MessageBox(NULL, "memcmp() detected false file type!", "Error LoadBMP()", MB_OK);
    		fclose(img); // Close the file since it is the wrong filetype.
    		return false;
    	}
     
    	// This contains information on the bitmap itself
    	BITMAPINFOHEADER bInfo; 
     
    	// Read in the info for the bitmap.
    	if(!fread(&bInfo, sizeof(BITMAPINFOHEADER), 1, img))
    	{
    		MessageBox(NULL, "fread() [BITMAPINFOHEADER] failed!", "Error LoadBMP()", MB_OK);
    		fclose(img);
    		return false;
    	}
     
    	if((bInfo.biBitCount != 24) && (bInfo.biBitCount != 32)){
    		/*
    			Here, we checked if the image was 24 or 32 bits. If it is neither, then we just return false after
    				closing the file. This loader is currently unable to load monochrome, or 8 bit bmp images. We
    				will simply stick to 24 or 32.
    		*/
    		MessageBox(NULL, "Not a valid 24 | 32 bit image type!", "Error LoadBMP()", MB_OK);
    		fclose(img);
    		return false;
    	}
     
    	/*
    		After getting all the information from the header, we then set the image data up 
    			and prepare it for loading in the actual image data itself. That is done
    			with the function call we created earlier in the class. We pass in the height
    			and the width. To send in the number of channels, it is the bit count / 8 (8 bits per byte),
    			and 3 bytes is the number of channels. Or 4...
    	*/
    	if(!SizeImg(bInfo.biWidth, bInfo.biHeight, bInfo.biBitCount/8)){
    		MessageBox(NULL, "Size() failed!", "Error LoadBMP()", MB_OK);
    		fclose(img);
    		return false;
    	}
     
    	/*
    		What is about to happen might look confusing but it is very straight forward! 
    			First, we need to find out how many bits are on each line in the image.
    			Second, we need to find out how many of those bytes are padded since we want to avoid reading those in.
    			Finally, we read the data into the image handler.
    	*/
    	unsigned int bytesPerLine	= mWidth * mType;			// Get the number of bytes per line
    	unsigned int padCount		= mStride - bytesPerLine;	// Get the amount of padding involved.
     
    	// Loop through and read the data in
    	for(int i=0; i<mHeight; i++){
    		/*
    			i is the line number in the image we are on. In this case, i 
    				will start at 0 being the top of the file. From each line, we need 
    				to relocate our position
    		*/
    		unsigned char* pos = GetImageData(i);			// Relocate our position
     
    		/*
    			Read in the image data
    		*/
    		if(!fread(pos, bytesPerLine, 1, img)){
    			MessageBox(NULL, "fread() at ImageData failed!", "Error LoadBMP()", MB_OK);
    			fclose(img);
    			return false;
    		}
     
    		/*
    			Skip over padding, remember that fseek returns 0 on succes, and negative values
    				for errors.
    		*/
    		if(fseek(img, 0, SEEK_CUR)){
    			MessageBox(NULL, "fread() at padding failed!", "Error LoadBMP()", MB_OK);
    			fclose(img);
    			return false;
    		}
    	}
     
    	// Loaded the image successfully, we now just do what we want with the image data
    	fclose(img);
    	return true;
    }

    That loads the image and this actually makes the texture.
    Code :
    bool LoadImage(char* file, GLuint tex[], GLuint id){
    	ImageBMP img;
    	if(!img.LoadBMP(file))
    		return false;
     
    	glGenTextures(1, &amp;tex[id]);
    	glBindTexture(GL_TEXTURE_2D, tex[id]);
     
    	glTexImage2D(	GL_TEXTURE_2D,		
    					0,				
    					img.GetType(),		
    					img.GetWidth(),			
    					img.GetHeight(),		
    					0,						
    					GL_BGR_EXT,				
    					GL_UNSIGNED_BYTE,		
    					img.GetImageData(0));
     
    	gluBuild2DMipmaps(	GL_TEXTURE_2D,
    						img.GetType(),
    						img.GetWidth(),
    						img.GetHeight(),
    						GL_BGR_EXT,			
    						GL_UNSIGNED_BYTE,
    						img.GetImageData(0));
     
    	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
    	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
     
    	/*
    		The functions below cause the image to be stretched properly to cover the border lines preventing
    			black lines from showing. Try commenting these out to see the effect.
    	*/
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     
     
    	return true;
    }

    For some reason though, I get a strange error. I am unable to draw any image that is loaded before the last image loaded in. So I can load in 3 images, but no matter which one I bind, only the last one will be drawn. Here is my draw function.
    Code :
    glEnable(GL_TEXTURE_2D);
    	glPushMatrix();
    		glTranslatef(m_position.x(), m_position.y(), m_position.z());
    		glRotatef(90, 1, 0, 0);
    		glRotatef(m_facingAngle, 0, 0, 1);
    		glColor3f(1, 1, 1);
    		glBegin(GL_QUADS);
    			glBindTexture(GL_TEXTURE_2D, textures[0]);
    			glTexCoord2i(0, 1); glVertex3f(-.8, -.5, 0);
    			glTexCoord2i(1, 1); glVertex3f(.8, -.5, 0);
    			glTexCoord2i(1, 0); glVertex3f(.8, .5, 0);
    			glTexCoord2i(0, 0); glVertex3f(-.8, .5, 0);
    		glEnd();
    	glPopMatrix();
    glDisable(GL_TEXTURE_2D);

    Does anyone have any idea on why this happens? Do you need more info?

  2. #2
    Senior Member Regular Contributor
    Join Date
    Mar 2009
    Posts
    153

    Re: Loading a image

    You are always binding same texture:
    glBindTexture(GL_TEXTURE_2D, textures[0]);

    Do not call glBindTexture in glBegin/glEnd block.

    GL_INVALID_OPERATION is generated if glBindTexture is executed between the execution of glBegin and the corresponding execution of glEnd.

  3. #3
    Junior Member Newbie
    Join Date
    Dec 2010
    Posts
    2

    Re: Loading a image

    Thanks, the error was I was calling it after glBegin. Thanks for the follow up.

Similar Threads

  1. Image Loading Library for loading image textures
    By jitendra2896 in forum OpenGL: Basic Coding
    Replies: 1
    Last Post: 08-03-2017, 12:13 AM
  2. Loading an image??
    By Creative Mind in forum OpenGL: Basic Coding
    Replies: 1
    Last Post: 08-20-2009, 11:13 AM
  3. Loading an image
    By Erin C. in forum OpenGL: Basic Coding
    Replies: 3
    Last Post: 11-02-2008, 04:28 AM
  4. Replies: 2
    Last Post: 07-28-2003, 07:30 PM
  5. RGB Image Loading
    By in forum OpenGL: Basic Coding
    Replies: 0
    Last Post: 07-08-2002, 12:38 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Proudly hosted by Digital Ocean