//***************************************************************************
//**
//** Alias25 (C) 2000
//**
//** File: CDX8GRAPHICS.CPP
//**
//** Date: 25/11/2000
//**
//** Author: Pierre Renaux
//**
//** Desc: DirectX8 Graphics Wrapper Functions
//**
//***************************************************************************
//===========================================================================
//    IMPLEMENTATION HEADERS
//===========================================================================
#include "CDX8Graphics.h"
  //===========================================================================
//    IMPLEMENTATION PRIVATE DEFINITIONS / ENUMERATIONS / SIMPLE TYPEDEFS
//===========================================================================
#ifndef __AGAMELIB_H__
 #include <stdio.h>
 #include <stdarg.h>
   static void write_error(char *str, ...)
 {
  va_list ap;
  char buf[1024];
    va_start(ap, str);
  vsprintf((char*)buf, (char*)str, ap);
  va_end(ap);
    OutputDebugString(buf);
 }
#endif
  //===========================================================================
//    IMPLEMENTATION PRIVATE CLASS PROTOTYPES / EXTERNAL CLASS REFERENCES
//===========================================================================
//===========================================================================
//    IMPLEMENTATION PRIVATE STRUCTURES / UTILITY CLASSES
//===========================================================================
// Structure used to represent an adpater
typedef struct DX8GRAPHIC_ADAPTER
{
 // Gfx Modes
 U32             num_mode;
 D3DDISPLAYMODE *modes;
 // Identifier structure
 D3DADAPTER_IDENTIFIER8 id;
 // Device Caps
 D3DCAPS8        caps;
} DX8GRAPHIC_ADAPTER;
  //===========================================================================
//    IMPLEMENTATION REQUIRED EXTERNAL REFERENCES (AVOID)
//===========================================================================
/* Game Library reference */
#ifdef __AGAMELIB_H__
extern "C"
{
 extern HWND agl_wnd;
 extern int wnd_windowed;
 extern BOOL wnd_paint_back;
}
#endif
  //===========================================================================
//    IMPLEMENTATION PRIVATE FUNCTION PROTOTYPES
//===========================================================================
//===========================================================================
//    IMPLEMENTATION PRIVATE DATA
//===========================================================================
//===========================================================================
//    IMPLEMENTATION PRIVATE FUNCTIONS
//===========================================================================
//===========================================================================
//    INTERFACE DATA
//===========================================================================
//===========================================================================
//    INTERFACE FUNCTIONS
//===========================================================================
//===========================================================================
//    INTERFACE CLASS BODIES
//===========================================================================
//---------------------------------------------------------------------------
// Name: CDX8Graphics::CDX8Graphics()
// Desc: Constructor, load the D3D8.DLL file.
//---------------------------------------------------------------------------
CDX8Graphics::CDX8Graphics(HWND wnd)
{
 Initialise(wnd);
}
  //---------------------------------------------------------------------------
// Name: CDX8Graphics::CDX8Graphics()
// Desc: Constructor which allow you to specify directly a gfx mode to
//       initialise and the window to use.
//---------------------------------------------------------------------------
CDX8Graphics::CDX8Graphics(HWND wnd, U32 adapter, int w, int h, D3DFORMAT pixformat, U32 behavior)
{
 Initialise(wnd);
 if(AllOk())
 {
  mp_all_ok = Gfx(adapter, w, h, pixformat, behavior);
 }
}
  //---------------------------------------------------------------------------
// Name: CDX8Graphics::CDX8Graphics()
// Desc: Constructor which allow you to specify directly a gfx mode to
//       initialise.
//---------------------------------------------------------------------------
CDX8Graphics::CDX8Graphics(U32 adapter, int w, int h, D3DFORMAT pixformat, U32 behavior)
{
 Initialise();
 if(AllOk())
 {
  mp_all_ok = Gfx(adapter, w, h, pixformat, behavior);
 }
}
  //---------------------------------------------------------------------------
// Name: CDX8Graphics::~CDX8Graphics()
// Desc: Destructor, destroy all created objects, devices and unload the DLL.
//---------------------------------------------------------------------------
CDX8Graphics::~CDX8Graphics()
{
 Uninitialise();
}
  //---------------------------------------------------------------------------
