Sign in to follow this  
jonzy_x86

Release mode EXE wont render textures?

Recommended Posts

When I produce an EXE in Debug mode, the textures in my application render no problem, the FPS is about 128. When I produce the EXE as a release application, there are no textures. I can see 1 rendered pixel and the FPS is abot 2500. Does anybody know what is happening?

Share this post


Link to post
Share on other sites
Hello ... check for uninitialized variables in your project (maybe in one of your classes). I think this is the number one cause when dealing with release problems.
As far as I know , in debug mode variables are being initialized whereas in the release they aren't which leads to problems.
So ... check the relevant parts of your code for uninitialized variables.

I hope I've been of help to you...

-------------------------------------------------------------------------------------------
My Website - Portfolio, Tutorials
My blog

Share this post


Link to post
Share on other sites
Quote:
Original post by jonzy_x86
The paths are relative, and both work fine.


I thought they don't work fine?

What the first two posts were guessing is btw that yes, they are relative, but that your filestructure looks roughly like this:

Project/
+-Debug/
| +-Textures/
| | +-foo.bmp
| | +-bar.bmp
| |
| +-yourGame.exe
|
+-Release/
+-yourGame.exe "Textures/" not here


So that maybe you try to load "Textures/foo.bmp", but when in release-mode, it simply isn't there.


Quote:
I have a return value on the function that loads the textures and that returns true.

We are not clairvoyants and cannot guess what happens inside your function that returns true. Maybe post some code?

Btw, you can easily check if a file exists (yay, I made a cheat sheet!):

------------------------------------------------------
C++: if (std::ifstream (path)) { /*exists*/ }

-or maybe-

const bool exists = std::ifstream (path);
------------------------------------------------------
C#: if System.IO.File.Exists (path)) { /*exists*/ }
------------------------------------------------------
C: if (FILE *f = fopen (path, "r")) {
// exists
fclose (f); // don't forget!
}
------------------------------------------------------
PHP:if (file_exists ($path)) { /*exists*/ }
------------------------------------------------------

Share this post


Link to post
Share on other sites
Check your texture bindings, add some code in release version to dump texture IDs to a file and see if they remain consistent at various parts in your program. Also check how you load textures via glTexImage and friends as well. Struct alignment and padding in release code could also screw things up, particularly if you use hard coded offset pointers.

Share this post


Link to post
Share on other sites
Thanks all for your replies.

I'll have a look at the uninitialised variables today, perhaps that is the problem.

I will post some cut-down code here to demonstrate the problem.

The directory structure is like this...

Project
+-Debug
| +MyProject.exe (opens "Images\\Images.tga")
|
+- Release
| +MyProject.exe (opens "Images\\Images.tga")
|
+-Images
+Image.tga

*For some reason, the Image.tga part of the above will not format properly, this should be under the Images folder.*

I know that the Images folder is outside of the debug/release folders, but this work when running from the compiler because it uses the project path as the root.

And even without running in the compiler, I can copy the exes to the right directory and still the debug works but the release doesn't.

When I say that they both work fine, I mean that the function can open and read the file in both projects (I already have a file exists test there).

Thanks

Paul

Share this post


Link to post
Share on other sites
OK, So most of my GL functions are in a class wrapper.

I stripped the main parts of the class out, ie Initialise GL, Load the texture, display the texture etc and put them into plain C functions, and they worked!

So there must be an uninitialised variable in my class.

The code for the classes are too long to post, but I post the bug here when I find it so if anyone else has the same problem they can sort it out.

The simpler code is here...

[SOURCE]
// GNU GL Engine.cpp : Defines the entry point for the application.
//

// Include header files
#include "stdafx.h"
#include "resource.h"
#include <stdio.h>
#include <gl/gl.h> // Include opengl header
#include <gl/glu.h> // Include opengl utility header
#include <gl/glaux.h> // Include opengl aux header (discontinued). Cross compatible?

// Include library files
#pragma comment (lib, "glu32.lib") // Include opengl utility library
#pragma comment (lib, "glaux.lib") // Include opengl auxilary library
#pragma comment (lib, "opengl32.lib") // Include opengl for windows library

#define MAX_LOADSTRING 100

// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // The title bar text
HDC g_hDC;
HGLRC g_hGLRC;
RECT g_rctWindow;

