Hi, I'm trying to load a 24 bit image, and then render it on the primary surface via DirectX. The application compiles fine, but quits with an appcrash error. What is wrong?
Game.cpp
Code:
/*************************************************************************/
// Called in this order
// Code to initialize game - called once
#include "main.h" // your header file
// Global varables for this source file
LPDIRECTDRAW7 lpdd = NULL; // dd object
LPDIRECTDRAWSURFACE7 lpddsprimary = NULL; // dd primary surface
LPDIRECTDRAWSURFACE7 lpddssecondary = NULL; // dd back surface
LPDIRECTDRAWSURFACE7 lpoffscreen = NULL; // offscreen working surface
LPDIRECTDRAWPALETTE lpddpal = NULL; // a pointer to the created dd palette
DDSURFACEDESC2 ddsd; // a direct draw surface description struct
DDSCAPS2 ddscaps; // a direct draw surface capabilities struct
HRESULT ddrval; // result back from dd calls
UCHAR *primary_buffer = NULL; // primary video buffer
int Game_Init(void *parms)
{
// this function is where you do all the initialization
// for your game
log_file = fopen("log.txt","w");
debug("Initializing Game...\n\n\n");
// create object and test for error
if (DirectDrawCreateEx(NULL, (void **)&lpdd, IID_IDirectDraw7, NULL) == DD_OK)
debug("-> DirectDraw Object Created Successfully\n\n");
else
{
debug("***Error creating DDraw object***\n\n\n");
return(0);
}
// set cooperation level to windowed mode normal
if (lpdd->SetCooperativeLevel(g_hwnd,
DDSCL_ALLOWMODEX | DDSCL_FULLSCREEN |
DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT) == DD_OK)
debug("-> Cooperation Level Set\n\n");
else
{
debug("***Couldn't set cooperation level***\n\n\n");
return(0);
}
// set the display mode
if (lpdd->SetDisplayMode(WINDOW_WIDTH,WINDOW_HEIGHT,BITS,0,0) == DD_OK)
debug("-> Display Mode Set\n\n");
else
{
debug("***Failed to set display mode***\n\n\n");
return(0);
}
// Create the primary surface
memset(&ddsd,0,sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
// For secondary surface
ddsd.dwBackBufferCount = 1;
if (lpdd->CreateSurface(&ddsd,&lpddsprimary,NULL) == DD_OK)
debug("-> Primary Surface Created at lpddsprimary\n\n");
else
{
debug("***Error Creating Primary Surface***\n\n\n");
return(0);
}
ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
if (lpddsprimary->GetAttachedSurface(&ddscaps,&lpddssecondary) == DD_OK)
debug("-> Secondary Surface Created at lpddssecondary off of lpddsprimary\n\n");
else
{
debug("***Error Creating Secondary Surface***\n\n\n");
return(0);
}
// For Offscreen surface
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
// set dimensions
ddsd.dwWidth = 600;
ddsd.dwHeight = 400;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
// create offscreen surface
if (lpdd->CreateSurface(&ddsd,&lpoffscreen,NULL) == DD_OK)
debug("-> Offscreen Surface Created at lpoffscreen\n\n");
else
{
debug("***Error Creating Offscreen Surface***\n\n\n");
return(0);
}
if(!Load_Bitmap_File(&bitmap, "image.bmp"))
{
debug("***Couldn't Load Bitmap***");
return(0);
}
else debug("-> Loaded bitmap");
debug("Done\n\n\n");
// return success
return(1);
} // end Game_Init
/**************************************************************************/
// Main Game - loops
// this is the workhorse of your game it will be called
// continuously in real-time this is like main() in C
// all the calls for you game go here!
int Game_Main(void *parms)
{
// check of user is trying to exit
if (KEY_DOWN(VK_ESCAPE) || KEY_DOWN(VK_SPACE))
PostMessage(g_hwnd, WM_DESTROY,0,0);
// set up the surface description to lock the surface
memset(&ddsd,0,sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
// lock the primary surface, note in a real game you would
lpddsprimary->Lock(NULL,&ddsd,
DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,NULL);
// get video pointer
primary_buffer = (UCHAR *)ddsd.lpSurface;
// copy each bitmap line into primary buffer
// taking into consideration non-linear video
// cards and the memory pitch lPitch
for (int y = 0; y < WINDOW_HEIGHT; y++)
{
// copy the line
memcpy(&primary_buffer[y*ddsd.lPitch], // dest address
&bitmap.buffer[y*WINDOW_WIDTH*4], // src address
WINDOW_WIDTH*4); // bytes to copy
} // end for y
// unlock the surface
lpddsprimary->Unlock(NULL);
// return success
return(1);
} // end Game_Main
/*************************************************************************/
// Called before WM_DESTROY
int Game_Shutdown(void *parms)
{
// this function is where you shutdown your game and
// release all resources that you allocated
debug("Shutting Game down...\n\n\n");
// release attached surface first
if (lpddssecondary!=NULL)
lpddssecondary->Release();
debug("-> Released Secondary Surface\n\n");
// first release the primary surface
if (lpddsprimary!=NULL)
lpddsprimary->Release();
debug("-> Released Primary Surface\n\n");
// release offscreen surface
if (lpoffscreen!=NULL)
lpoffscreen->Release();
debug("-> Released Offscreen Surface\n\n");
// release the directdraw object
if (lpdd!=NULL)
lpdd->Release();
debug("-> Released DirectDraw Object\n\n");
if(!Unload_Bitmap_File(&bitmap))
debug("***Failed to unload bitmap***");
else debug("-> Unloaded bitmap\n\n");
debug("Done\n");
fclose(log_file);
// return success
return(1);
} // end Game_Shutdown
Dexterous.cpp
Code:
#include "main.h"
void debug(char *text)
{
fprintf(log_file,"%s",text);
}
/***************************************************************************/
int Load_Bitmap_File(BITMAP_FILE_PTR bitmap, char *filename)
{
// this function opens a bitmap file and loads the data into bitmap
int file_handle, // the file handle
index; // looping index
char *buffer;
UCHAR *temp_buffer = NULL; // used to convert 24 bit images to 16 bit
OFSTRUCT file_data; // the file data information
// open the file if it exists
if ((file_handle = OpenFile(filename,&file_data,OF_READ))==-1)
return(0);
// now load the bitmap file header
_lread(file_handle, &bitmap->bitmapfileheader,sizeof(BITMAPFILEHEADER));
// test if this is a bitmap file
if (bitmap->bitmapfileheader.bfType!=BITMAP_ID)
{
// close the file
_lclose(file_handle);
// return error
return(0);
} // end if
// now we know this is a bitmap, so read in all the sections
// first the bitmap infoheader
// now load the bitmap file header
_lread(file_handle, &bitmap->bitmapinfoheader,sizeof(BITMAPINFOHEADER));
// finally the image data itself
_lseek(file_handle,-(int)(bitmap->bitmapinfoheader.biSizeImage),SEEK_END);
// now read in the image, if the image is 16, 24, or 32 bit then simply read it
if (bitmap->bitmapinfoheader.biBitCount == 16 || bitmap->bitmapinfoheader.biBitCount == 24 || bitmap->bitmapinfoheader.biBitCount == 32)
{
// allocate the memory for the image
if (!(bitmap->buffer = (UCHAR *)malloc(bitmap->bitmapinfoheader.biSizeImage)))
{
// close the file
_lclose(file_handle);
// return error
return(0);
} // end if
// now read it in
_lread(file_handle,bitmap->buffer,bitmap->bitmapinfoheader.biSizeImage);
} // end if
else
{
debug("***8-bit image***");
return(0);
} // end if
// write the file info out
sprintf(buffer,"-> Bitmap Information\n\n\tfilename:%s \n\tsize=%d \n\twidth=%d \n\theight=%d \n\tbitsperpixel=%d \n\tcolors=%d \n\timpcolors=%d\n\n",
filename,
bitmap->bitmapinfoheader.biSizeImage,
bitmap->bitmapinfoheader.biWidth,
bitmap->bitmapinfoheader.biHeight,
bitmap->bitmapinfoheader.biBitCount,
bitmap->bitmapinfoheader.biClrUsed,
bitmap->bitmapinfoheader.biClrImportant);
debug(buffer);
// close the file
_lclose(file_handle);
// flip the bitmap
Flip_Bitmap(bitmap->buffer,
bitmap->bitmapinfoheader.biWidth*(bitmap->bitmapinfoheader.biBitCount/8),
bitmap->bitmapinfoheader.biHeight);
// return success
return(1);
} // end Load_Bitmap_File
///////////////////////////////////////////////////////////
int Unload_Bitmap_File(BITMAP_FILE_PTR bitmap)
{
// this function releases all memory associated with "bitmap"
if (bitmap->buffer)
{
// release memory
free(bitmap->buffer);
// reset pointer
bitmap->buffer = NULL;
} // end if
// return success
return(1);
} // end Unload_Bitmap_File
///////////////////////////////////////////////////////////
int Flip_Bitmap(UCHAR *image, int bytes_per_line, int height)
{
// this function is used to flip upside down .BMP images
UCHAR *buffer; // used to perform the image processing
int index; // looping index
// allocate the temporary buffer
if (!(buffer = (UCHAR *)malloc(bytes_per_line*height)))
return(0);
// copy image to work area
memcpy(buffer,image,bytes_per_line*height);
// flip vertically
for (index=0; index < height; index++)
memcpy(&image[((height-1) - index)*bytes_per_line], &buffer[index*bytes_per_line], bytes_per_line);
// release the memory
free(buffer);
// return success
return(1);
} // end Flip_Bitmap
main.h
Code:
// Compiler Includes
#include <windows.h> // include important windows stuff
#include <windowsx.h>
#include <mmsystem.h>
#include <iostream> // include important C/C++ stuff
#include <conio.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <math.h>
#include <io.h>
#include <fcntl.h>
#include <ddraw.h>
// Project Includes
// Defines
#define WINDOW_TITLE "Dexterous"
#define WINDOW_WIDTH 1280
#define WINDOW_HEIGHT 1024
#define BITS 24
#define _RGB24BIT(r,g,b) ((b) + ((g) << 8) + ((r) << 16))
#define _RGB32BIT(a,r,g,b) ((b) + ((g) << 8) + ((r) << 16) + ((a) << 24))
#define BITMAP_ID 0x4D42 // universal id for a bitmap
// Macros
// these read the keyboard asynchronously
#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEY_UP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)
// Typedefs
// container structure for bitmaps .BMP file
typedef struct BITMAP_FILE_TAG
{
BITMAPFILEHEADER bitmapfileheader; // this contains the bitmapfile header
BITMAPINFOHEADER bitmapinfoheader; // this is all the info including the palette
UCHAR *buffer; // this is a pointer to the data
} BITMAP_FILE, *BITMAP_FILE_PTR;
// Prototypes
int Game_Init(void *parms=NULL);
int Game_Shutdown(void *parms=NULL);
int Game_Main(void *parms=NULL);
void debug(char *text);
int Load_Bitmap_File(BITMAP_FILE_PTR bitmap, char *filename);
int Unload_Bitmap_File(BITMAP_FILE_PTR bitmap);
int Flip_Bitmap(UCHAR *image, int bytes_per_line, int height);
// Global Variables
extern HWND g_hwnd; // save the window handle
extern HINSTANCE g_hInstance; // save the instance
extern FILE *log_file;
extern BITMAP_FILE bitmap; // a bitmap file
There is also another file, title Windows.cpp. That file is definately not the problem, since it's only initializing the standard window and calling the game functions.
Help is very appreciated, thanks!
P.S. I have this feeling the error or bug is in Game_Main, specifically where it tries to copy memory onto the primary surface...