DevC++ Image File Loading Problem

Started by
5 comments, last by Cubed3 18 years ago
I wrote an OpenGL Checkers game program for Mac OS 10.4 using XCode 2.x. The game runs quite well, so I decided to also make one for Windows using DevC++. Just like with XCode, getting images to load and display is turning out to be a monumental task. The error is my own messageBox error saying that there is no hBitmap (!hBitmap). What could be causing this? The code is included below. ------------------------------------------------------------------------------ To start, a new C plus plus Windows project was created and saved in its own folder which also contains a 512x512 24 bit bmp image of a checkerboard (checkerboard.bmp). ------------------------------------------------------------------------------ A new resource file, "Images.rc" was created with the following information: CHECKERBOARD BITMAP "checkerboard.bmp" ------------------------------------------------------------------------------ main.cpp looks like this: #include <windows.h> #include <windowsx.h> #include <iostream> #include <gl/gl.h> #include <GL/gl.h> using namespace std; GLuint texture; static HINSTANCE hinst; HBITMAP hBitmap; BITMAP bitmap; bool determinePixelFormat(HDC *hDC, HGLRC *hRC, HWND hwnd); LRESULT CALLBACK WinProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nFunsterStil) { glClearColor(0.0, 0.0, 0.0, 0.0); glClearDepth(1.0); glShadeModel(GL_SMOOTH); glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); hBitmap = (HBITMAP) LoadImage(hinst, "CHECKERBOARD", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION); if (!hBitmap) { MessageBox(NULL, "LoadImage failed", "ERROR", MB_OK); } int get_object; get_object = GetObject(hBitmap, sizeof(bitmap), &bitmap); if (!get_object) { MessageBox(NULL, "GetObject failed", "ERROR", MB_OK); } GLint bm_bits_pixel = (GLint) bitmap.bmBitsPixel; GLint internal_format; if (bm_bits_pixel < 32) { internal_format = GL_RGB; } else { internal_format = GL_RGBA; } GLuint width = (GLuint) bitmap.bmWidth; GLuint height = (GLuint) bitmap.bmHeight; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, internal_format, GL_UNSIGNED_BYTE, bitmap.bmBits); DeleteObject(hBitmap); bool quit_game = FALSE; WNDCLASSEX wincl; HWND hwnd; HDC hDC; HGLRC hRC; MSG messages; wincl.cbSize = sizeof(WNDCLASSEX); wincl.style = CS_OWNDC; wincl.lpfnWndProc = WinProc; wincl.cbClsExtra = 0; wincl.cbWndExtra = 0; wincl.hInstance = hThisInstance; wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION); wincl.hCursor = LoadCursor (NULL, IDC_CROSS); wincl.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wincl.lpszMenuName = NULL; wincl.lpszClassName = "Checkers"; wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION); if (!RegisterClassEx(&wincl)) { return 0; } hwnd = CreateWindowEx(NULL, "Checkers", "Checkers Beta 0.70", WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 100, 100, 768, 600, NULL, NULL, hThisInstance, 0); if (!determinePixelFormat(&hDC, &hRC, hwnd)) { PostQuitMessage (0); } ShowWindow(hwnd, SW_SHOWNORMAL); UpdateWindow(hwnd); while (!quit_game) { if (PeekMessage(&messages, NULL, 0, 0, PM_REMOVE)) { if (messages.message == WM_QUIT) { quit_game = TRUE; } else { TranslateMessage(&messages); DispatchMessage(&messages); } } else { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glDisable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texture); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, -1.0, 0.0); glTexCoord2f(0.0, 1.0); glVertex3f(-1.0, 1.0, 0.0); glTexCoord2f(1.0, 1.0); glVertex3f(0.5, 1.0, 0.0); glTexCoord2f(1.0, 0.0); glVertex3f(0.5, -1.0, 0.0); glEnd(); glDisable(GL_TEXTURE_2D); glEnable(GL_DEPTH_TEST); glFlush(); SwapBuffers(hDC); } } wglMakeCurrent(NULL, NULL); wglDeleteContext(hRC); ReleaseDC(hwnd, hDC); return (messages.wParam); } bool determinePixelFormat(HDC *hDC, HGLRC *hRC, HWND hwnd) { PIXELFORMATDESCRIPTOR pfd; pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pfd.dwLayerMask = PFD_MAIN_PLANE; pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 24; pfd.cDepthBits = 16; pfd.cAccumBits = 0; pfd.cStencilBits = 0; *hDC = GetDC(hwnd); int pixelformat; pixelformat = ChoosePixelFormat(*hDC, &pfd); if (!pixelformat) { MessageBox(NULL, "ChoosePixelFormat failed", "Error", MB_OK); return (FALSE); } bool set_pixel_format; set_pixel_format = SetPixelFormat(*hDC, pixelformat, &pfd); if (!set_pixel_format) { MessageBox(NULL, "SetPixelFormat failed", "Error", MB_OK); return (FALSE); } *hRC = wglCreateContext(*hDC); wglMakeCurrent(*hDC, *hRC); return (TRUE); } LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CREATE: break; case WM_CLOSE: DestroyWindow(hwnd); break; case WM_QUIT: DestroyWindow(hwnd); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd, message, wParam, lParam); } return 0; }
What-up, dawg?
Advertisement
You have to provide the full file name:

hBitmap = (HBITMAP) LoadImage(hinst,
"CHECKERBOARD.BMP",
IMAGE_BITMAP,
0, 0,
LR_LOADFROMFILE | LR_CREATEDIBSECTION);

Preferably you might add the full path to your game folder so you always load the correct file.

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

[edit]Ha, Endurion is correct on that, I guess I fixed that and didn't realize it -- the error goes away, but the image will not display, bugs in the code :/

For future references, you can wrap your code in [source] code goes here [/source] tags for a cleaner presentation [wink]

Now as for your project. It compiles and runs fine for me, but it does not work. I just placed a 512x512 bmp in the same folder and it ran without that error. I however did get that error when the file was not there. Check to make sure that your bitmap is in the same folder and your project so it is loaded from where the .exe is compiled at. It should fix that.

Now as for your program, I would suggest not trying to do all of this from scratch again. There is a function done that does all of this + other formats as well by NeHe. It's called IPicture (http://nehe.gamedev.net/counter.asp?file=files/misc/nehe_ipicture.zip) I pasted in the link because hotlinking to the file does not work on the first try, so copy and paste it into your URL bar.

Ok, so in relation to your project. Basically you can rip out all of the BMP loading stuff and replace it with the function and this function call:O
    if(!BuildTexture("checkerboard.bmp", texture))        return -1;

And that's it! The function takes care of everything else for you. Of course you have to add in a few more header files and link in additional files, but they are all native Win32.