unsigned int g_iWindowWidth = 320; // Window width
unsigned int g_iWindowHeight = 240; // Window height
unsigned int g_iColourDepth = 32;
unsigned int g_iImageWidth = 0;
unsigned int g_iImageHeight = 0;
unsigned int g_iTexture = 0;

// Forward declarations
void Mainloop(void);
bool Initialise(void);
bool OnCreate(HWND);
bool LoadTexture(char* szFilename);

// Foward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);

/*------------------------------------------------------------------------------------------------
Function: WinMain

Purpose: The main entry point of the application.
------------------------------------------------------------------------------------------------*/

int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;

// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_GNUGLENGINE, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);

// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}

hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_GNUGLENGINE);

while(true)
{
// Check to see if any messages are waiting in the queue
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
// Translate the message and dispatch it to WindowProc()
TranslateMessage(&msg);
DispatchMessage(&msg);
}

// If the message is WM_QUIT, exit the while loop
if(msg.message == WM_QUIT)
break;

// Run game code here...
Mainloop();
}

return msg.wParam;
}


/*------------------------------------------------------------------------------------------------
Function: MyRegisterClass

Purpose: Register the window class
------------------------------------------------------------------------------------------------*/

ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;

wcex.cbSize = sizeof(WNDCLASSEX);

wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_GNUGLENGINE);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = (LPCSTR)IDC_GNUGLENGINE;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);

return RegisterClassEx(&wcex);
}

/*------------------------------------------------------------------------------------------------
Function: InitInstance

Purpose: Initialise the window
------------------------------------------------------------------------------------------------*/

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;

hInst = hInstance; // Store instance handle in our global variable

// Set up the window rect...
g_rctWindow.top = 0; // Make zero at the top
g_rctWindow.left = 0; // and left
g_rctWindow.bottom = g_iWindowHeight; // Make the same size as the requested area
g_rctWindow.right = g_iWindowWidth; // and height

// Adjust the window to suit - This is important to get the correct position of the cursor over
// the window for WM_MOUSEMOVE events.
AdjustWindowRect(&g_rctWindow, WS_CAPTION | WS_SYSMENU, true);

// Fix window dimensions for later use
g_rctWindow.right = (g_rctWindow.right-g_rctWindow.left);
g_rctWindow.bottom = (g_rctWindow.bottom-g_rctWindow.top);
g_rctWindow.left = 0;
g_rctWindow.top = 0;

// Create the window
hWnd = CreateWindow(szWindowClass,
szTitle,
WS_CAPTION | WS_SYSMENU,
CW_USEDEFAULT,
0,
g_rctWindow.right,
g_rctWindow.bottom,
NULL,
NULL,
hInstance,
NULL);

// Is window handle valid?
if (!hWnd)
{
return FALSE;
}

// Show the window and update it
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);

return TRUE;
}

/*------------------------------------------------------------------------------------------------
Function: WndProc

Purpose: The main window message loop.
------------------------------------------------------------------------------------------------*/

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
// One window created
case WM_CREATE:
// Setup 3D parameters on window creation
if(OnCreate(hWnd)==false)
{
// Display error if there is a problem.
MessageBox(NULL,"Failed to create OpenGL Window!","Fatal Error",MB_ICONERROR);
PostQuitMessage(0);
break;
}

// Initialise game state
if(Initialise()==false)
{
// Display error if there is a problem.
MessageBox(NULL,"Failed to initialise variables!","Fatal Error",MB_ICONERROR);
PostQuitMessage(0);
break;
}

// Load the texture
if(!LoadTexture("images\\test1.tga"))
{
// Display error if there is a problem.
MessageBox(NULL,"Failed to load texture!","Fatal Error",MB_ICONERROR);
PostQuitMessage(0);
break;
}

break;

// On window closing...
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

/*------------------------------------------------------------------------------------------------
Function: OnCreate

Purpose: Sets up the window and rendering context in a WM_CREATE message.
------------------------------------------------------------------------------------------------*/