// Name: CDX8Graphics::Initialise()
// Desc: Initialise the class.
//---------------------------------------------------------------------------
void CDX8Graphics::Initialise(HWND wnd)
{
 // Set the default values of all members
 mp_all_ok = FALSE;
 
 mpUpdateInfo();
   mp_d3d_obj = NULL;
 mp_d3d_dev = NULL;
   mp_num_adapter = 0;
 mp_adapters = NULL;
   // Load the D3D8 Dll
 mp_d3d8_dll = LoadLibrary("D3D8.DLL");
 if(!mp_d3d8_dll)
 {
  write_error("CDX8Graphics::Initialise() - Unable to load D3D8.DLL !");
  return;
 }
   // Get the needed address functions
 mpDirect3DCreate8 = (LPDIRECT3D8(WINAPI*)(UINT))GetProcAddress(mp_d3d8_dll, "Direct3DCreate8");
 if(!mpDirect3DCreate8)
 {
  write_error("CDX8Graphics::Initialise() - Unable to get the Direct3DCreate8 procedure address !");
  return;
 }
   // Create the Direct3D object
 mp_d3d_obj = mpDirect3DCreate8(D3D_SDK_VERSION);
 if(!mp_d3d_obj)
 {
  write_error("CDX8Graphics::Initialise() - Unable to create the IDirect3D8 object !");
  return;
 }
   // Enumerate hardware
 if(!mpEnumerateHardware())
 {
  write_error("CDX8Graphics::Initialise() - Unable to enumerate hardware !");
  return;
 }
   // Set the current HWND to use
#ifdef __AGAMELIB_H__
 mp_wnd = wnd ? wnd : agl_wnd;
#else
 if(!wnd)
 {
  write_error("CDX8Graphics::Initialise() - No Window passed to the initialiser !");
  return;
 }
 mp_wnd = wnd;
#endif
   // All is ok so put the state variable at TRUE.
 mp_all_ok = TRUE;
}
  
//---------------------------------------------------------------------------
// Name: CDX8Graphics::Uninitialise()
// Desc: Initialise the class.
//---------------------------------------------------------------------------
void CDX8Graphics::Uninitialise()
{
 // Free the adpater list
 if(mp_adapters)
 {
  for(U32 i = 0; i < mp_num_adapter; i++)
  {
   if(mp_adapters[i].modes)
   {
    delete mp_adapters[i].modes;
	mp_adapters[i].modes = NULL;
   }
  }
  delete mp_adapters;
 }
   // Free the D3D device
 if(mp_d3d_dev)
 {
  mp_d3d_dev->Release();
  mp_d3d_dev = NULL;
 }
   // Free the D3D object
 if(mp_d3d_obj)
 {
  mp_d3d_obj->Release();
  mp_d3d_obj = NULL;
 }
 
 // Free the DLL
 if(mp_d3d8_dll)
 {
  FreeLibrary(mp_d3d8_dll);
  mp_d3d8_dll = NULL;
  mpDirect3DCreate8 = NULL;
 }
   // Set the window ptr to NULL
 mp_wnd = NULL;
   // All is not yet ok ;)
 mp_all_ok = FALSE;
}
  //---------------------------------------------------------------------------
// Name: CDX8Graphics::Gfx(U32 adapter, int w, int h, D3DFORMAT pixformat)
// Desc: Setup the gfx mode.
//---------------------------------------------------------------------------
BOOL CDX8Graphics::Gfx(U32 adapter, int w, int h, D3DFORMAT pixformat, U32 behavior)
{
 if(!AdapterCapsWindowed(adapter))
  pixformat = mpDesktopMode();
   if(pixformat == D3DFMT_UNKNOWN)
 {
  return mpWindowedInit(adapter, w, h, behavior); 
 }
 
 return mpFullScreenInit(adapter, w, h, pixformat, behavior);
}
  //---------------------------------------------------------------------------
// Name: CDX8Graphics::Switch()
// Desc: Switch between fullscreen and windowed mode.s
//---------------------------------------------------------------------------
BOOL CDX8Graphics::Switch(BOOL fullscreen)
{
 if(!AdapterCapsWindowed(mp_current_adapter))
  return FALSE;
   if(fullscreen == 2)
  fullscreen = mp_fullscreen ? FALSE : TRUE;
   if(fullscreen)
  return Gfx(mp_current_adapter, mp_w, mp_h, mp_pixformat);
 else
  return Gfx(mp_current_adapter, mp_w, mp_h);
}
  //---------------------------------------------------------------------------
