Direct3D Lesson 1:Your First DirectX Window
// These are all the includes we need.  One for the basic Windows stuff
// (which we will use as rarely as possible, I'm not a fan of the Win32
// API) and one for Direct3D 8.
#define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers
#include <windows.h>
#include <D3DX8.h>

// This is causes the d3d8.lib to be linked in, the same thing can be accomplished by
// adding it to your compiler's link list (Project->Settings->Link in VC++),
// but I prefer this method.
#pragma comment(lib,"d3d8.lib")
#pragma comment(lib,"d3dx8.lib")

// Forward declarations for all of our functions, see their definitions for more detail
void FatalError(const char *error_msg);
void FatalError(HRESULT hr,const char *error_msg);
void ask_fullscreen(void);
LRESULT CALLBACK default_window_proc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam);
void init_window(void);
void kill_window(void);
void init_d3d(void);
void kill_d3d(void);
void init_scene(void);
void kill_scene(void);
void message_pump(void);
D3DFORMAT find_16bit_mode(void);
void render(void);
void NOP(HINSTANCE p_prev_instance,LPSTR p_cmd_line,int p_show);

// The name of our application.  Used for window titles, MessageBox titles and
// error reporting
const char g_app_name[]="DirectX 8 Tutorial 1";

// Our screen/window sizes.  A better app would allow the user to choose the
// sizes.  I'll do that in a later tutorial, for now this is good enough.
const int g_width=640;
const int g_height=480;

// A global flag to determine if we're windowed (false) or full-screen(true)
bool g_fullscreen=true;

// A global handle to our main window, initializing pointers to NULL can save you
// a lot of hassle in the future.
HWND g_main_window=NULL;

// A global handle to our 'instance'.  This is needed in various places by the Windows API.
HINSTANCE g_instance;

// Our global flag to track whether we should quit or not.  When it becomes true, we clean
// up and exit.
bool g_app_done=false;

// Our main Direct3D interface, it doesn't do much on it's own, but all the more commonly
// used interfaces are created by it.  It's the first D3D object you create, and the last
// one you release.

// The D3DDevice is your main rendering interface.  It represents the display and all of its
// capabilities.  When you create, modify, or render any type of resource, you will likely
// do it through this interface.
IDirect3DDevice8 *g_d3d_device=NULL;