bool OnCreate(HWND _hWnd)
{
g_hDC = GetDC(_hWnd); // Get and store a device context

// Device context captured?
if(!g_hDC)
{
// Failed...
return false;
}

int nPixelFormat; // Pixel format index

PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR), // size of the structure
1, // version, always set to 1
PFD_DRAW_TO_WINDOW | // support window
PFD_SUPPORT_OPENGL | // support OpenGL
PFD_DOUBLEBUFFER, // support double buffering
PFD_TYPE_RGBA, // RGBA color mode
g_iColourDepth, // Color mode
0, 0, 0, 0, 0, 0, // ignore color bits, not used
0, // no alpha buffer
0, // ignore shift bit
0, // no accumulation buffer
0, 0, 0, 0, // ignore accumulation bits
16, // 16-bit z-buffer size
0, // no stencil buffer
0, // no auxiliary buffer
PFD_MAIN_PLANE, // main drawing plane
0, // reserved
0, 0, 0 // layer masks ignored
};

// Choose best matching pixel format...
nPixelFormat = ChoosePixelFormat(g_hDC, &pfd);

// Success?
if(!nPixelFormat)
{
//Failed...
return false;
}

// Set pixel format to device context
if(!SetPixelFormat(g_hDC, nPixelFormat, &pfd))
{
// Failed...
return false;
}

// Create rendering context and make it current
g_hGLRC = wglCreateContext(g_hDC);

// Success?
if(!g_hGLRC)
{
// Failed...
return false;
}

// Make rendering context current...
if(!wglMakeCurrent(g_hDC, g_hGLRC))
{
// Failed...
return false;
}

// Show the window
ShowWindow(_hWnd,SW_SHOW);

// Bring to front
SetForegroundWindow(_hWnd);
SetFocus(_hWnd);

// Success
return true;
}

/*------------------------------------------------------------------------------------------------
Function: Initialise

Purpose: Set up gl settings, load textures etc.
------------------------------------------------------------------------------------------------*/

bool Initialise(void)
{
// Set up the viewport
glViewport(0,0,g_iWindowWidth,g_iWindowHeight);

// Set up texturing
glEnable(GL_TEXTURE_2D);

// Set default clear colour to black
glClearColor(0.0f,0.0f,0.0f,1.0f);

// Enable depth testing
glEnable(GL_DEPTH_TEST);

return true;
}

/*------------------------------------------------------------------------------------------------
Function: LoadTexture

Purpose: Loads the texture into memory.
------------------------------------------------------------------------------------------------*/

bool LoadTexture(char* szFilename)
{
FILE* hFile; // File object to read data
unsigned char cByte; // To read garbage data
unsigned long iSize; // TGA image pixel count
int iColorMode; // 4 for RGBA or 3 for RGB
short int iWidth; // Image width
short int iHeight; // Image height
unsigned char iBitCount; // Colour depth
unsigned char* pPixelData;

// Open the file (binary)
hFile = fopen(szFilename, "rb");

// Make sure OK
if(!hFile){return false;}

// Read first two bytes of data that we don’t need
fread(&cByte, sizeof(unsigned char), 1, hFile);
fread(&cByte, sizeof(unsigned char), 1, hFile);

// Read in the image type
fread(&cByte, sizeof(unsigned char), 1, hFile);

// for our purposes, the image type should be either a 2 or a 3
if ((cByte != 2) && (cByte != 3))
{
// Failed...
fclose(hFile); // Close the file
return false; // Return false
}

// Read 9 bytes of data we don’t need
fread(&cByte, sizeof(unsigned char), 1, hFile);
fread(&cByte, sizeof(unsigned char), 1, hFile);
fread(&cByte, sizeof(unsigned char), 1, hFile);
fread(&cByte, sizeof(unsigned char), 1, hFile);
fread(&cByte, sizeof(unsigned char), 1, hFile);
fread(&cByte, sizeof(unsigned char), 1, hFile);
fread(&cByte, sizeof(unsigned char), 1, hFile);
fread(&cByte, sizeof(unsigned char), 1, hFile);
fread(&cByte, sizeof(unsigned char), 1, hFile);

// Read image dimensions
fread(&iWidth, sizeof(short int), 1, hFile); // Width
fread(&iHeight, sizeof(short int), 1, hFile); // Height

// Store global image variable
g_iImageWidth = iWidth;
g_iImageHeight = iHeight;

// Read image bit depth
fread(&iBitCount, sizeof(unsigned char), 1, hFile);

// Read 1 byte of data we don’t need
fread(&cByte, sizeof(unsigned char), 1, hFile);

// If the the bitmode / 8 = 3 then it is a 24 bit image
iColorMode = iBitCount / 8;

// 24 bit images only
if(iColorMode != 3)
{
return false;
}

// Make space for an alpha channel (RGBA = iColorMode = 4)
iColorMode++;

//Calculate the pixel data chunk size
iSize = (iWidth * iHeight * iColorMode);

// Allocate memory for the data chunk (image data)
pPixelData = new unsigned char[iSize];

// Read in image data
for(unsigned long i = 0;i < iSize;i += iColorMode)
{
// Read 3 bytes (RGB)
fread(&pPixelData[i], sizeof(unsigned char), 3, hFile);

// Is it a black pixel? (RGB = 000)
if(pPixelData[i] == 0)
if(pPixelData[i+1] == 0)
if(pPixelData[i+2] == 0)
{
// If it is then set the 4th pixel as transparent
pPixelData[i+3] = 0;
}
else
{
// Else just make it opaque
pPixelData[i+3] = 255;
}
}

// Change BGR to RGB so OpenGL can read the image data
for (unsigned long j = 0; j < iSize; j += iColorMode)
{
cByte = pPixelData[j]; // Store the R value
pPixelData[j] = pPixelData[j + 2]; // Swap the R with the B
pPixelData[j + 2] = cByte; // Swap the B with the R
}

// Close the file
fclose(hFile);

// Create 1 texture
glGenTextures(1, &g_iTexture);

// Bind the texture
glBindTexture(GL_TEXTURE_2D, g_iTexture);

// Set mip-map mode
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

// Generate a GL texture
glTexImage2D(GL_TEXTURE_2D, // This is a 2D texture
0, // ?
GL_RGBA, // Destination data uses RGBA colour space
g_iImageWidth, // The texture width
g_iImageHeight, // and height
0, // ?
GL_RGBA, // Source data uses RGBA colour space
GL_UNSIGNED_BYTE, // Data is stored in unsigned char array
pPixelData); // The source data

delete pPixelData;
pPixelData = NULL;

// Return success
return true;
}