// Name: CDX8Graphics::NumAdapter()
// Desc: Return the number of D3D adapter. 
//---------------------------------------------------------------------------
U32 CDX8Graphics::NumAdapter()
{
 return mp_num_adapter;
}
  //---------------------------------------------------------------------------
// Name: CDX8Graphics::AdapterInfo() 
// Desc: Return informations about an adapter.
//---------------------------------------------------------------------------
BOOL CDX8Graphics::AdapterInfo(U32 i, D3DCAPS8 *caps, char *name, char *desc)
{
 if(i >= mp_num_adapter)
  return FALSE;
   if(name)
  strncpy(name, mp_adapters[i].id.Driver, MAX_DEVICE_IDENTIFIER_STRING);
 if(desc)
  strncpy(desc, mp_adapters[i].id.Description, MAX_DEVICE_IDENTIFIER_STRING);
 if(caps)
  memcpy(caps, &mp_adapters[i].caps, sizeof(D3DCAPS8));
   return TRUE;
}
  //---------------------------------------------------------------------------
// Name: CDX8Graphics::AdapterNumMode()
// Desc: Return the number of gfx mode of an adpater.
//---------------------------------------------------------------------------
U32 CDX8Graphics::AdapterNumMode(U32 i)
{
 if(i >= mp_num_adapter)
  return 0;
   return mp_adapters[i].num_mode;
}
  //---------------------------------------------------------------------------
// Name: CDX8Graphics::AdapterMode()
// Desc: Enumerate a gfx mode of an adapter.
//---------------------------------------------------------------------------
BOOL CDX8Graphics::AdapterMode(U32 i, U32 imode, int *w, int *h, D3DFORMAT *format)
{
 if(i >= mp_num_adapter)
  goto error;
   if(imode >= mp_adapters[i].num_mode)
  goto error;
   if(w) *w = mp_adapters[i].modes[imode].Width;
 if(h) *h = mp_adapters[i].modes[imode].Height;
 if(format) *format = mp_adapters[i].modes[imode].Format;
   return TRUE;
  error:;
 if(w) *w = 0;
 if(h) *h = 0;
 if(format) *format = D3DFMT_UNKNOWN;
 return FALSE;
}
  //---------------------------------------------------------------------------
// Name: CDX8Graphics::AdapterCapsWindowed()
// Desc: Return TRUE if the specifed adapter can render in windowed
//       mode.
//---------------------------------------------------------------------------
BOOL CDX8Graphics::AdapterCapsWindowed(U32 i)
{ 
 D3DCAPS8 caps;
   if(AdapterInfo(i, &caps))
 {
  if((caps.Caps2 & D3DCAPS2_CANRENDERWINDOWED) == D3DCAPS2_CANRENDERWINDOWED)
   return TRUE;
 }
   return FALSE;
}
  //---------------------------------------------------------------------------
// Name: CDX8Graphics::mpEnumerateHardware()
// Desc: Enumerate present harware.
//---------------------------------------------------------------------------
BOOL CDX8Graphics::mpEnumerateHardware()
{
 U32 i, j, num_hal;
   if(!mp_d3d_obj)
  return FALSE;
   // Get the number of adpaters
 mp_num_adapter = mp_d3d_obj->GetAdapterCount();
 if(mp_num_adapter < 1)
 {
  write_error("CDX8Graphics::mpEnumerateHardware() - No adapter detected !");
  return FALSE;
 }
   // Alloc the adapters array
 mp_adapters = new DX8GRAPHIC_ADAPTER[mp_num_adapter];
 if(!mp_adapters)
 {
  write_error("CDX8Graphics::mpEnumerateHardware() - Unable to alloc mp_adapters !");
  return FALSE;
 }
   // Gets Adapter identifier and gfx modes
 for(i = 0, num_hal = 0; i < mp_num_adapter; i++)
 {
  if(FAILED(mp_d3d_obj->GetAdapterIdentifier(i, D3DENUM_NO_WHQL_LEVEL, &mp_adapters[num_hal].id)))
  {
   write_error("CDX8Graphics::mpEnumerateHardware() - Unable to adapter identifier [%d] !", i);
   return FALSE;
  }
    if(FAILED(mp_d3d_obj->GetDeviceCaps(i, D3DDEVTYPE_HAL, &mp_adapters[num_hal].caps)))
  {
   write_error("CDX8Graphics::mpEnumerateHardware() - Unable to get HAL caps of an adapter [%d] !", i);
   continue;
  }
    mp_adapters[num_hal].num_mode = mp_d3d_obj->GetAdapterModeCount(i);
  mp_adapters[num_hal].modes = new D3DDISPLAYMODE[mp_adapters[num_hal].num_mode];
  if(!mp_adapters[num_hal].modes)
  {
   write_error("CDX8Graphics::mpEnumerateHardware() - Unable to alloc mp_adapters[%d].modes !", i);
   return FALSE;
  }
    for(j = 0; j < mp_adapters[num_hal].num_mode; j++)
  {
   mp_d3d_obj->EnumAdapterModes(i, j, &mp_adapters[num_hal].modes[j]);
  }
    num_hal++;
 }
   if(num_hal < 1)
 {
  write_error("CDX8Graphics::mpEnumerateHardware() - No HAL device detected !", i);
  return FALSE;
 }
   return TRUE;
}
  //---------------------------------------------------------------------------