Ok, so here is a copy and paste modification of your code to show you what I have been talking about:
/* Do not forget to link in:-lmingw32-lopengl32-lglu32-luser32-lgdi32-lole32-loleaut32-luuid*/#include <windows.h>#include <windowsx.h>#include <iostream>#include <olectl.h>														// Header File For The OLE Controls Library	(Used In BuildTexture)#include <math.h>														// Header File For The Math Library			(Used In BuildTexture)#include <gl/gl.h>#include <GL/gl.h>using namespace std;int BuildTexture(char *szPathName, GLuint &texid)						// Load Image And Convert To A Texture{	HDC			hdcTemp;												// The DC To Hold Our Bitmap	HBITMAP		hbmpTemp;												// Holds The Bitmap Temporarily	IPicture	*pPicture;												// IPicture Interface	OLECHAR		wszPath[MAX_PATH+1];									// Full Path To Picture (WCHAR)	char		szPath[MAX_PATH+1];										// Full Path To Picture	long		lWidth;													// Width In Logical Units	long		lHeight;												// Height In Logical Units	long		lWidthPixels;											// Width In Pixels	long		lHeightPixels;											// Height In Pixels	GLint		glMaxTexDim ;											// Holds Maximum Texture Size	if (strstr(szPathName, "http://"))									// If PathName Contains http:// Then...	{		strcpy(szPath, szPathName);										// Append The PathName To szPath	}	else																// Otherwise... We Are Loading From A File	{		GetCurrentDirectory(MAX_PATH, szPath);							// Get Our Working Directory		strcat(szPath, "\\");											// Append "\" After The Working Directory		strcat(szPath, szPathName);										// Append The PathName	}	MultiByteToWideChar(CP_ACP, 0, szPath, -1, wszPath, MAX_PATH);		// Convert From ASCII To Unicode	HRESULT hr = OleLoadPicturePath(wszPath, 0, 0, 0, IID_IPicture, (void**)&pPicture);	if(FAILED(hr))														// If Loading Failed		return FALSE;													// Return False	hdcTemp = CreateCompatibleDC(GetDC(0));								// Create The Windows Compatible Device Context	if(!hdcTemp)														// Did Creation Fail?	{		pPicture->Release();											// Decrements IPicture Reference Count		return FALSE;													// Return False (Failure)	}	glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glMaxTexDim);					// Get Maximum Texture Size Supported		pPicture->get_Width(&lWidth);										// Get IPicture Width (Convert To Pixels)	lWidthPixels	= MulDiv(lWidth, GetDeviceCaps(hdcTemp, LOGPIXELSX), 2540);	pPicture->get_Height(&lHeight);										// Get IPicture Height (Convert To Pixels)	lHeightPixels	= MulDiv(lHeight, GetDeviceCaps(hdcTemp, LOGPIXELSY), 2540);	// Resize Image To Closest Power Of Two	if (lWidthPixels <= glMaxTexDim) // Is Image Width Less Than Or Equal To Cards Limit		lWidthPixels = 1 << (int)floor((log((double)lWidthPixels)/log(2.0f)) + 0.5f); 	else  // Otherwise  Set Width To "Max Power Of Two" That The Card Can Handle		lWidthPixels = glMaxTexDim; 	if (lHeightPixels <= glMaxTexDim) // Is Image Height Greater Than Cards Limit		lHeightPixels = 1 << (int)floor((log((double)lHeightPixels)/log(2.0f)) + 0.5f);	else  // Otherwise  Set Height To "Max Power Of Two" That The Card Can Handle		lHeightPixels = glMaxTexDim;		//	Create A Temporary Bitmap	BITMAPINFO	bi = {0};												// The Type Of Bitmap We Request	DWORD		*pBits = 0;												// Pointer To The Bitmap Bits	bi.bmiHeader.biSize			= sizeof(BITMAPINFOHEADER);				// Set Structure Size	bi.bmiHeader.biBitCount		= 32;									// 32 Bit	bi.bmiHeader.biWidth		= lWidthPixels;							// Power Of Two Width	bi.bmiHeader.biHeight		= lHeightPixels;						// Make Image Top Up (Positive Y-Axis)	bi.bmiHeader.biCompression	= BI_RGB;								// RGB Encoding	bi.bmiHeader.biPlanes		= 1;									// 1 Bitplane	//	Creating A Bitmap This Way Allows Us To Specify Color Depth And Gives Us Imediate Access To The Bits	hbmpTemp = CreateDIBSection(hdcTemp, &bi, DIB_RGB_COLORS, (void**)&pBits, 0, 0);		if(!hbmpTemp)														// Did Creation Fail?	{		DeleteDC(hdcTemp);												// Delete The Device Context		pPicture->Release();											// Decrements IPicture Reference Count		return FALSE;													// Return False (Failure)	}	SelectObject(hdcTemp, hbmpTemp);									// Select Handle To Our Temp DC And Our Temp Bitmap Object	// Render The IPicture On To The Bitmap	pPicture->Render(hdcTemp, 0, 0, lWidthPixels, lHeightPixels, 0, lHeight, lWidth, -lHeight, 0);	// Convert From BGR To RGB Format And Add An Alpha Value Of 255	for(long i = 0; i < lWidthPixels * lHeightPixels; i++)				// Loop Through All Of The Pixels	{		BYTE* pPixel	= (BYTE*)(&pBits);							// Grab The Current Pixel		BYTE  temp		= pPixel[0];									// Store 1st Color In Temp Variable (Blue)		pPixel[0]		= pPixel[2];									// Move Red Value To Correct Position (1st)		pPixel[2]		= temp;											// Move Temp Value To Correct Blue Position (3rd)		// This Will Make Any Black Pixels, Completely Transparent		(You Can Hardcode The Value If You Wish)		if ((pPixel[0]==0) && (pPixel[1]==0) && (pPixel[2]==0))			// Is Pixel Completely Black			pPixel[3]	=   0;											// Set The Alpha Value To 0		else															// Otherwise			pPixel[3]	= 255;											// Set The Alpha Value To 255	}	glGenTextures(1, &texid);											// Create The Texture	// Typical Texture Generation Using Data From The Bitmap	glBindTexture(GL_TEXTURE_2D, texid);								// Bind To The Texture ID	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);		// (Modify This For The Type Of Filtering You Want)	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);     // (Modify This For The Type Of Filtering You Want)	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, lWidthPixels, lHeightPixels, 0, GL_RGBA, GL_UNSIGNED_BYTE, pBits);	// (Modify This If You Want Mipmaps)	DeleteObject(hbmpTemp);												// Delete The Object	DeleteDC(hdcTemp);													// Delete The Device Context	pPicture->Release();												// Decrements IPicture Reference Count	return TRUE;														// Return True (All Good)}GLuint texture;static HINSTANCE hinst;bool determinePixelFormat(HDC *hDC, HGLRC *hRC, HWND hwnd);LRESULT CALLBACK WinProc(HWND, UINT, WPARAM, LPARAM);int WINAPI WinMain (HINSTANCE hThisInstance,HINSTANCE hPrevInstance,LPSTR lpszArgument,int nFunsterStil){    int get_object;        bool quit_game = FALSE;    WNDCLASSEX wincl;    HWND hwnd;    HDC hDC;    HGLRC hRC;    MSG messages;        wincl.cbSize = sizeof(WNDCLASSEX);    wincl.style = CS_OWNDC;    wincl.lpfnWndProc = WinProc;    wincl.cbClsExtra = 0;    wincl.cbWndExtra = 0;    wincl.hInstance = hThisInstance;    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);    wincl.hCursor = LoadCursor (NULL, IDC_CROSS);    wincl.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);    wincl.lpszMenuName = NULL;    wincl.lpszClassName = "Checkers";    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);        if (!RegisterClassEx(&wincl))     {        return 0;    }    hwnd = CreateWindowEx(NULL,        "Checkers",        "Checkers Beta 0.70",        WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,        100,        100,        768,        600,        NULL,        NULL,        hThisInstance,        0);            if (!determinePixelFormat(&hDC, &hRC, hwnd))     {        PostQuitMessage (0);    }        ShowWindow(hwnd, SW_SHOWNORMAL);    UpdateWindow(hwnd);        /* OpenGl code goes here! After you have setup the Win32 window + context */    glClearColor(0.0, 0.0, 0.0, 0.0);    glClearDepth(1.0);    glShadeModel(GL_SMOOTH);    glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);    glEnable(GL_DEPTH_TEST);    glDepthFunc(GL_LEQUAL);        // here is where you load the bmp    if(!BuildTexture("checkerboard.bmp", texture))        return -1;                // The rest is all you!    while (!quit_game)     {        if (PeekMessage(&messages, NULL, 0, 0, PM_REMOVE)) {        if (messages.message == WM_QUIT) {            quit_game = TRUE;        } else {            TranslateMessage(&messages);            DispatchMessage(&messages);            }        } else {                    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);            glDisable(GL_DEPTH_TEST);            glEnable(GL_TEXTURE_2D);            glBindTexture(GL_TEXTURE_2D, texture);            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);            glBegin(GL_QUADS);            glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, -1.0, 0.0);            glTexCoord2f(0.0, 1.0); glVertex3f(-1.0, 1.0, 0.0);            glTexCoord2f(1.0, 1.0); glVertex3f(0.5, 1.0, 0.0);            glTexCoord2f(1.0, 0.0); glVertex3f(0.5, -1.0, 0.0);            glEnd();            glDisable(GL_TEXTURE_2D);            glEnable(GL_DEPTH_TEST);                        glFlush();            SwapBuffers(hDC);            }        }        wglMakeCurrent(NULL, NULL);        wglDeleteContext(hRC);        ReleaseDC(hwnd, hDC);        return (messages.wParam);    }        bool determinePixelFormat(HDC *hDC, HGLRC *hRC, HWND hwnd)     {    PIXELFORMATDESCRIPTOR pfd;    pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);    pfd.nVersion = 1;    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;    pfd.dwLayerMask = PFD_MAIN_PLANE;    pfd.iPixelType = PFD_TYPE_RGBA;    pfd.cColorBits = 24;    pfd.cDepthBits = 16;    pfd.cAccumBits = 0;    pfd.cStencilBits = 0;    *hDC = GetDC(hwnd);    int pixelformat;    pixelformat = ChoosePixelFormat(*hDC, &pfd);    if (!pixelformat) {    MessageBox(NULL, "ChoosePixelFormat failed", "Error", MB_OK);    return (FALSE);    }    bool set_pixel_format;    set_pixel_format = SetPixelFormat(*hDC, pixelformat, &pfd);    if (!set_pixel_format) {    MessageBox(NULL, "SetPixelFormat failed", "Error", MB_OK);    return (FALSE);    }    *hRC = wglCreateContext(*hDC);    wglMakeCurrent(*hDC, *hRC);    return (TRUE);    }        LRESULT CALLBACK    WinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {    switch (message) {    case WM_CREATE:        break;    case WM_CLOSE:    DestroyWindow(hwnd);    break;    case WM_QUIT:    DestroyWindow(hwnd);    break;    case WM_DESTROY:    PostQuitMessage(0);    break;    default:    return DefWindowProc(hwnd, message, wParam, lParam);    }    return 0;    }