/*------------------------------------------------------------------------------------------------
Function: Mainloop

Purpose: The main loop of the application
------------------------------------------------------------------------------------------------*/

void Mainloop(void)
{
// Clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Reset the projection matrix
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

// Set the parallel mode
glOrtho(0,g_iWindowWidth,0.0,g_iWindowHeight,-100.0,1.0);

// Set matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

// Use this texture
glBindTexture(GL_TEXTURE_2D, g_iTexture);

// Store the matrix
glPushMatrix();
// Set colour
glColor4f(1.0f,1.0f,1.0f,1.0f);
// Change to quad mode
glBegin(GL_QUADS);
// Render
glTexCoord2f(0.0f,0.0f);glVertex2f(0.0f,0.0f);
glTexCoord2f(1.0f,0.0f);glVertex2f(64.0f,0.0f);
glTexCoord2f(1.0f,1.0f);glVertex2f(64.0f,64.0f);
glTexCoord2f(0.0f,1.0f);glVertex2f(0.0f,64.0f);
// Done
glEnd();
// Restore Matrix
glPopMatrix();

// Swap the buffers
glFlush();
SwapBuffers(g_hDC);
}
[/SOURCE]

Share this post


Link to post
Share on other sites
Ah! I found it here...

// Don't render pixels lower than this (RGBA=0,0,0,0)
glAlphaFunc(GL_GREATER,0.001f);

// Enable the alpha test
glEnable(GL_ALPHA_TEST);

This part of my GL Class is stopping the image being rendered properly. In debug mode, the black pixels of the image are transparent, but in release mode, nothing is drawn (except for one pixel).

I added this line of code to the extract above, so that it is outside of the class and it still does the same thing.

Is there something I am missing?

Thanks!

Share this post


Link to post
Share on other sites
No no, it wasn't that it was this part of the loadtexture function...

[SOURCE]
if(m_pPixelData[i] == 0)
if(m_pPixelData[i+1] == 0)
if(m_pPixelData[i+2] == 0)
{
// Make alpha
}
[/SOURCE]


Should have been

[SOURCE]
if(m_pPixelData[i] == 0 && m_pPixelData[i+1] == 0 && m_pPixelData[i+2] == 0)
{
// Make Alpha
}
[/SOURCE]


I don't understand why this wouldn't work in release mode, the logic looks the same to me, but hey, it works now.

Share this post


Link to post
Share on other sites
I've been staring at your 2 code snippets for about an hour trying to figure out why they are different. The only thing I can think of is if you are doing something funky with operator overloading.

Otherwise, can someone please explain the difference between the snippets?

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