// Name: CDX8Graphics::mpDesktopMode()
// Desc: Return the Dektop gfx mode.
//---------------------------------------------------------------------------
D3DFORMAT CDX8Graphics::mpDesktopMode(int *w, int *h)
{
 D3DDISPLAYMODE dm;  // Used to get the current gfx mode.
 // First, get the desktop display mode
 if(FAILED(mp_d3d_obj->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &dm)))
 {
  write_error("CDX8Graphics::mpDesktopMode() - Unable to get the current display mode !");
  return D3DFMT_UNKNOWN;
 }
   if(w) *w = dm.Width;
 if(h) *h = dm.Height;
   return dm.Format;
}
  //---------------------------------------------------------------------------
// Name: CDX8Graphics::mpCheckUpBeforeGfxInitialisation()
// Desc: Reset all variables that need to be, before a gfx mode
//       initialisation.
//---------------------------------------------------------------------------
void CDX8Graphics::mpCheckUpBeforeGfxInitialisation()
{
 // Free the D3D device
 if(mp_d3d_dev)
 {
  mp_d3d_dev->Release();
  mp_d3d_dev = NULL;
 }
   // Reset the info vars.
 mpUpdateInfo();
}
  //---------------------------------------------------------------------------
// Name: CDX8Graphics::mpWindowedStyle()
// Desc: Change the style and the size of the window to use a windowed gfx
//       mode.
//---------------------------------------------------------------------------
void CDX8Graphics::mpWindowedStyle(int w, int h)
{
 RECT r;
 int style;
  #ifdef __AGAMELIB_H__
 wnd_paint_back = 0;
 wnd_windowed = 1;
#endif
   style = GetWindowLong(mp_wnd, GWL_STYLE);
 style &= ~(WS_BORDER | WS_SIZEBOX);
 style |= WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU; 
 SetWindowLong(mp_wnd, GWL_STYLE, style);
   SetRect(&r, 0, 0, w, h);
 AdjustWindowRectEx(&r,
	                GetWindowLong(mp_wnd,GWL_STYLE),
					GetMenu(mp_wnd) != NULL,
					GetWindowLong(mp_wnd,GWL_EXSTYLE));
   SetWindowPos(mp_wnd, HWND_NOTOPMOST,
			  (GetSystemMetrics(SM_CXSCREEN)-w)/2,
			  (GetSystemMetrics(SM_CYSCREEN)-h)/2,
			  r.right-r.left, r.bottom-r.top, 0);
}
  //---------------------------------------------------------------------------
// Name: CDX8Graphics::mpFullScreenStyle()
// Desc: Change the style and the size of the window to use a fullscreen gfx
//       mode.
//---------------------------------------------------------------------------
void CDX8Graphics::mpFullScreenStyle(int w, int h)
{
 RECT r;
 int style;
  #ifdef __AGAMELIB_H__
 wnd_paint_back = 0;
 wnd_windowed = 0;
#endif
   style = GetWindowLong(mp_wnd, GWL_STYLE);
 style &= ~(WS_BORDER | WS_MINIMIZEBOX | WS_SYSMENU | WS_SIZEBOX | WS_CAPTION);
 SetWindowLong(mp_wnd, GWL_STYLE, style);
   SetRect(&r, 0, 0, w, h);
 AdjustWindowRectEx(&r,
	                GetWindowLong(mp_wnd,GWL_STYLE),
					GetMenu(mp_wnd) != NULL,
					GetWindowLong(mp_wnd,GWL_EXSTYLE));
   SetWindowPos(mp_wnd, HWND_NOTOPMOST,
			  (GetSystemMetrics(SM_CXSCREEN)-w)/2,
			  (GetSystemMetrics(SM_CYSCREEN)-h)/2,
			  r.right-r.left, r.bottom-r.top, 0);
  }
  //---------------------------------------------------------------------------
