Original Post
Hi everyone,
Expect posts from me on this forum now :D I''m using Jim Adam''s book and Drunken Hyena''s tutorials. After 4.5 months of C++, it''s a welcoming change :D Anyway, I''m basically playing around at the moment, mixing some of his code with Drunken Hyena''s, and this program isn''t working correctly. I can''t find the problem either. This is supposed to open at fullscreen, display a square, with a texture on it. The screen is constantly flashing a purple like color on opening. The texture is in the correct directory, but I doubt that''s having an impact at the moment. Here''s my code:
Thanks
-Peter
//These are the necessary includes
#define WIN32_LEAN_AND_MEAN //Excludes rarely used stuff
#include <windows.h>
#include <d3dx8.h>
#pragma comment( lib, "d3d8.lib" )//Includes libraries
#pragma comment( lib, "d3dx8.lib" )
//All the function prototypes
void FatalError( const char* p_error_msg );
void FatalError( HRESULT p_hr, const char* p_error_msg );
LRESULT CALLBACK default_window_proc(HWND p_hwnd,UINT p_msg,WPARAM p_wparam,LPARAM p_lparam);
void init_window();
void kill_window();
void init_d3d();
void kill_d3d();
void init_scene();
void kill_scene();
void message_pump();
D3DFORMAT find_16bit_mode();
void render();
void NOP(HINSTANCE p_prev_instance,LPSTR p_cmd_line,int p_show);
//Name of the application
const char g_app_name[] = "Framework for Tutorials";
//Screen window sizes
const int g_width = 640;
const int g_height = 480;
//Global handle to main window
HWND g_main_window = NULL;
//Global handle to our instance
HINSTANCE g_instance;
//Global flag to check if app should end
bool g_app_done = false;
//Main DIRECT3D8 object
IDirect3D8* g_D3D=NULL;
//DIRECT3DDEVICE object
IDirect3DDevice8* g_d3d_device = NULL;
struct my_vertex
{
FLOAT x, y, z;
FLOAT rhw;
FLOAT u, v;
};
#define VERTEXFVF ( D3DFVF_XYZRHW | D3DFVF_TEX1 )
my_vertex g_Square[ 4 ] =
{
{ 150.0f, 150.0f, 0.0f, 1.0f, 0.0f, 0.0f },
{ 150.0f, 300.0f, 0.0f, 1.0f, 0.0f, 1.0f },
{ 300.0f, 150.0f, 0.0f, 1.0f, 1.0f, 0.0f },
{ 300.0f, 300.0f, 0.0f, 1.0f, 1.0f, 1.0f }
};
//Make a vertex buffer
IDirect3DVertexBuffer8* g_VB = NULL;
//Make a texture pointer
IDirect3DTexture8* g_Texture = NULL;
//WinMain function
int APIENTRY WinMain(HINSTANCE p_instance,HINSTANCE p_prev_instance,LPSTR p_cmd_line,int p_show)
{
//Save the instance in the function
g_instance = p_instance;
//Quiet compiler warnings
NOP(p_prev_instance,p_cmd_line,p_show);
//Build window
init_window();
//Build 3D objects
init_d3d();
//Preparation to build objects and other stuff
init_scene();
//Loop until the user aborts
while( !g_app_done )
{
message_pump(); //Check for window messages
render(); // Render stuff
}
//Free all objects and resources
kill_scene();
//Clean up all 3D objects
kill_d3d();
//Close down window
kill_window();
//Exit
return 0;
}
//FUNCTION DEFINITIONS
void NOP(HINSTANCE p_prev_instance,LPSTR p_cmd_line,int p_show)
{
p_prev_instance=p_prev_instance;
p_cmd_line=p_cmd_line;
p_show=p_show;
}
void message_pump()
{
MSG msg;
if(PeekMessage(&msg, NULL, 0, 0,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
//Registers a window class and then creates the window
void init_window()
{
ULONG window_width, window_height;
WNDCLASS window_class;
DWORD style;
//Fill in all the fields for the WNDCLASS structure. Window classes
//are a sort of template for window creation. You could create many
//windows using the same window class.
window_class.style = CS_OWNDC;
window_class.cbClsExtra = 0;
window_class.cbWndExtra = 0;
window_class.hInstance = g_instance;
window_class.hIcon = LoadIcon(NULL,IDI_APPLICATION);
window_class.hCursor = LoadCursor(NULL,IDC_ARROW);
window_class.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
window_class.lpszMenuName = NULL;
window_class.lpszClassName = "DH Class";
//Here we provide our default window handler, all windows messages
//will be sent to this function.
window_class.lpfnWndProc = default_window_proc;
//Register the class with windows
if(!RegisterClass(&window_class)){
FatalError("Error registering window class");
}
//When running full screen, we cover the desktop with our window.
//This isn''t necessary, but it provides a smoother transition for the
//user, especially when we''re going to change screen modes.
window_width=GetSystemMetrics(SM_CXSCREEN);
window_height=GetSystemMetrics(SM_CYSCREEN);
style=WS_POPUP;
//Here we actually create the window. For more detail on the various
//parameters please refer to the Win32 documentation.
g_main_window=CreateWindow("DH Class", //name of our registered class
g_app_name, //Window name/title
style, //Style flags
0, //X position
0, //Y position
window_width,//width of window
window_height,//height of window
NULL, //Parent window
NULL, //Menu
g_instance, //application instance handle
NULL); //pointer to window-creation data
if(!g_main_window){
FatalError("Error opening window");
}
//The next 3 lines just make sure that our window is visible and has the
//input focus. It''s not strictly necessary, but it doesn''t hurt to be
//thorough.
ShowWindow(g_main_window,SW_SHOW);
UpdateWindow(g_main_window);
SetFocus(g_main_window);
}
//Unregister and destroy window
void kill_window(){
//Test if our window is valid
if(g_main_window){
if(!DestroyWindow(g_main_window)){
//We failed to destroy our window, this shouldn''t ever happen
MessageBox(NULL,"Destroy Window Failed",g_app_name,MB_OK|MB_ICONERROR|MB_TOPMOST);
}else{
MSG msg;
//Clean up any pending messages
while(PeekMessage(&msg, NULL, 0, 0,PM_REMOVE)){
DispatchMessage(&msg);
}
}
//Set our window handle to NULL just to be safe
g_main_window=NULL;
}
//Unregister our window, if we had opened multiple windows using this
//class, we would have to close all of them before we unregistered the class.
if(!UnregisterClass("DH Class",g_instance)){
MessageBox(NULL,"Unregister Failed",g_app_name,MB_OK|MB_ICONERROR|MB_TOPMOST);
}
}
//Set up Direct3D and create the device
void init_d3d()
{
HRESULT hr;
D3DPRESENT_PARAMETERS d3dpp;
//Create Direct3D8, this is the first thing you have to do in any D3D8 program
//Always pass D3D_SDK_VERSION to the function.
g_D3D = Direct3DCreate8( D3D_SDK_VERSION );
if(!g_D3D ){
FatalError("Direct3DCreate8():Error creating Direct3D.");
}
//Clear out our D3DPRESENT_PARAMETERS structure. Even though we''re going
//to set virtually all of its members, it''s good practice to zero it out first.
ZeroMemory(&d3dpp,sizeof(d3dpp));
//Whether we''re full-screen or windowed these are the same.
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // Throw away previous frames, we don''t need them
d3dpp.hDeviceWindow = g_main_window; //This is our main (and only) window
d3dpp.BackBufferCount= 1; //We only need a single back buffer
//BackBufferWidth/Height have to be set for full-screen apps, these values are
//used (along with BackBufferFormat) to determine the display mode.
//They aren''t needed in windowed mode since the size of the window will be used.
//BackBufferFormat is the pixel format we want.
d3dpp.Windowed = FALSE;
d3dpp.BackBufferWidth = g_width;
d3dpp.BackBufferHeight = g_height;
//In full-screen we need to find a pixel format we like, see find_16bit_mode()
//below for more details.
d3dpp.BackBufferFormat = find_16bit_mode();
//After filling in our D3DPRESENT_PARAMETERS structure, we''re ready to create our device.
//Most of the options in how the device is created are set in the D3DPRESENT_PARAMETERS
//structure.
hr=g_D3D->CreateDevice(D3DADAPTER_DEFAULT, //The default adapter, on a multimonitor system
//there can be more than one.
//Use hardware acceleration rather than the software renderer
D3DDEVTYPE_HAL,
//Our Window
g_main_window,
//Process vertices in software. This is slower than in hardware,
//But will work on all graphics cards.
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
//Our D3DPRESENT_PARAMETERS structure, so it knows what we want to build
&d3dpp,
//This will be set to point to the new device
&g_d3d_device);
if(FAILED(hr)){
FatalError(hr,"CreateDevice():Error creating device");
}
}
//Kill D3D
void kill_d3d(){
if(g_d3d_device){
g_d3d_device->Release();
g_d3d_device=NULL;
}
if(g_D3D){
g_D3D->Release();
g_D3D=NULL;
}
}
//Initialize scene
void init_scene()
{
HRESULT hr;
BYTE* Ptr;
hr = g_d3d_device-> CreateVertexBuffer ( 4 * sizeof( my_vertex ),
D3DUSAGE_WRITEONLY,
VERTEXFVF,
D3DPOOL_MANAGED,
&g_VB );
D3DXCreateTextureFromFile( g_d3d_device, "Texture.bmp", &g_Texture );
hr = g_VB->Lock( 0, 0, &Ptr, 0 );
memcpy( Ptr, g_Square, sizeof( g_Square ) );
}
//Kill scene
void kill_scene()
{
if ( g_VB )
{
g_VB -> Release();
g_VB = NULL;
}
if ( g_Texture )
{
g_Texture-> Release();
g_Texture = NULL;
}
}
//Find 16bit mode
D3DFORMAT find_16bit_mode()
{
HRESULT hr;
//CheckDeviceType() is used to verify that a Device can support a particular display mode.
//First we test for R5G6B5. All 16-bits are used in this format giving us a full 64K worth
//worth of colours
hr=g_D3D->CheckDeviceType(D3DADAPTER_DEFAULT, //Test the primary display device, this is
//necessary because systems can have add-on cards
//or multi-monitor setups
D3DDEVTYPE_HAL, //This states that we want support for this mode
//in hardware rather than emulated in software
D3DFMT_R5G6B5, //The is the primary (viewable) buffer format
D3DFMT_R5G6B5, //This is the back (drawable) buffer format
FALSE); //Is this windowed mode? Nope
if(SUCCEEDED(hr)){
return D3DFMT_R5G6B5;
}
//Next try X1R5G5B5. Since 1 bit is wasted it''s technically a 15-bit mode and only
//provides 32K colours, though you''d be hard pressed to tell the difference between
//15- & 16-bit modes.
hr=g_D3D->CheckDeviceType(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,D3DFMT_X1R5G5B5,D3DFMT_X1R5G5B5,FALSE);
if(SUCCEEDED(hr)){
return D3DFMT_X1R5G5B5;
}
//This is a freaky card. Complain and bail out.
FatalError(hr,"find_16bit_mode():Couldn''t find a decent 16-bit mode");
//Won''t actually hit this line since FatalError() kills us, but it makes the compiler happy.
return (D3DFORMAT)NULL;
}
//Render the scene
void render()
{
g_d3d_device->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
if(SUCCEEDED(g_d3d_device->BeginScene()))
{
g_d3d_device-> SetVertexShader( VERTEXFVF );
g_d3d_device-> SetStreamSource( 0, g_VB, sizeof( my_vertex ) );
g_d3d_device-> SetTexture( 0, g_Texture );
g_d3d_device-> DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );
g_d3d_device-> SetTexture( 0, NULL );
g_d3d_device-> EndScene();
g_d3d_device-> Present( NULL, NULL, NULL, NULL );
}
}
//FatalError Closes down all the stuff and notifies user
void FatalError(const char *p_error_msg)
{
kill_scene();
kill_d3d();
kill_window();
//Write our error message out to the debugger (if it''s active)
OutputDebugString( p_error_msg );
OutputDebugString("\n");
MessageBox(NULL, p_error_msg,g_app_name, MB_OK );
exit(5);
}
//Another FatalError
void FatalError(HRESULT p_hr,const char *p_error_msg)
{
char buffer[255];
D3DXGetErrorStringA(p_hr,buffer,250);
strcat(buffer,"\n");
strcat(buffer,p_error_msg);
kill_scene();
kill_d3d();
kill_window();
//Write our error message out to the debugger (if it''s active)
OutputDebugString( buffer );
OutputDebugString("\n");
MessageBox(NULL, buffer,g_app_name, MB_OK );
exit(5);
}
//Windows message handler
LRESULT CALLBACK default_window_proc(HWND p_hwnd,UINT p_msg,WPARAM p_wparam,LPARAM p_lparam)
{
switch(p_msg)
{
case WM_KEYDOWN: // A key has been pressed, end the app
case WM_CLOSE: //User hit the Close Window button, end the app
case WM_LBUTTONDOWN: //user hit the left mouse button
g_app_done=true;
return 0;
case WM_DESTROY: //This window is being destroyed, tell Windows we''re quitting
PostQuitMessage(0);
return 0;
}
return (DefWindowProc(p_hwnd,p_msg,p_wparam,p_lparam));
}