Note that you will have to now link in the following libraries:
-lmingw32-lopengl32-lglu32-luser32-lgdi32-lole32-loleaut32-luuid


You should not need a resource file either now. See if this helps, if you have any questions on it feel free to ask! The NeHe function is at the top of your program, so you do not have to download the IPicture example if you do not want to.
hBitmap = (HBITMAP) LoadImage(hinst,
"CHECKERBOARD",
IMAGE_BITMAP,
0, 0,
LR_LOADFROMFILE | LR_CREATEDIBSECTION);
if (!hBitmap) {
MessageBox(NULL, "LoadImage failed", "ERROR", MB_OK);
}

I want to make the checkerboard .bmp file tied in with the .exe program as a resource. That is why I am trying to use the "CHECKERBOARD" handle in the .rc file. This worked for me in a different DevC++ project, but not this one.

DevC++ shows examples where this is being done.


-------------------------------------------------------------------------------
With the file loaded this way, I no longer get the error. I don't think
the image will be part of the .exe program, though:

hBitmap = (HBITMAP) LoadImage(hinst,
"checkerboard.bmp",
IMAGE_BITMAP,
0, 0,
LR_LOADFROMFILE | LR_CREATEDIBSECTION);
if (!hBitmap) {
MessageBox(NULL, "LoadImage failed", "ERROR", MB_OK);
}

And there are also OpenGL related problems. The image does not show up. Maybe version 4.9.9.2 has problems with .rc files.
What-up, dawg?
If you want to load the image from the resources you have to

A) include the bmp in the resources (i think you already did that)
B) remove the LR_LOADFROMFILE flag (otherwise LoadBitmap tries to load from a file)

If you included the bmp in your resources you ought to have an ID for it. Use that as the second parameter in one of the both ways:

LoadBitmap( hinst, "ID_DEFINE", ...

or

LoadBitmap( hinst, MAKEINTRESOURCE( ID_DEFINE ), ...

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

Thanks for the code, DREW_BENTON. The checkerboard image displays. No modifications needed.

It would be nice if there was some sort of handbook for DevC++.

It still bugs me that DevC++ 4.9.9.2 beta will not recognize .rc files.
What-up, dawg?
Quote:Original post by glMatt


It still bugs me that DevC++ 4.9.9.2 beta will not recognize .rc files.


Thats news to me...

This topic is closed to new replies.

Advertisement