// Name: CDX8Graphics::mpWindowedInit()
// Desc: Initialise a windowed gfx mode. Return FALSE if failed,
//       otherwise TRUE.
//---------------------------------------------------------------------------
BOOL CDX8Graphics::mpWindowedInit(U32 adapter, int w, int h, U32 behavior)
{
 D3DFORMAT pixformat;
 D3DPRESENT_PARAMETERS pp;  // Used to create the D3D device.
 mpCheckUpBeforeGfxInitialisation();
   // Change the window size and style to match with the requested mode
 mpWindowedStyle(w, h);
   // Get the Desktop color format
 pixformat = mpDesktopMode();
   // Initialise the pp structure
 ZeroMemory(&pp, sizeof(D3DPRESENT_PARAMETERS));
 pp.Windowed = TRUE;                    // Use windowed mode
 pp.SwapEffect = D3DSWAPEFFECT_DISCARD; // Use DISCARD swapping method
 pp.BackBufferFormat = pixformat;       // Use the same pixel format as the
                                        // current display mode.
 // Now create the D3D device with the same value as in the DX8Doc tutorial.
 // Will be modified !
 if(FAILED(mp_d3d_obj->CreateDevice(adapter, D3DDEVTYPE_HAL, mp_wnd,
                                    behavior,
                                    &pp, &mp_d3d_dev)))
 {
  write_error("CDX8Graphics::mpWindowedInit() - Unable to create the D3D device !");
  return FALSE;
 }
   // Finally update the gfx mode informations
 mpUpdateInfo(adapter, w, h, pixformat, FALSE);
   return TRUE;
}
  //---------------------------------------------------------------------------
// Name: CDX8Graphics::mpFullScreenInit()
// Desc: Initialise a fullscreen gfx mode. Return FALSE if failed,
//       otherwise TRUE.
//---------------------------------------------------------------------------
BOOL CDX8Graphics::mpFullScreenInit(U32 adapter, int w, int h, D3DFORMAT pixformat, U32 behavior)
{
 D3DPRESENT_PARAMETERS pp;  // Used to create the D3D device.
 mpCheckUpBeforeGfxInitialisation();
   // Change the window size and style to match with the requested mode
 mpFullScreenStyle(w, h);
   // Initialise the pp structure
 ZeroMemory(&pp, sizeof(D3DPRESENT_PARAMETERS));
 pp.Windowed = FALSE;                   // Use fullscreen mode
 pp.SwapEffect = D3DSWAPEFFECT_DISCARD; // Use DISCARD swapping method
 pp.BackBufferWidth = w;
 pp.BackBufferHeight = h;
 pp.BackBufferFormat = pixformat;       // Use the same pixel format as the
                                        // current display mode.
 // Now create the D3D device with the same value as in the DX8Doc tutorial.
 // Will be modified !
 if(FAILED(mp_d3d_obj->CreateDevice(adapter, D3DDEVTYPE_HAL, mp_wnd,
                                    behavior,
                                    &pp, &mp_d3d_dev)))
 {
  write_error("CDX8Graphics::mpWindowedInit() - Unable to create the D3D device !");
  return FALSE;
 }
   // Finally update the gfx mode informations
 mpUpdateInfo(adapter, w, h, pixformat, TRUE);
   return TRUE;
}
  //---------------------------------------------------------------------------
// Name: CDX8Graphics::mpUpdateInfo()
// Desc: Update the info variables.
//---------------------------------------------------------------------------
void CDX8Graphics::mpUpdateInfo(U32 adapter, int w, int h, D3DFORMAT pixformat, BOOL fullscreen)
{
 mp_current_adapter = adapter;
 mp_w = w;
 mp_h = h;
 mp_pixformat = pixformat;
 mp_fullscreen = fullscreen;
}
  //***************************************************************************
//**
//**    END MODULE CDX8GRAPHICS.CPP
//**
//***************************************************************************
   |