// WinMain is the first function called by Windows when our app is run.  It's the entry
// point of our application.
int APIENTRY WinMain(HINSTANCE p_instance,HINSTANCE p_prev_instance,LPSTR p_cmd_line,int p_show){

   // Set our global instance handle so we don't have to pass it around

   //This function exists to quiet compiler warnings, see its definition for more detail

   // Prompt the user, Full Screen?  Windowed?  Cancel?

   // Build our window.  Cover the screen if full-screen, otherwise make a standard window

   //Build the D3D objects we'll require

   //One-time preparation of objects and other stuff required for rendering

   //Loop until the user aborts (closes the window or hits a key)
      message_pump();   //Check for window messages

      render();   //Draw our incredibly cool graphics

   //Free all of our objects and other resources

   //Clean up all of our Direct3D objects

   //Close down our window

   //Exit happily
   return 0;

// Procedure: NOP
// Whazzit:This procedure does nothing.  If set to a high warning level
//         (which I like to do) the compiler will complain because the
//         parameters passed into WinMain are never used.  The purpose
//         of this procedure is to make it think that they are used, so
//         it doesn't complain.  
void NOP(HINSTANCE p_prev_instance,LPSTR p_cmd_line,int p_show){


// Procedure: message_pump
// Whazzit:Checks the message queue to see if any windows messages
//         (window is closing, window needs repainting, etc)
//         are waiting and if there are, the messages are dispatched
//         to our message handler.
void message_pump(void){
MSG msg;

   if(PeekMessage(&msg, NULL, 0, 0,PM_REMOVE)){


// Function:init_d3d
// Whazzit:Sets up Direct3D and creates the device.  The device is create differently
//         if we're full-screen as opposed to running in a desktop window.
void init_d3d(void){
D3DDISPLAYMODE display_mode;

   //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("Error getting Direct3D");

   //Get the current(desktop) display mode.  This is really only needed if
   //we're running in a window.
      FatalError(hr,"Error getting display mode\n");

   //Clear out our D3DPRESENT_PARAMETERS structure.  Even though we're going
   //to set virtually all of it members, it's good practice to zero it out first.

   //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.  In windowed mode we use the same
   //format as the desktop (which we found by using GetAdapterDisplayMode() above).
   //In full-screen we need to find a pixel format we like, see find_16bit_mode()
   //below for more details.
      d3dpp.Windowed          = FALSE;
      d3dpp.BackBufferWidth   = g_width;
      d3dpp.BackBufferHeight  = g_height;
      d3dpp.BackBufferFormat  = find_16bit_mode();
      d3dpp.Windowed          = TRUE;
      d3dpp.BackBufferFormat  = display_mode.Format;

   //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
   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
                          //Our Window
                          //Process vertices in software. This is slower than in hardware,
                          //But will work on all graphics cards.
                          //Our D3DPRESENT_PARAMETERS structure, so it knows what we want to build
                          //This will be set to point to the new device
      FatalError(hr,"Error creating device\n");

// Function:kill_d3d
// Whazzit:Releases all of our D3D resources in the opposite order from their creation.
//         Note-Since we initially set the pointers to be NULL, we can safely test them
//         for a non-NULL state and we know if they've been created.  Thus we never Release
//         something we didn't create (which causes bad things to happen).
void kill_d3d(void){



// Function:init_scene
// Whazzit:Prepare any objects required for rendering.  In this tutorial we have nothing to do here.
void init_scene(void){

// Function:kill_scene
// Whazzit:Clean up any objects we required for rendering.  In this tutorial we have nothing to do here.
void kill_scene(void){

// Function:find_16bit_mode
// Whazzit:Tests a couple of 16-bit modes to see if they are supported.  Virtually every graphics
//         card in existance will support one of these 2 formats.
D3DFORMAT find_16bit_mode(void){

   //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
      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.
      return D3DFMT_X1R5G5B5;

   //This is a freaky card.  Complain and bail out.
   FatalError("Couldn't find a decent mode\n");

   //Won't actually hit this line since FatalError() kills us, but it makes the compiler happy.
   return (D3DFORMAT)NULL;
// Function:ask_fullscreen
// Whazzit:Ask the user if they would like to run in full-screen or windowed mode or if they
//         would like to Cancel (abort).
void ask_fullscreen(void){
int full_result;

   full_result=MessageBox(NULL,"Would you like to run in fullscreen mode?",g_app_name,
      case IDCANCEL: //User hit 'Cancel' button, so we quit
         MessageBox(NULL,"User Abort",g_app_name,MB_OK);
      case IDNO:     //User hit 'No' button, run in a window
      case IDYES:    //User hit 'Yes' button, run full-screen
      case 0:        //Error!  Couldn't open dialog box
         OutputDebugString("Couldn't open MessageBox, dying");

// Function: render
// Whazzit:Clears the screen to a pseudo-random colour and then presents the results.
//         If we were doing any real drawing, it would go in this function between
//         the BeginScene() & EndScene().
void render(void){
static unsigned char red=0,green=0,blue=0;

   //These will safely overflow when the values go over 255, wrapping back to 0.

   //Clear the buffer to our new colour.
   g_d3d_device->Clear(0,  //Number of rectangles to clear, we're clearing everything so set it to 0
                       NULL, //Pointer to the rectangles to clear, NULL to clear whole display
                       D3DCLEAR_TARGET,   //What to clear.  We don't have a Z Buffer or Stencil Buffer
                       D3DCOLOR_XRGB(red,green,blue), //Colour to clear to
                       1.0f,  //Value to clear ZBuffer to, doesn't matter since we don't have one
                       0 );   //Stencil clear value, again, we don't have one, this value doesn't matter

   //Notify the device that we're ready to render

      //Put cool stuff here

      //Notify the device that we're finished rendering for this frame

   //Show the results
   g_d3d_device->Present(NULL,  //Source rectangle to display, NULL for all of it
                         NULL,  //Destination rectangle, NULL to fill whole display
                         NULL,  //Target window, if NULL uses device window set in CreateDevice
                         NULL );//Unused parameter, set it to NULL

// Function: init_window
// Whazzit:Registers a window class and then creates our window.
void init_window(void){
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.          = 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
      FatalError("Error registering window class");

   //If we're 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.
      //In windowed mode, we just make the window whatever size we need.

   g_main_window=CreateWindow("DH Class",g_app_name,style,

      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

// Function: kill_window
// Whazzit:Closes the window, clean up any waiting messages, and then unregister 
//         our window class.  Note - This is not the standard Win32 way of cleaning
//         up your window.  The standard way involves putting the clean-up code in
//         your window handler, I don't like that method.
void kill_window(void){

   //Test if our window is valid
         //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);
         MSG msg;
         //Clean up any pending messages
         while(PeekMessage(&msg, NULL, 0, 0,PM_REMOVE)){
      //Set our window handle to NULL just to be safe

   //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);

// Function:FatalError
// Whazzit:Close down all resources, alert the user and quit
void FatalError(const char *error_msg){




   //Write our error message out to the debugger (if it's active)
	OutputDebugString( error_msg );
	MessageBox(NULL, error_msg,g_app_name, MB_OK );


// Function:FatalError
// Whazzit:Close down all resources, alert the user and quit
void FatalError(HRESULT hr,const char *error_msg){
char buffer[255];






   //Write our error message out to the debugger (if it's active)
	OutputDebugString( buffer );
	MessageBox(NULL, buffer,g_app_name, MB_OK );


// Function:default_window_proc
// Whazzit:All Windows messages get passed through this function.  We only handle
//         a tiny subset of the available messages, all unhandled messages get
//         passed through to DefWindowProc() which is part of the Win32 API.
LRESULT CALLBACK default_window_proc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam){
      case WM_KEYDOWN:  // A key has been pressed, end the app
         return 0;
      case WM_CLOSE:    //User hit the Close Window button, end the app
         return 0;
      case WM_DESTROY:  //This window is being destroyed, tell Windows we're quitting
         return 0;

   return (DefWindowProc(hwnd,msg,wparam,lparam));