Hey,
I'm just in the process of getting to grips with DirectX and I wrote the following attempt at a game the other day. It wasn't origionally going to be a game, I just got carried away adding things to it. So that should explain the wierdness of it.
It all more-ales works but if you people don't mind reading over it and giving any pointers as you go along it would be much appreciated.
If anyone wants the graphics or anything else let me know..
The main source code:
/*
TITLE: DirectX Game Shell
AUTHOR: David Stubbs
DATE: 30/5/00
EMAIL: root@cod3r.cjb.net
WEB: http://cod3r.cjb.net
TEL: +44 7968 397782
TODO: Tidy code and libs
Optimise where posible
Comment more
Add end screen
Make all important stages logged to error log file
Work out why sometimes near the end of prog blt gives error invalid params
...and the surface is lost before GAME_END
Stop good guy flickering
make sure too many bad guys arnt attempted to be created at end of game
*/
//---------------------------------------------------------------------------
//Library Files
#define WIN32_LEAN_AND_MEAN // just say no to MFC
#include <windows.h> // include important windows stuff
#include <windowsx.h>
#include <mmsystem.h>
#include <iostream.h> // 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 <c:\mssdk\include\ddraw.h> //DirectDraw header file
#include <c:\mssdk\include\dinput.h> //DirectInput header file
//---------------------------------------------------------------------------
//Constants
#define WINDOW_CLASS_NAME "WINCLASS1"
//---------------------------------------------------------------------------
//Globals
HWND hMainWindow = NULL; // globally track main window
HINSTANCE hModule = NULL; // globally track hinstance
LPDIRECTDRAW lpdd = NULL; // The DirectDraw Object
LPDIRECTDRAW4 lpdd4 = NULL; // DirectX 6 interafce 4
DDSURFACEDESC2 ddsd; //Surface description
LPDIRECTDRAWSURFACE4 lpddsprimary = NULL; //Primary surface pointer
LPDIRECTDRAWSURFACE4 lpddsback = NULL;
LPDIRECTDRAWSURFACE4 MySprite = NULL;
LPDIRECTDRAWSURFACE4 MySprite2 = NULL;
LPDIRECTINPUT lpdi = NULL; // dinput object
LPDIRECTINPUTDEVICE lpdikey = NULL; // dinput keyboard
UCHAR keyboard_state[256]; // contains keyboard state table
int LevelTimer = 0;
int FPS = 0;
int FrameCount = 0;
int Lives = 3;
int Level = 1;
char TextOutput[256]= "Sprite ";
char Temp[10] = " ";
int WindowClosed = 0;
//---------------------------------------------------------------------------
struct Sprite_Type
{
int x, y;
int xv, yv;
int AnimState;
LPDIRECTDRAWSURFACE4 Surface[8];
int Frame;
} Sprite[30];
Sprite_Type Unit;
int Frame;
//---------------------------------------------------------------------------
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_RES = 16;
//---------------------------------------------------------------------------
#include "routines.cpp"
//---------------------------------------------------------------------------
//Function prototypes
LRESULT CALLBACK WindowProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam);
int Game_Main(void);
//---------------------------------------------------------------------------
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:
{
SetTimer(hwnd, 1, 1000, NULL);
}break;
case WM_TIMER:
{
FPS=FrameCount;
FrameCount=0;
}break;
case WM_PAINT:
{
hdc = BeginPaint(hwnd,&ps); //Validate the window
EndPaint(hwnd,&ps); //End painting
}break;
case WM_DESTROY:
{
PostQuitMessage(0); //Send WM_QUIT, kills application
}break;
default:break;
};
//Let windows deal with all other
return (DefWindowProc(hwnd, msg, wparam, lparam)); //messages
}
//---------------------------------------------------------------------------
void DoCharacter(void)
{
lpdikey->GetDeviceState(256, (LPVOID)keyboard_state); //Get keyboard state
if (keyboard_state[DIK_RIGHT]) //If right arrow move x right 5 pixels
Unit.x+=5;
else if (keyboard_state[DIK_LEFT])//else if keyboard left move x left 5 pixels
Unit.x+=-5;
if (keyboard_state[DIK_UP]) //If up move y -5 pixels
Unit.y+=-5;
else if (keyboard_state[DIK_DOWN])
Unit.y+=5; //else if down move y +5 pixles
if (Unit.x<=1)
Unit.x=1; //If user at end of screen on left hold them there
else if (Unit.x>=SCREEN_WIDTH-50)
Unit.x = SCREEN_WIDTH-50; //Same for right hand side
if (Unit.y<=1)
Unit.y=1; //And top of screeen
else if (Unit.y>=SCREEN_HEIGHT-50)
Unit.y = SCREEN_HEIGHT-50; //Finally left
Unit.Frame++; //Move onto next animation frame
if (Unit.Frame >=9)
Unit.Frame=1; //If at end of animation sequence start again
//Draw unit to screen
BlitSurface(Unit.Surface[Unit.Frame], lpddsback, 140, 100, 50, 30, Unit.x, Unit.y);
}
//---------------------------------------------------------------------------
void DoEnemy(void)
{
for (int i=0; i<Level+5; i++) //For all the enemy sprites
{
Sprite<i>.x+=Sprite[i].xv; //Increment x + y positions by velocity
Sprite[i].y+=Sprite[i].yv;
if (Sprite[i].x <= 1)
Sprite[i].xv = 3; //If sprite hits left wayy set velocity to positive
if (Sprite[i].x>SCREEN_WIDTH-51) //Right wall then set moving left
Sprite[i].xv = -3;
if (Sprite[i].y <=1 ) //Top set moving down
Sprite[i].yv = 3;
if (Sprite[i].y>SCREEN_HEIGHT-51) //Bottom set movinf up
Sprite[i].yv = -3;
if (Sprite[i].AnimState==0) //Check which animation frame and draw it
{
BlitSurface(MySprite, lpddsback, 280, 140, 50, 50,Sprite[i].x, Sprite[i].y);
Sprite[i].AnimState=1;
}
else if (Sprite[i].AnimState=1)
{
BlitSurface(MySprite2, lpddsback, 280, 140, 50, 50,Sprite[i].x, Sprite[i].y);
Sprite[i].AnimState=0;
}
//Check for user and enemy collision
if ((Unit.x >= Sprite[i].x) && (Unit.x <= Sprite[i].x+50))
if ((Unit.y >= Sprite[i].y) && (Unit.y <= Sprite[i].y+50))
{
Lives--; //If so decrement lives
Unit.x=320; //Move user to centre screen
Unit.y=240;
if (Lives<1) //If no more lives then quit
{
PostMessage(hMainWindow,WM_CLOSE,0,0);
WindowClosed = 1;
}
}
}
}
//---------------------------------------------------------------------------
int Game_Main(void)
{
DWORD StartTime=GetTickCount(); //Get tickcount at start of routine
LevelTimer++;
if (LevelTimer % 500 == 0)
Level++;
if (WindowClosed) //Don't re-run code after exit
return(0);
lpdikey->GetDeviceState(256, (LPVOID)keyboard_state); //Get keyboard state
if (keyboard_state[DIK_ESCAPE]) //If right arrow move x right 5 pixels //Test for escapoe key, if so quit
{
WindowClosed = 1;
PostMessage(hMainWindow,WM_CLOSE,0,0);
return(0);
}
FillScreen(lpddsback, RGB(0,0,0)); //Clear back buffer
DoCharacter(); //Sort out character
DoEnemy(); //And enemy
//Display screen stats
wsprintf(TextOutput, "Frames Per Second: %d Lives: %d Level: %d", FPS, Lives, Level);
Draw_Text_GDI(TextOutput,0, 0, RGB(0, 255, 0), lpddsback);
lpddsprimary->Flip(NULL, DDFLIP_WAIT); //Flip primary and back buffer
FrameCount++; //Another frame rendered
int difference=GetTickCount(); //Get finish time of routine
//If we arnt running at 30FPS slow down to 30FPS
if ((difference - StartTime) < 33)
Sleep (difference);
return(1);
}
//---------------------------------------------------------------------------
int Game_Init(void *parms = NULL, int num_parms = 0)
{
HFILE File;
DeleteFile("errors.log"); //Delete old log file and create empty new one
_lcreat("errors.log", 0);
_lclose(File);
ShowCursor(FALSE); //Hide the mouse cursor
LogProg("STARTING: GameInit", FALSE);
DirectDrawCreate(NULL, &lpdd, NULL); //Get DD4 Interface
lpdd->QueryInterface(IID_IDirectDraw4, (LPVOID *)&lpdd4);
lpdd->Release();
LogProg(" Setting coop level", FALSE); //Set cooperation level
lpdd4->SetCooperativeLevel(hMainWindow, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX | DDSCL_ALLOWREBOOT);
LogProg(" Setting display mode", FALSE); //Set display mode
lpdd4->SetDisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_RES, 0, 0);
DDRAW_INIT_STRUCT(ddsd); //clear surface description and set size
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; //Enable valid fields
ddsd.dwBackBufferCount = 1; //Enable 1 back buffer
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
LogProg(" Creating surface", FALSE);
lpdd4->CreateSurface(&ddsd, &lpddsprimary, NULL); //Create the primary surface
ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;//And get a handle to the back buffer
lpddsprimary->GetAttachedSurface(&ddsd.ddsCaps, &lpddsback);
LogProg(" Attaching clipper to primary buffer", FALSE);
RECT RectList[1]={0,0,SCREEN_WIDTH,SCREEN_HEIGHT};
AttachClipper(lpddsprimary, 1, RectList);//Attach a clipper to the full screen
LogProg(" Attaching clipper to back buffer", FALSE);
AttachClipper(lpddsback, 1, RectList);//Attach a clipper to the full screen
LogProg(" Loading and drawing logo to primary surface", FALSE);
//Draw the startup image to the screen
BlitSurface(File2NewSurface("logo.bmp"), lpddsprimary, 640, 480, 640, 480,0,0);
LogProg(" Loading oponent sprites", FALSE);
//Load opponents images and output progress
MySprite=File2NewSurface("n0p3x.bmp");
Draw_Text_GDI("Loading Images.",0, 0, RGB(0, 255, 0), lpddsprimary);
MySprite2=File2NewSurface("n0p3x2.bmp");;
Draw_Text_GDI("Loading Images..",0, 0, RGB(0, 255, 0), lpddsprimary);
LogProg(" Loading users animation frames", FALSE);
//Load all frames of animation for users unit
Unit.Surface[1]=File2NewSurface("unit1.bmp");
Draw_Text_GDI("Loading Images...",0, 0, RGB(0, 255, 0), lpddsprimary);
Unit.Surface[2]=File2NewSurface("unit2.bmp");
Draw_Text_GDI("Loading Images....",0, 0, RGB(0, 255, 0), lpddsprimary);
Unit.Surface[3]=File2NewSurface("unit3.bmp");
Draw_Text_GDI("Loading Images.....",0, 0, RGB(0, 255, 0), lpddsprimary);
Unit.Surface[4]=File2NewSurface("unit4.bmp");
Draw_Text_GDI("Loading Images......",0, 0, RGB(0, 255, 0), lpddsprimary);
Unit.Surface[5]=File2NewSurface("unit5.bmp");
Draw_Text_GDI("Loading Images.......",0, 0, RGB(0, 255, 0), lpddsprimary);
Unit.Surface[6]=File2NewSurface("unit6.bmp");
Draw_Text_GDI("Loading Images........",0, 0, RGB(0, 255, 0), lpddsprimary);
Unit.Surface[7]=File2NewSurface("unit7.bmp");
Draw_Text_GDI("Loading Images.........",0, 0, RGB(0, 255, 0), lpddsprimary);
Unit.Surface[8]=File2NewSurface("unit8.bmp");
Draw_Text_GDI("Loading Images..........done",0, 0, RGB(0, 255, 0), lpddsprimary);
Unit.Frame=1; //Set current annimation frame to 1
LogProg(" Initialising sprites start positions", FALSE);
//Initialise all opponents details
Draw_Text_GDI("Initialising sprites....",0, 12, RGB(0, 255, 0), lpddsprimary);
for (int i=0; i<21; i++)
{
Sprite[i].x =rand()%SCREEN_WIDTH;
Sprite[i].y =rand()%SCREEN_HEIGHT;
Sprite[i].xv =3;
Sprite[i].yv =3;
Sprite[i].AnimState=0;
}
Unit.x=320; //Set users starting position
Unit.y=240;
Draw_Text_GDI("Initialising sprites.......done",0, 12, RGB(0, 255, 0), lpddsprimary);
Draw_Text_GDI("Initialising keyboard...",0, 24, RGB(0, 255, 0), lpddsprimary);
LogProg(" Creating DINPUT object", FALSE);
//Create the direct input object
if (DirectInputCreate(hModule,DIRECTINPUT_VERSION,&lpdi,NULL)!=DI_OK)
return(0);
LogProg(" Creating a keyboard device", FALSE);
//Create a keyboard device
if (lpdi->CreateDevice(GUID_SysKeyboard, &lpdikey, NULL)!=DI_OK)
return(0);
LogProg(" Setting keyboard co-op level", FALSE);
//Set cooperation level
if (lpdikey->SetCooperativeLevel(hMainWindow,
DISCL_NONEXCLUSIVE | DISCL_BACKGROUND)!=DI_OK)
return(0);
LogProg(" Setting keyboard data format", FALSE);
if (lpdikey->SetDataFormat(&c_dfDIKeyboard)!=DI_OK) //Set data format
return(0);
LogProg(" Acquiring the keyboard", FALSE);
if (lpdikey->Acquire()!=DI_OK) //Acquire the keyboard
return(0);
Draw_Text_GDI("Initialising keyboard...done",0, 24, RGB(0, 255, 0), lpddsprimary);
LogProg(" Waiting for enter key before continuing", FALSE);
do //Loop until enter pressed
{
lpdikey->GetDeviceState(256, (LPVOID)keyboard_state);
}
while (!keyboard_state[DIK_RETURN]);
LogProg("ENDING: GameInit", FALSE);
return(1);
}
//---------------------------------------------------------------------------
int Game_Shutdown(void *parms = NULL, int num_parms = 0)
{
LogProg("STARTING: Game_Shutdown", FALSE);
//Surface is lost by this point. Why?
//BlitSurface(File2NewSurface("end.bmp"), lpddsprimary, 640, 480, 640, 480,0,0);
LogProg(" Releasing keyboard", FALSE);
lpdikey->Unacquire(); //Release the keyboard
lpdikey->Release();
lpdi->Release();
LogProg(" Releasing users sprite animation frames", FALSE);
for (int i=1; i<8; i++) //Kill all frames of users sprite
if (Unit.Surface[i])
{
Unit.Surface[i]->Release();
Unit.Surface[i]=NULL;
}
LogProg(" Releasing opponent sprite animation frames", FALSE);
if (MySprite) //Kill opponent sprites
{
MySprite->Release();
MySprite=NULL;
}
if (MySprite2)
{
MySprite2->Release();
MySprite=NULL;
}
LogProg(" Releasing back buffer", FALSE);
if (lpddsback) //Kill the back buffer
{
lpddsback->Release();
lpddsback=NULL;
}
LogProg(" Releasing primary surface", FALSE);
if (lpddsprimary) //...The primary surface
{
lpddsprimary->Release();
lpddsprimary=NULL;
}
LogProg(" Releasing DDraw object", FALSE);
if (lpdd4) //Finally the DD object
{
lpdd4->Release();
lpdd4 = NULL;
}
LogProg("ENDING: Game_Shutdown", FALSE);
return(1);
}
//---------------------------------------------------------------------------
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);
hModule = hinstance; //Save hinstance in global
if (!RegisterClassEx(&winclass)) //Register the window class
return(0);
// create the window
if (!(hwnd = CreateWindowEx(NULL, //Extended style
WINDOW_CLASS_NAME, //Class
"DirectX Game Shell" , //Title
WS_VISIBLE | WS_POPUP,
0,0, //Initial x,y
400,300, //Initial width, height
NULL, //Handle to parent
NULL, //Handle to menu
hinstance, //Instance of this application
NULL))) //Extra creation parms
LogProg("ERROR: WinMain, CreateWindow", TRUE);
hMainWindow = hwnd; //Save main window handle
Game_Init(); //Initialize game here
while(TRUE) //Enter main event loop
{
//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;
TranslateMessage(&msg); //Translate any accelerator keys
DispatchMessage(&msg); //Send the message to the window proc
}
Game_Main(); //Main game processing goes here
}
Game_Shutdown(); //Close down game
ShowCursor(TRUE); //Give the user the cursor back
LogProg("*END*", FALSE);
return(msg.wParam);
}
//---------------------------------------------------------------------------
[/source]
The routines.cpp file:
[source]
#define WIN32_LEAN_AND_MEAN // just say no to MFC
//----------------------------------------------------------------------------
#define _RGB16BIT565(r,g,b) ((b%32) + ((g%64) << 5) + ((r%32) << 11))
#define DDRAW_INIT_STRUCT(ddstruct) { memset(&ddstruct,0,sizeof(ddstruct)); ddstruct.dwSize=sizeof(ddstruct); }
#define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEYUP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)
//----------------------------------------------------------------------------
typedef struct BITMAP_FILE_TAG
{
BITMAPFILEHEADER bitmapfileheader;
BITMAPINFOHEADER bitmapinfoheader;
PALETTEENTRY palette[256];
UCHAR *buffer;
} BITMAP_FILE, *BITMAP_FILE_PTR;
//---------------------------------------------------------------------------
#define MAX_COLORS_PALETTE 256
#define INITGUID
//---------------------------------------------------------------------------
const int BITMAP_ID = 0x4D42;
//---------------------------------------------------------------------------
typedef unsigned short USHORT;
typedef unsigned short WORD;
typedef unsigned char UCHAR;
typedef unsigned char BYTE;
//----------------------------------------------------------------------------
//When sent a DirectX error code outputs actual errors name to error log file
void ErrorCode2Log(HRESULT errcd);
//Copies a bitmap to a surface at given xy coordinates
void Bmp2Surface(BITMAP_FILE_PTR Bitmap, LPDIRECTDRAWSURFACE4 &lpddsSurface, int x, int y);
//Logs given text to a error log file. Exits program if desired
void LogProg(char *ErrorMessage, bool Exit);
//Loads a bitmap file into memory
int Load_Bitmap_File(BITMAP_FILE_PTR bitmap, char *filename);
//Unloads a nbitmap file from memory
int UnloadBitmapFile(BITMAP_FILE_PTR Bitmap);
//Attaches a clipper to desired surface
LPDIRECTDRAWCLIPPER AttachClipper(LPDIRECTDRAWSURFACE4 lpdds, int num_rects, LPRECT clip_list);
//Creates desired surface
LPDIRECTDRAWSURFACE4 CreateSurface(int width, int height, int mem_flags, int color_key=0);
//Creates a new surface for given bitmap and copies it there
LPDIRECTDRAWSURFACE4 File2NewSurface(BITMAP_FILE_PTR Bitmap);
//Copies one surface to the other using the hardware blitter. If dest>src image is stretched
void BlitSurface(LPDIRECTDRAWSURFACE4 &lpddsSource, LPDIRECTDRAWSURFACE4 &lpddsDest, int Swidth, int Sheight,int Dwidth, int Dheight, int x, int y);
//Draws desired text using GDI
void Draw_Text_GDI(char *text, int x,int y,COLORREF color, LPDIRECTDRAWSURFACE4 lpdds);
//Fills screen desired colour
void FillScreen(LPDIRECTDRAWSURFACE4 &lpddsSurf, COLORREF Colour);
//----------------------------------------------------------------------------
byte Get16bitFormat(LPDIRECTDRAWSURFACE4 lpDDSPrimary)
{
DDPIXELFORMAT ddpf;
memset(&ddpf,0,sizeof(DDPIXELFORMAT));
ddpf.dwSize=sizeof(DDPIXELFORMAT);
byte gfxmode=0;
if (lpDDSPrimary->GetPixelFormat(&ddpf)==DD_OK)
{
if ((ddpf.dwGBitMask /32) == 31 )
gfxmode =1;
if ((ddpf.dwGBitMask /32) == 63 )
gfxmode =2;
}
else
gfxmode = 255;
return gfxmode;
}
//----------------------------------------------------------------------------
void FillScreen(LPDIRECTDRAWSURFACE4 &lpddsSurf, COLORREF Colour )
{
DDBLTFX ddbltfx; //The blitter fx structure
DDRAW_INIT_STRUCT(ddbltfx); //Initialise the structure
ddbltfx.dwFillColor = Colour; //Set the colour to blit
//Blit colour to surface
if (FAILED(lpddsSurf->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx)))
LogProg("ERROR: FillScreen, Blitting colour to surface", FALSE);
}
//----------------------------------------------------------------------------
void Draw_Text_GDI(char *text, int x,int y,COLORREF color, LPDIRECTDRAWSURFACE4 lpdds)
{
HDC xdc; //The working dc
if (FAILED(lpdds->GetDC(&xdc))) //Get the dc from surface
LogProg("ERROR: Draw_Text_GDI, Getting surface DC", TRUE);
SetTextColor(xdc,color); //Set the colors for the text up
//Set background mode to transparent so black isn't copied
SetBkMode(xdc, TRANSPARENT);
TextOut(xdc,x,y,text,strlen(text)); //Draw the text
lpdds->ReleaseDC(xdc); //Release the DC
}
//----------------------------------------------------------------------------
void ErrorCode2Log(HRESULT errcd)
{
char ErrorString[255];
strcpy(ErrorString, "ERROR: ErrorCode2Log ANALYSIS: ");
if (errcd == DDERR_GENERIC)
strcat(ErrorString, "DDERR_GENERIC");
if (errcd == DDERR_INVALIDCLIPLIST)
strcat(ErrorString, "DDERR_INVALIDCLIPLIST");
if (errcd == DDERR_INVALIDOBJECT)
strcat(ErrorString, "DDERR_INVALIDOBJECT");
if (errcd == DDERR_INVALIDPARAMS)
strcat(ErrorString, "DDERR_INVALIDPARAMS");
if (errcd == DDERR_INVALIDRECT)
strcat(ErrorString, "DDERR_INVALIDRECT");
if (errcd == DDERR_NOALPHAHW)
strcat(ErrorString, "DDERR_NOALPHAHW");
if (errcd == DDERR_NOBLTHW)
strcat(ErrorString, "DDERR_NOBLTHW");
if (errcd == DDERR_NOCLIPLIST)
strcat(ErrorString, "DDERR_NOCLIPLIST");
if (errcd == DDERR_NODDROPSHW)
strcat(ErrorString, "DDERR_NODDROPSHW");
if (errcd == DDERR_NOMIRRORHW)
strcat(ErrorString, "DDERR_NOMIRRORHW");
if (errcd == DDERR_NORASTEROPHW)
strcat(ErrorString, "DDERR_NORASTEROPHW");
if (errcd == DDERR_NOROTATIONHW)
strcat(ErrorString, "DDERR_NOROTATIONHW");
if (errcd == DDERR_NOSTRETCHHW)
strcat(ErrorString, "DDERR_NOSTRETCHHW");
if (errcd == DDERR_NOZBUFFERHW)
strcat(ErrorString, "DDERR_NOZBUFFERHW");
if (errcd == DDERR_SURFACEBUSY)
strcat(ErrorString, "DDERR_SURFACEBUSY");
if (errcd == DDERR_SURFACELOST)
strcat(ErrorString, "DDERR_SURFACELOST");
if (errcd == DDERR_UNSUPPORTED)
strcat(ErrorString, "DDERR_UNSUPPORTED");
if (errcd == DDERR_WASSTILLDRAWING)
strcat(ErrorString, "DDERR_WASSTILLDRAWING");
LogProg(ErrorString, FALSE);
}
//----------------------------------------------------------------------------
void BlitSurface(LPDIRECTDRAWSURFACE4 &lpddsSource, LPDIRECTDRAWSURFACE4 &lpddsDest, int Swidth, int Sheight,int Dwidth, int Dheight, int x, int y)
{
RECT SourceRect, DestRect;
DestRect.left = x; //Set the destination rect
DestRect.top = y;
DestRect.right = x+Dwidth-1;
DestRect.bottom = y+Dheight-1;
SourceRect.left = 0; //Set the source rect
SourceRect.top = 0;
SourceRect.right = Swidth-1;
SourceRect.bottom = Sheight-1;
HRESULT errcd = lpddsDest->Blt(&DestRect, lpddsSource, &SourceRect, (DDBLT_WAIT | DDBLT_KEYSRC), NULL);
if (FAILED(errcd))
{
char ErrorString[255];
wsprintf(ErrorString, "ERROR: BlitSurface, Blitting image of %d*%d, to %d*%d, Error Code: %d", Swidth, Sheight, Dwidth, Dheight, errcd);
LogProg(ErrorString, FALSE);
ErrorCode2Log(errcd);
}
}
//----------------------------------------------------------------------------
LPDIRECTDRAWSURFACE4 File2NewSurface(char *FileName)
{
LPDIRECTDRAWSURFACE4 NewSurface;
BITMAP_FILE Bitmap;
Load_Bitmap_File(&Bitmap, FileName); //Load the desired bitmap
//Create a surface for it
NewSurface=CreateSurface(int(Bitmap.bitmapinfoheader.biWidth), int(Bitmap.bitmapinfoheader.biHeight), DDSCAPS_SYSTEMMEMORY); //DDSCAPS_VIDEOMEMORY
Bmp2Surface(&Bitmap, NewSurface, 0, 0); //Copy image to surface
UnloadBitmapFile(&Bitmap); //Unload unneeded bitmap
return (NewSurface); //Return new surface with bitmap
}
//----------------------------------------------------------------------------
LPDIRECTDRAWCLIPPER AttachClipper(LPDIRECTDRAWSURFACE4 lpdds, int num_rects, LPRECT clip_list)
{
int index; //Looping var
LPDIRECTDRAWCLIPPER lpddclipper; //Pointer to the newly created dd clipper
LPRGNDATA region_data; //Pointer to the region data that contains
//The header and clip list
//First create the direct draw clipper
if (FAILED(lpdd4->CreateClipper(0,&lpddclipper,NULL)))
LogProg("ERROR: AttachClipper, Creating DDraw clipper", TRUE);
// now create the clip list from the sent data
// first allocate memory for region data
region_data = (LPRGNDATA)malloc(sizeof(RGNDATAHEADER)+num_rects*sizeof(RECT));
// now copy the rects into region data
memcpy(region_data->Buffer, clip_list, sizeof(RECT)*num_rects);
// set up fields of header
region_data->rdh.dwSize = sizeof(RGNDATAHEADER);
region_data->rdh.iType = RDH_RECTANGLES;
region_data->rdh.nCount = num_rects;
region_data->rdh.nRgnSize = num_rects*sizeof(RECT);
region_data->rdh.rcBound.left = 64000;
region_data->rdh.rcBound.top = 64000;
region_data->rdh.rcBound.right = -64000;
region_data->rdh.rcBound.bottom = -64000;
// find bounds of all clipping regions
for (index=0; index<num_rects; index++)
{
// test if the next rectangle unioned with the current bound is larger
if (clip_list[index].left < region_data->rdh.rcBound.left)
region_data->rdh.rcBound.left = clip_list[index].left;
if (clip_list[index].right > region_data->rdh.rcBound.right)
region_data->rdh.rcBound.right = clip_list[index].right;
if (clip_list[index].top < region_data->rdh.rcBound.top)
region_data->rdh.rcBound.top = clip_list[index].top;
if (clip_list[index].bottom > region_data->rdh.rcBound.bottom)
region_data->rdh.rcBound.bottom = clip_list[index].bottom;
} // end for index
// now we have computed the bounding rectangle region and set up the data
// now let's set the clipping list
if (FAILED(lpddclipper->SetClipList(region_data, 0)))
{
// release memory and return error
free(region_data);
return(NULL);
} // end if
// now attach the clipper to the surface
if (FAILED(lpdds->SetClipper(lpddclipper)))
{
// release memory and return error
free(region_data);
return(NULL);
} // end if
// all is well, so release memory and send back the pointer to the new clipper
free(region_data);
return(lpddclipper);
} // end DDraw_Attach_Clipper
//----------------------------------------------------------------------------
int Flip_Bitmap(UCHAR *image, int bytes_per_line, int height)
{
// this function is used to flip bottom-up .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(ℑ[((height-1) - index)*bytes_per_line],
&buffer[index*bytes_per_line], bytes_per_line);
// release the memory
free(buffer);
// return success
return(1);
}
//----------------------------------------------------------------------------
void Bmp2Surface(BITMAP_FILE_PTR Bitmap, LPDIRECTDRAWSURFACE4 &lpddsSurface, int x, int y)
{
DDSURFACEDESC2 ddsd; //Surface description
LogProg("STARTING: Bmp2Surface", FALSE);
DDRAW_INIT_STRUCT(ddsd);
lpddsSurface->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
USHORT *PrimaryBuffer=(USHORT *)ddsd.lpSurface;
// process each line and copy it into the primary buffer
for (int index_y = 0; index_y < Bitmap->bitmapinfoheader.biHeight; index_y++)
{
for (int index_x = 0; index_x < Bitmap->bitmapinfoheader.biWidth; index_x++)
{
// get BGR values, note the scaling down of the channels, so that they
// fit into the 5.6.5 format
UCHAR blue = (Bitmap->buffer[index_y*Bitmap->bitmapinfoheader.biWidth*3 + index_x*3 + 0]) >> 3,
green = (Bitmap->buffer[index_y*Bitmap->bitmapinfoheader.biWidth*3 + index_x*3 + 1]) >> 3,
red = (Bitmap->buffer[index_y*Bitmap->bitmapinfoheader.biWidth*3 + index_x*3 + 2]) >> 3;
// this builds a 16 bit color value in 5.6.5 format (green dominant mode)
USHORT pixel = _RGB16BIT565(red,green,blue);
// write the pixel
PrimaryBuffer[index_x+x + (index_y*ddsd.lPitch >> 1)+y*SCREEN_WIDTH] = pixel;
} // end for index_x
} // end for index_y
LogProg(" Unlocking primary surface", FALSE);
lpddsSurface->Unlock(NULL);
}
//----------------------------------------------------------------------------
void LogProg(char *ErrorMessage, bool Exit)
{
HFILE FileHandle;
FileHandle=_lopen("ERRORS.LOG", OF_WRITE);
_llseek(FileHandle, 0, FILE_END);
_lwrite(FileHandle, ErrorMessage, lstrlen(ErrorMessage));
_lwrite(FileHandle, "\r\n", 2);
_lclose(FileHandle);
if (Exit)
exit(0);
}
//----------------------------------------------------------------------------
int UnloadBitmapFile(BITMAP_FILE_PTR Bitmap)
{
LogProg("STARTING: UnloadBitmapFile", FALSE);
if (Bitmap->buffer)
{
free(Bitmap->buffer);
Bitmap->buffer = NULL;
}
LogProg("ENDING: UnloadBitmapFile", FALSE);
return(1);
}
//----------------------------------------------------------------------------
LPDIRECTDRAWSURFACE4 CreateSurface(int width, int height, int mem_flags, int color_key)
{
// this function creates an offscreen plain surface
DDSURFACEDESC2 ddsd; // working description
LPDIRECTDRAWSURFACE4 lpdds; // temporary surface
// set to access caps, width, and height
memset(&ddsd,0,sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
// set dimensions of the new bitmap surface
ddsd.dwWidth = width;
ddsd.dwHeight = height;
// set surface to offscreen plain
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | mem_flags;
// create the surface
if (FAILED(lpdd4->CreateSurface(&ddsd,&lpdds,NULL)))
return(NULL);
// test if user wants a color key
if (color_key >= 0)
{
// set color key to color 0
DDCOLORKEY color_key; // used to set color key
color_key.dwColorSpaceLowValue = 0;
color_key.dwColorSpaceHighValue = 0;
// now set the color key for source blitting
lpdds->SetColorKey(DDCKEY_SRCBLT, &color_key);
} // end if
// return surface
return(lpdds);
} // end DDraw_Create_Surface
//----------------------------------------------------------------------------
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
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));
// now load the color palette if there is one
if (bitmap->bitmapinfoheader.biBitCount == 8)
{
_lread(file_handle, &bitmap->palette,MAX_COLORS_PALETTE*sizeof(PALETTEENTRY));
// now set all the flags in the palette correctly and fix the reversed
// BGR RGBQUAD data format
for (index=0; index < MAX_COLORS_PALETTE; index++)
{
// reverse the red and green fields
int temp_color = bitmap->palette[index].peRed;
bitmap->palette[index].peRed = bitmap->palette[index].peBlue;
bitmap->palette[index].peBlue = temp_color;
// always set the flags word to this
bitmap->palette[index].peFlags = PC_NOCOLLAPSE;
} // end for index
} // end if
// finally the image data itself
_llseek(file_handle,-(int)(bitmap->bitmapinfoheader.biSizeImage),SEEK_END);
// now read in the image, if the image is 8 or 16 bit then simply read it
// but if its 24 bit then read it into a temporary area and then convert
// it to a 16 bit image
if (bitmap->bitmapinfoheader.biBitCount==8 || bitmap->bitmapinfoheader.biBitCount==16 ||
bitmap->bitmapinfoheader.biBitCount==24)
{
// delete the last image if there was one
// if (bitmap->buffer)
// free(bitmap->buffer);
// 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
{
// serious problem
return(0);
} // end else
// 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
//----------------------------------------------------------------------------
The errors.log file
STARTING: GameInit
Setting coop level
Setting display mode
Creating surface
Attaching clipper to primary buffer
Attaching clipper to back buffer
Loading and drawing logo to primary surface
STARTING: Bmp2Surface
Unlocking primary surface
STARTING: UnloadBitmapFile
ENDING: UnloadBitmapFile
Loading oponent sprites
STARTING: Bmp2Surface
Unlocking primary surface
STARTING: UnloadBitmapFile
ENDING: UnloadBitmapFile
STARTING: Bmp2Surface
Unlocking primary surface
STARTING: UnloadBitmapFile
ENDING: UnloadBitmapFile
Loading users animation frames
STARTING: Bmp2Surface
Unlocking primary surface
STARTING: UnloadBitmapFile
ENDING: UnloadBitmapFile
STARTING: Bmp2Surface
Unlocking primary surface
STARTING: UnloadBitmapFile
ENDING: UnloadBitmapFile
STARTING: Bmp2Surface
Unlocking primary surface
STARTING: UnloadBitmapFile
ENDING: UnloadBitmapFile
STARTING: Bmp2Surface
Unlocking primary surface
STARTING: UnloadBitmapFile
ENDING: UnloadBitmapFile
STARTING: Bmp2Surface
Unlocking primary surface
STARTING: UnloadBitmapFile
ENDING: UnloadBitmapFile
STARTING: Bmp2Surface
Unlocking primary surface
STARTING: UnloadBitmapFile
ENDING: UnloadBitmapFile
STARTING: Bmp2Surface
Unlocking primary surface
STARTING: UnloadBitmapFile
ENDING: UnloadBitmapFile
STARTING: Bmp2Surface
Unlocking primary surface
STARTING: UnloadBitmapFile
ENDING: UnloadBitmapFile
Initialising sprites start positions
Creating DINPUT object
Creating a keyboard device
Setting keyboard co-op level
Setting keyboard data format
Acquiring the keyboard
Waiting for enter key before continuing
ENDING: GameInit
ERROR: BlitSurface, Blitting image of 140*100, to 50*30, Error Code: -2147024809
ERROR: ErrorCode2Log ANALYSIS: DDERR_INVALIDPARAMS
ERROR: BlitSurface, Blitting image of 140*100, to 50*30, Error Code: -2147024809
ERROR: ErrorCode2Log ANALYSIS: DDERR_INVALIDPARAMS
STARTING: Game_Shutdown
Releasing keyboard
Releasing users sprite animation frames
Releasing opponent sprite animation frames
Releasing back buffer
Releasing primary surface
Releasing DDraw object
ENDING: Game_Shutdown
*END*
Thanks..
Dave
Edited by - n0p3x on 7/23/00 7:52:10 AM