-
Cannot find error
I am just begining to learn programming with DirectX. I am currently on the section on Page Flipping in the book I am reading. Anyway, I am getting an access violation fault with the program I am doing from the book. The source for it that come on the CD with the book runs fine but for the life of me I cannot find where I messed up the code. It gets as far as creating a blank screen then crashes. Here is the code that I have
Code:
#define WIN32_LEAN_AND_MEAN
#define INITGUID // make sure directX guids are included
#include <windows.h>
#include <windowsx.h>
#include <ddraw.h>
// DEFINES /////////////////////////////////////////////////////////////////////
// defines for windows
#define WINDOW_CLASS_NAME "WINCLASS1"
// default screen size
#define SCREEN_WIDTH 640 // size of screen
#define SCREEN_HEIGHT 480 // max size 1280, 1024 w/ 32 bbp
#define SCREEN_BPP 8 // bits per pixel
#define MAX_COLORS 256 // maximum colors
// TYPES ///////////////////////////////////////////////////////////////////////
// basic unsigned types
typedef unsigned short USHORT;
typedef unsigned short WORD;
typedef unsigned char UCHAR;
typedef unsigned char BYTE;
// MACROS //////////////////////////////////////////////////////////////////////
#define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEYUP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)
// initializes a direct draw struct
#define DDRAW_INIT_STRUCT(ddstruct) { memset(&ddstruct,0,sizeof(ddstruct)); ddstruct.dwSize=sizeof(ddstruct); }
// GLOBALS /////////////////////////////////////////////////////////////////////
HWND main_window_handle = NULL; // globally track main window
HINSTANCE hinstance_app = NULL; // globally track hinstance
int window_closed = 0;
// directdraw stuff
LPDIRECTDRAW7 lpDD = NULL; // dd object
LPDIRECTDRAWSURFACE7 lpDDPrimarySurface = NULL; // dd primary surface
LPDIRECTDRAWSURFACE7 lpDDBackSurface = NULL; // dd back surface
LPDIRECTDRAWPALETTE lpDDPalette = NULL; // a pointer to the created dd palette
LPDIRECTDRAWCLIPPER lpDDClipper = NULL; // dd clipper
PALETTEENTRY palette[256]; // color palette
PALETTEENTRY save_palette[256]; // used to save palettes
DDSURFACEDESC2 DDSurfaceDesc; // a direct draw surface description struct
DDBLTFX DDbltfx; // used to fill
DDSCAPS2 DDSurfaceCaps; // a direct draw surface capabilities struct
HRESULT DDResultVal; // result back from dd calls
DWORD start_clock_count = 0; // used for timing
// FUNCTIONS ///////////////////////////////////////////////////////////////////
// this is the main message handler of the system
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
PAINTSTRUCT ps; // used in WM_PAINT
HDC hdc; // handle to a device context
switch(msg) {
case WM_CREATE: {
// do initialization stuff here
// return success
return(0);
} break;
case WM_PAINT: {
// simply validate the window
hdc = BeginPaint(hwnd,&ps);
// end painting
EndPaint(hwnd,&ps);
// return success
return(0);
} break;
case WM_DESTROY: {
// kill the application, this sends a WM_QUIT message
PostQuitMessage(0);
// return success
return(0);
} break;
default: break;
} // end switch
// process any messages that we didn't take care of
return (DefWindowProc(hwnd, msg, wparam, lparam));
} // end WinProc
////////////////////////////////////////////////////////////////////////////////
// this is the main loop of the game, do all your processing here
int Game_Main(void *parms = NULL, int num_parms = 0) {
// make sure this is not executed again
if (window_closed) return(0);
// for now test if user is hitting ESC and send WM_CLOSE
if (KEYDOWN(VK_ESCAPE) ) {
PostMessage(main_window_handle,WM_CLOSE,0,0);
window_closed = 1;
} // end if
// lock the back buffer
DDRAW_INIT_STRUCT(DDSurfaceDesc);
lpDDBackSurface->Lock(NULL, &DDSurfaceDesc, DDLOCK_SURFACEMEMORYPTR |
DDLOCK_WAIT, NULL);
// alias pointer to back buffer surface
UCHAR *back_buffer = (UCHAR*)DDSurfaceDesc.lpSurface;
// now clear the back buffer out
// linear memory?
if (DDSurfaceDesc.lPitch == SCREEN_WIDTH) {
memset(back_buffer, 0, SCREEN_WIDTH * SCREEN_HEIGHT);
} else { // non linear memory
// make copy of video pointer
UCHAR *dest_ptr = back_buffer;
// clear out memory one line at a time
for(int y = 0; y < SCREEN_HEIGHT; y++) {
// clear the next line
memset(dest_ptr, 0, SCREEN_WIDTH);
// advance pointer to next line
dest_ptr += DDSurfaceDesc.lPitch;
} // end for
} // end else
// game logic here....
// draw the next frame into the back buffer
// plot 5000 random pixels
for (int index = 0; index < 5000; index++) {
int x = rand()%SCREEN_WIDTH;
int y = rand()%SCREEN_HEIGHT;
UCHAR col = rand()%256;
back_buffer[x+y*DDSurfaceDesc.lPitch] = col;
} // end for
// unlock the back buffer
if (FAILED(lpDDBackSurface->Unlock(NULL) ) )
return(0);
// perform the flip
while(FAILED(lpDDPrimarySurface->Flip(NULL, DDFLIP_WAIT) ) );
// wait a sec
Sleep(500);
// return success or failure or your own return code here
return(1);
} // end Game_Main
////////////////////////////////////////////////////////////////////////////////
// this is called once after the initial window is created and
// before the main event loop is entered, do all your initialization here
int Game_Init(void *parms = NULL, int num_parms = 0) {
// create IDirectDraw interface 7.0 object and test for error
if (FAILED(DirectDrawCreateEx(NULL, (void **)&lpDD, IID_IDirectDraw7, NULL) ) )
return(0);
// set cooperation to fullscreen
if (FAILED(lpDD->SetCooperativeLevel(main_window_handle, DDSCL_FULLSCREEN |
DDSCL_ALLOWMODEX |
DDSCL_EXCLUSIVE |
DDSCL_ALLOWREBOOT) ) );
return(0);
// set display mode to 640x480x8
if (FAILED(lpDD->SetDisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP,
0, 0) ) )
return(0);
// clear DirectDrawSurfaceDescription and set size
DDRAW_INIT_STRUCT(DDSurfaceDesc);
// enable valid fields, surface capabilities and # of back buffers
DDSurfaceDesc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
// set the back buffer count field to 1, use 2 for triple buffering
DDSurfaceDesc.dwBackBufferCount = 1;
// request a complex, flippable
DDSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
DDSCAPS_COMPLEX | DDSCAPS_FLIP;
// create the primary surface
if (FAILED(lpDD->CreateSurface(&DDSurfaceDesc, &lpDDPrimarySurface, NULL) ) )
return(0);
// now query for attached surface from the primary surface
// this line is needed by the call
DDSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
// get te attached back buffer surface
if (FAILED(lpDDPrimarySurface->GetAttachedSurface(&DDSurfaceDesc.ddsCaps,
&lpDDBackSurface) ) )
return(0);
// build up the palette data array
for (int color = 1; color < 255; color++) {
// fill with random RGB values
palette[color].peRed = rand()%255;
palette[color].peGreen = rand()%255;
palette[color].peBlue = rand()%255;
// set flags field to PC_NOCOLLAPSE
palette[color].peFlags = PC_NOCOLLAPSE;
} // end for
// now fill in entry 0 & 255 w/ black and white
palette[0].peRed = 0;
palette[0].peGreen = 0;
palette[0].peBlue = 0;
palette[0].peFlags = PC_NOCOLLAPSE;
palette[255].peRed = 255;
palette[255].peGreen = 255;
palette[255].peBlue = 255;
palette[255].peFlags = PC_NOCOLLAPSE;
// create the palette object
if (FAILED(lpDD->CreatePalette(DDPCAPS_8BIT | DDPCAPS_ALLOW256 |
DDPCAPS_INITIALIZE,
palette, &lpDDPalette, NULL) ) )
return(0);
// finally, attach the palette to the primary surface
if (FAILED(lpDDPrimarySurface->SetPalette(lpDDPalette) ) )
return(0);
// return success or failure or your own return code here
return(1);
} // end Game_Init
/////////////////////////////////////////////////////////////
// this is called after the game is exited and the main event
// loop while is exited, do all you cleanup and shutdown here
int Game_Shutdown(void *parms = NULL, int num_parms = 0) {
// first the palette
if (lpDDPalette) {
lpDDPalette->Release();
lpDDPalette = NULL;
} // end if
// now the back buffer surface
if (lpDDBackSurface) {
lpDDBackSurface->Release();
lpDDBackSurface = NULL;
} // end if
// now the primary surface
if (lpDDPrimarySurface) {
lpDDPrimarySurface->Release();
lpDDPrimarySurface = NULL;
} // end if
// now blow away the IDirectDraw4 interface
if (lpDD) {
lpDD->Release();
lpDD = NULL;
} // end if
// return success or failure or your own return code here
return(1);
} // end Game_Shutdown
////////////////////////////////////////////////////////////////////////////////
// WINMAIN
int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance,
LPSTR lpcmdline, int ncmdshow) {
WNDCLASSEX winclass; // this will hold the class we create
HWND hwnd; // generic window handle
MSG msg; // generic message
HDC hdc; // graphics device context
// first fill in the window class stucture
winclass.cbSize = sizeof(WNDCLASSEX);
winclass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
winclass.lpfnWndProc = WindowProc;
winclass.cbClsExtra = 0;
winclass.cbWndExtra = 0;
winclass.hInstance = hinstance;
winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
winclass.hCursor = LoadCursor(NULL, IDC_ARROW);
winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
winclass.lpszMenuName = NULL;
winclass.lpszClassName = WINDOW_CLASS_NAME;
winclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
// save hinstance in global
hinstance_app = hinstance;
// register the window class
if (!RegisterClassEx(&winclass))
return(0);
// create the window
if (!(hwnd = CreateWindowEx(0, // extended style
WINDOW_CLASS_NAME, // class
"DirectDraw Initialization Demo", // title
WS_POPUP | WS_VISIBLE, // fullscreen
0,0, // initial x,y
SCREEN_WIDTH, SCREEN_HEIGHT, // initial width, height
NULL, // handle to parent
NULL, // handle to menu
hinstance, // instance of this application
NULL) ) ) // extra creation parms
return(0);
// save main window handle
main_window_handle = hwnd;
// initialize game here
Game_Init();
// enter main event loop
while(TRUE) {
// test if there is a message in queue, if so get it
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
// test if this is a quit
if (msg.message == WM_QUIT)
break;
// translate any accelerator keys
TranslateMessage(&msg);
// send the message to the window proc
DispatchMessage(&msg);
} // end if
// main game processing goes here
Game_Main();
} // end while
// closedown game here
Game_Shutdown();
// return to Windows like this
return(msg.wParam);
} // end WinMain
-
Great book, but yeah errors creep up somewhere. I'll keep looking at it and find out the problem. A minor mistake: when initializing your palette, you should be giving it rand()%256 instead of rand()%255.
What you might want to do is make a log for runtime.
Code:
void Log(std::string text) {
// Logs text to c:\\log.txt for debugging purposes.
std::ofstream out("c:\\log.txt", std::ios::out | std::ios::app);
out << text << std::endl;
out.close();
}
Then check your code like this...
Code:
hr = lpdd->CreateSurface(...); // basically any function returns an HRESULT.
if (FAILED(hr)) {
Log("Creating the surface failed.");
return false; // dont initialize any further.
}
And... do some error checking on your Game_Init() function. Game_Init() returns true if initializion succeeded (programmed by you), or false. If false, exit the program.
Code:
if (!Game_Init()) {
Log("Initializing the game failed.");
return 0;
}
You will know exactly where the problem is.
I'm just jotting down notes on every concern I have. The next one is I tried to compile your code and it didn't even try setting the display mode because the screen was still in my desktop's resolution. So, I think it runs somewhere inside Game_Init() before the display mode.
Update:
Ding ding! Look at your code here...
// set display mode to 640x480x8
if (FAILED(lpDD->SetDisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP,
0, 0) ) );
return(0);
You set the display mode with the if condition, but take a look at what that first semi-colen is doing. It doesn't return 0 if it fails. Instead, there's two things going on here. It sets the mode successfully, but then it returns 0. Your Game_Init() function thinks its done and jumps right into the main game loop. Your surfaces were never made. So, remove the first semi-colen and you'll be up and running.
-
http://www.gamedev.net/reference/pro...res/d3dsprite/
This is a much better way to go about doing 2D in 3D. This is DirectX 8 so ID3DXSprite has been changed in DX9. Check the SDK for information.
A very simple way to do blits in Direct3D:
TLVertex.h
Code:
#pragma once
#define TLVERTEXTEX1_FVF D3DFVF_XYZRHW | D3DFVF_TEX1;
struct TLVertexTex1
{
D3DXVECTOR3 vecPos;
float rhw;
float u,v;
TLVertexTex1():vecPos(D3DXVECTOR3(0.0f,0.0f,0.0f)),u(0.0f),v(0.0f),rhw(0.0f) { }
TLVertexTex1(float x,float y,float u,float v):vecPos(D3DXVECTOR3(x,y,1.0f)),u(u),v(v),rhw(1.0f) { }
};
CGameApp::RenderTestQuad()
Code:
#include "TLVertex.h"
void CGameApp::RenderTestQuad(IDirect3DTexture9 *pTexture)
{
TLVertexTex1 verts[4];
verts[0]=TLVertexTex1(0.0f,0.0f,0.0f,0.0f);
verts[1]=TLVertexTex1(200.0f,0.0f,1.0f,0.0f);
verts[2]=TLVertexTex1(200.0f,200.0f,0.0f,1.0f);
verts[3]=TLVertexTex1(200.0f,200.0f,1.0f,1.0f);
m_pDevice->SetFVF(TLVERTEXTEX1_FVF);
m_pDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLESTRIP,2,&verts,sizeof(TLVertexTex1));
}
If I coded everything correctly you should have a textured image on screen. You should be able to draw about a million of these before you get any major issues.
-
That wasn't his question nor the problem, Bubba.
-
Holy semi-colen's Batman! I did not even see that! Man, I really need to start getting more sleep.... I'll correct that and see what happens....
Although I still don't see why that would give an access violation fault.....
-
Heh, it's always those semi-colens! Think about it this way, SetDisplayMode() returned 1 because it was successful.
You did this basically...
if(1); // returned result of SetDisplayMode()
return 0;
There's basically two statements going on here instead of one!
Game_Init() had no error checking on its returned result, so it continues on and starts up the main game loop. You can easily check success or failure with something like this...
if (!Game_Init())
return 0; // basically don't jump into the game loop but exit.
But yeah, sleep helps :)
-
yeah, I realized that after I thought it through. After all, the computer is only as smart as you program it to be, and it only does what you tell it to do... even if you don't realize what it is you are telling it :P
Thanx for the help!