Skip to content

Instantly share code, notes, and snippets.

@aliakseis
Created June 26, 2022 11:38
Show Gist options
  • Save aliakseis/482017335ee3d5942ca0af11b0f4cd71 to your computer and use it in GitHub Desktop.
Save aliakseis/482017335ee3d5942ca0af11b0f4cd71 to your computer and use it in GitHub Desktop.
///////////////////////////////////////////////////////////////////////////////////
// //
// Blitz 2D //
// //
// Code to make easy use of DirectX / GDI+ to draw 2D graphics //
// //
// By Sean O'Connor 2010 //
// //
// Thanks to: //
// Wendy Jones - for the book "Beginning DirectX 9" //
// Eamonn Doherty - for how to rotate a DirectX image //
// Simon O'Connor - for how to load DLLs at run time //
// JGuntherS@NL - for how to try loading each D3DX9_nn.dll in turn //
// Steve Macpherson - invaluable advice //
// //
///////////////////////////////////////////////////////////////////////////////////
// TODO:
// Free surfaces during running
// Draw triangles
// Draw arrows
// includes
#include "stdafx.h"
#include "Blitz2D.h"
#include <d3d9.h> // DirectX
#include <d3dx9.h>
#include <gdiplus.h> // GDI+
using namespace Gdiplus;
// constants
const DWORD D3DFVF_CUSTOMVERTEX = D3DFVF_XYZRHW | D3DFVF_TEX1 | D3DFVF_DIFFUSE;
#define RADIANS 57.295779513f // used in cos() and sin() to convert degrees to radians
#define HANDLES_START_AT BACK_BUFFER // first image/surface/font handle is this number - just so that if you use an uninitialized handle (which will be zero in debug) the error will be caught
#define B2D_MIN(a,b) (((a) < (b)) ? (a) : (b)) // macros for minimum and maximum
#define B2D_MAX(a,b) (((a) > (b)) ? (a) : (b))
#ifdef _DEBUG // used for debugging but ignored if in Release mode
#define ALERT(a, b) MessageBox(NULL, a, b, MB_OK | MB_ICONEXCLAMATION);
#else
#define ALERT(a, b)
#endif
#define MAX_FONT_FACENAME_LENGTH 64
// D3DX9 functions (the D3DX_nn.dll is loaded at run time as some computers won't have it installed, in that case we can use GDI+ instead)
typedef HRESULT (WINAPI *PD3DXCreateTextureFromFile)(LPDIRECT3DDEVICE9,
LPCTSTR,
LPDIRECT3DTEXTURE9 *);
typedef HRESULT (WINAPI *PD3DXCreateTextureFromFileEx)(
LPDIRECT3DDEVICE9 pDevice,
LPCTSTR pSrcFile,
UINT Width,
UINT Height,
UINT MipLevels,
DWORD Usage,
D3DFORMAT Format,
D3DPOOL Pool,
DWORD Filter,
DWORD MipFilter,
D3DCOLOR ColorKey,
D3DXIMAGE_INFO *pSrcInfo,
PALETTEENTRY *pPalette,
LPDIRECT3DTEXTURE9 *ppTexture);
typedef HRESULT (WINAPI *PD3DXCreateFont)(LPDIRECT3DDEVICE9 pDevice,
INT Height,
UINT Width,
UINT Weight,
UINT MipLevels,
BOOL Italic,
DWORD CharSet,
DWORD OutputPrecision,
DWORD Quality,
DWORD PitchAndFamily,
LPCTSTR pFacename,
LPD3DXFONT * ppFont);
typedef HRESULT (WINAPI *PD3DXCreateTexture)(LPDIRECT3DDEVICE9 pDevice,
UINT Width,
UINT Height,
UINT MipLevels,
DWORD Usage,
D3DFORMAT Format,
D3DPOOL Pool,
LPDIRECT3DTEXTURE9 *ppTexture);
typedef HRESULT (WINAPI *PD3DXCreateLine)(LPDIRECT3DDEVICE9 pDevice,
LPD3DXLINE* ppLine);
PD3DXCreateTextureFromFile pFunc_D3DXCreateTextureFromFile;
PD3DXCreateFont pFunc_PD3DXCreateFont;
PD3DXCreateLine pFunc_PD3DXCreateLine;
PD3DXCreateTexture pFunc_PD3DXCreateTexture;
// structs
struct CUSTOMVERTEX
{
float x, y, z;
float rhw;
D3DCOLOR color;
float u, v;
};
struct IMAGE
{
LPDIRECT3DTEXTURE9 pImageDX; // DirectX version
Bitmap* pImageGDIP; // GDI+ version
HBITMAP pImageGDI; // GDI version (used if it's a BMP and 100% opacity is specified)
int iTextureWidth, iTextureHeight; // used by DirectX as textures have dimensions of 2,4,8,16,32... etc...
int iActualWidth, iActualHeight;
};
struct SURFACE
{
// pointer to data
LPDIRECT3DTEXTURE9 pSurfaceDX; // DirectX version
HBITMAP pGraphicsGDIP; // GDI+ version
// dimensions
int iWidth, iHeight;
// pen attributes
int iRed, iGreen, iBlue;
int iOpacity;
int iBackgroundRed, iBackgroundGreen, iBackgroundBlue;
int iBackgroundOpacity;
BOOL bAntiAlias;
int hFontHandleSelected;
};
struct FONT
{
LPD3DXFONT pFontDX; // DirectX version
Font* pFontGDIP; // GDI+ version
// dimensions
unsigned int iHeight; // remember the font height so the program can query this later if it wants to
unsigned int iWidth; // remember the rest in case the font's size is changed and it needs to be re-created
unsigned int iWeight;
unsigned int iMipLevels;
BOOL bItalic;
DWORD dwCharSet;
DWORD dwOutputPrecision;
DWORD dwQuality;
DWORD dwPitchAndFamily;
char szFacename[MAX_FONT_FACENAME_LENGTH];
};
// global variables
BOOL bBlitz2DStarted = FALSE; // used to check if Blitz2D has been started so illegal calls can't be made
int iMode; // which mode is selected, DirectX or GDI+
HWND hWindow = NULL; // handle to the window (for drawing MessageBoxes in Debug mode)
RECT rClient = {0,0,0,0}; // client window area size
int iFatalError = -1; // the version number of D3DX9_nn.dll that is found
// DirectX variables
HMODULE hModuleD3D9 = NULL; // handle of D3D9.dll
HMODULE hModuleD3DX9 = NULL; // handle of D3DX9.dll
LPDIRECT3D9 pD3D = NULL; // the Direct3D object
LPDIRECT3DDEVICE9 pd3dDevice = NULL; // the Direct3D device
IDirect3DSurface9* backBufferTarget = NULL; // back buffer
LPDIRECT3DVERTEXBUFFER9 vertexBuffer = NULL; // vertex buffer
int hImageHandleSelectedDX = -1; // used in case the same image is drawn several times so it doesn't need to be reseleted
BOOL m_bDeviceLost = FALSE;
// GDI+ variables
ULONG_PTR m_gdiplusToken; // GDI+ token
HDC hdcWindow = NULL; // HDC to the screen
HDC hdcSurface = NULL; // HDC to the currently selected surface
HDC hdcFrom = NULL; // HDC to BLT images from
HBITMAP hSurfaceBitmapOld = NULL;
// images
int iNumberOfImagesLoaded = 0;
IMAGE* pListOfImages = NULL;
// offscreen surfaces
int iNumberOfOffscreenSurfacesCreated = 0; // NB the first offscren surface (surface '0') is the back buffer so at least one is always created
SURFACE* pListOfOffscreenSurfaces = NULL;
int hCurrentSurfaceHandleSelected = 0; // 0 means none, -1 means the back buffer, >=HANDLES_START_AT is an offscreen surface handle
// fonts
int iNumberOfFontsCreated = 0;
FONT* pListOfFonts = NULL;
// functions that can't be called by the user
BOOL B2D_FinishedDrawing();
// DirectX functions
BOOL DX_Start(HWND hWnd);
void DX_Stop();
BOOL DX_Resize(HWND hWnd);
BOOL DX_CreateOffscreenSurface(int i, int iWidth, int iHeight);
BOOL DX_CreateFontEx(int i, unsigned int iHeight, unsigned int iWidth, unsigned int iWeight, unsigned int iMipLevels, BOOL bItalic, DWORD dwCharSet, DWORD dwOutputPrecision, DWORD dwQuality, DWORD dwPitchAndFamily, char* szFacename);
void DX_ChangeFontHeight(int hFontHandle, int iHeight);
void DX_DeleteFont(int hFontHandle);
BOOL DX_LoadImage(int i, char* szFilename, int iWidth, int iHeight);
BOOL DX_DeleteImage(int hImageHandle);
BOOL DX_StartDrawingTo(int hSurfaceHandle);
BOOL DX_FinishedDrawing();
BOOL DX_Present();
BOOL DX_ClearRect(RECT_F* pRect, int iRed, int iGreen, int iBlue, float fOpacity);
BOOL DX_BltSurfaceStretched(int hSurfaceHandle, RECT_F* pSrc, RECT_F* pDest);
BOOL DX_DrawImage(int hImageHandle, float x, float y, float fSizeX, float fSizeY, float fRotate, float fOpacity, float fFromX, float fFromY, float fToX, float fToY);
BOOL DX_DrawLine(float fFromX, float fFromY, float fToX, float fToY, float fWidth, int iRed, int iGreen, int iBlue, int iOpacity);
BOOL DX_DrawTextEx(char* szString, float x, float y, RECT_F* pRect, int iAlignment, int iRed, int iGreen, int iBlue, int iOpacity);
BOOL _SetNewRenderTarget(int hSurfaceHandle);
// GDIPlus functions
BOOL GDIP_Start(HWND hWnd);
void GDIP_Stop();
BOOL GDIP_Resize(HWND hWnd);
BOOL GDIP_CreateOffscreenSurface(int i, int iWidth, int iHeight);
BOOL GDIP_CreateFontEx(int i, unsigned int iHeight, unsigned int iWidth, unsigned int iWeight, unsigned int iMipLevels, BOOL bItalic, DWORD dwCharSet, DWORD dwOutputPrecision, DWORD dwQuality, DWORD dwPitchAndFamily, char* szFacename);
void GDIP_ChangeFontHeight(int hFontHandle, int iHeight);
void GDIP_DeleteFont(int hFontHandle);
BOOL GDIP_LoadImage(int i, char* szFilename, int iWidth, int iHeight);
BOOL GDIP_DeleteImage(int hImageHandle);
BOOL GDIP_StartDrawingTo(int hSurfaceHandle);
BOOL GDIP_FinishedDrawing();
BOOL GDIP_Present();
BOOL GDIP_ClearRect(RECT_F* pRect, int iRed, int iGreen, int iBlue, float fOpacity);
BOOL GDIP_BltSurfaceStretched(int hSurfaceHandle, RECT_F* pSrc, RECT_F* pDest);
BOOL GDIP_DrawImage(int hImageHandle, float x, float y, float fSizeX, float fSizeY, float fRotate, float fOpacity, float fFromX, float fFromY, float fToX, float fToY);
BOOL GDIP_DrawLine(float fFromX, float fFromY, float fToX, float fToY, float fWidth, int iRed, int iGreen, int iBlue, int iOpacity);
BOOL GDIP_DrawTextEx(char* szString, float x, float y, RECT_F* pRect, int iAlignment, int iRed, int iGreen, int iBlue, int iOpacity);
// local functions
void _ResetSurfaceAttributesToDefaults(int hSurfaceHandle);
int _GetSurfaceArrayIndexFromHandle(int hSurfaceHandle);
BOOL _CheckValidSurfaceHandle(int hSurfaceHandle, const char* szFunction); // return TRUE if hSurfaceHandle is between HANDLES_START_AT and HANDLES_START_AT + iNumberOffscreenSurfaces
BOOL _CheckDrawingHasStarted(const char* szFunctionName);
BOOL _CheckBlitz2DHasStarted(const char* szFunctionName);
///////////////////////////////////////////////////////////
// //
// Blitz 2D //
// //
///////////////////////////////////////////////////////////
BOOL B2D_Start(HWND hWnd, int iForceMode)
{
// check a valid windows handle has been sent
if (hWnd == NULL)
{
MessageBox(NULL, "hWnd is NULL!", "B2D_Start", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
// has Blitz2D already started?
if (bBlitz2DStarted == TRUE)
{
return FALSE;
}
bBlitz2DStarted = TRUE;
// initialize variables
hWindow = hWnd;
iNumberOfImagesLoaded = 0;
pListOfImages = NULL;
iNumberOfOffscreenSurfacesCreated = 0;
pListOfOffscreenSurfaces = NULL;
iNumberOfFontsCreated = 0;
pListOfFonts = NULL;
hCurrentSurfaceHandleSelected = 0;
GetClientRect(hWnd, &rClient);
// start GDI+ so even if DirectX is used GDI+ can be used in say dialog boxes
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
// try using DirectX?
if (iForceMode == B2D_MODE_ANY
|| iForceMode == B2D_MODE_DIRECTX)
{
// assume DirectX will start
iMode = B2D_MODE_DIRECTX;
// try starting it
if (DX_Start(hWnd) == TRUE)
{
// succeeded with DirectX 9
return TRUE;
}
else
{
// failed, so free anything that DX_Start created
DX_Stop();
}
}
// try using GDI+?
if (iForceMode == B2D_MODE_ANY
|| iForceMode == B2D_MODE_GDIPLUS)
{
// assume GDI+ will start
iMode = B2D_MODE_GDIPLUS;
// try starting it
if (GDIP_Start(hWnd) == TRUE)
{
// succeeded with GDI+
return TRUE;
}
else
{
// failed, so free anything that GDIP_Start created
GDIP_Stop();
}
}
// failed to start
bBlitz2DStarted = FALSE;
iMode = B2D_MODE_UNSPECIFIED;
return FALSE;
}
void B2D_Stop()
{
// has Blitz2D actually been started?
if (_CheckBlitz2DHasStarted("B2D_Stop") == FALSE)
{
return;
}
// stop drawing
switch (iMode)
{
case B2D_MODE_DIRECTX:
DX_Stop();
break;
case B2D_MODE_GDIPLUS:
GDIP_Stop();
break;
}
// stop GDI+ (even if Blitz2D was used in DirectX mode, GDI+ was started so it could be used in say dialog boxes)
Gdiplus::GdiplusShutdown(m_gdiplusToken);
// flag that Blitz2D has stopped now
bBlitz2DStarted = FALSE;
}
int B2D_GetMode()
{
return iMode;
}
int B2D_GetFatalError()
{
return iFatalError;
}
BOOL B2D_Resize(HWND hWnd)
{
// resize
switch (iMode)
{
case B2D_MODE_DIRECTX:
return DX_Resize(hWnd);
case B2D_MODE_GDIPLUS:
return GDIP_Resize(hWnd);
}
// no such mode
return FALSE;
}
int B2D_CreateOffscreenSurface(int iWidth, int iHeight)
{
int iNewSurfaceHandle;
int i;
// check that drawing has been started
if (_CheckBlitz2DHasStarted("B2D_LoadImage") == FALSE)
{
return -1;
}
// allocate more space for this surface's data
pListOfOffscreenSurfaces = (SURFACE*)realloc(pListOfOffscreenSurfaces, sizeof(SURFACE) * (iNumberOfOffscreenSurfacesCreated+1));
// check memory was allocated
if (pListOfOffscreenSurfaces == NULL)
{
ALERT("Memory not allocated", "B2D_CreateOffscreenSurface");
return -1;
}
// calculate this surface's handle and the array index
iNewSurfaceHandle = iNumberOfOffscreenSurfacesCreated + HANDLES_START_AT;
i = iNumberOfOffscreenSurfacesCreated;
// increment number of surfaces created counter
iNumberOfOffscreenSurfacesCreated ++;
// initialize variables
pListOfOffscreenSurfaces[i].pSurfaceDX = NULL;
pListOfOffscreenSurfaces[i].pGraphicsGDIP = NULL;
// create the offscreen surface
BOOL bResult;
switch (iMode)
{
case B2D_MODE_DIRECTX:
bResult = DX_CreateOffscreenSurface(i, iWidth, iHeight);
break;
case B2D_MODE_GDIPLUS:
bResult = GDIP_CreateOffscreenSurface(i, iWidth, iHeight);
break;
}
// was the surface created OK?
if (bResult == FALSE)
{
return -1;
}
// set data
pListOfOffscreenSurfaces[i].iWidth = iWidth;
pListOfOffscreenSurfaces[i].iHeight = iHeight;
_ResetSurfaceAttributesToDefaults(iNewSurfaceHandle);
// successful
return iNewSurfaceHandle;
}
int B2D_CreateFont(unsigned int iHeight, unsigned int iWeight, BOOL bItalic, char* szFacename)
{
return B2D_CreateFontEx(iHeight,
0,
iWeight,
0,
bItalic,
DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS,
DEFAULT_QUALITY,
DEFAULT_PITCH | FF_DONTCARE,
szFacename);
}
int B2D_CreateFontEx(unsigned int iHeight, unsigned int iWidth, unsigned int iWeight, unsigned int iMipLevels, BOOL bItalic, DWORD dwCharSet, DWORD dwOutputPrecision, DWORD dwQuality, DWORD dwPitchAndFamily, char* szFacename)
{
int iNewFontHandle;
int i;
// check that drawing has been started
if (_CheckBlitz2DHasStarted("B2D_LoadImage") == FALSE)
{
return -1;
}
// allocate more space for this font's data
pListOfFonts = (FONT*)realloc(pListOfFonts, sizeof(FONT) * (iNumberOfFontsCreated+1));
// check memory was allocated
if (pListOfFonts == NULL)
{
ALERT("Memory not allocated", "B2D_CreateFontEx");
return -1;
}
// calculate this font's handle and the array index
iNewFontHandle = iNumberOfFontsCreated + HANDLES_START_AT;
i = iNumberOfFontsCreated;
// increment number of fonts created counter
iNumberOfFontsCreated ++;
pListOfFonts[i].pFontDX = NULL;
pListOfFonts[i].pFontGDIP = NULL;
// create the font
BOOL bResult;
switch (iMode)
{
case B2D_MODE_DIRECTX:
bResult = DX_CreateFontEx(i, iHeight, iWidth, iWeight, iMipLevels, bItalic, dwCharSet, dwOutputPrecision, dwQuality, dwPitchAndFamily, szFacename);
break;
case B2D_MODE_GDIPLUS:
bResult = GDIP_CreateFontEx(i, iHeight, iWidth, iWeight, iMipLevels, bItalic, dwCharSet, dwOutputPrecision, dwQuality, dwPitchAndFamily, szFacename);
break;
}
// was the font created OK?
if (bResult == FALSE)
{
return -1;
}
// remember the attributes
pListOfFonts[i].iHeight = iHeight; // remember the rest in case the font's size is changed and it needs to be re-created
pListOfFonts[i].iWidth = iWidth;
pListOfFonts[i].iWeight = iWeight;
pListOfFonts[i].iMipLevels = iMipLevels;
pListOfFonts[i].bItalic = bItalic;
pListOfFonts[i].dwCharSet = dwCharSet;
pListOfFonts[i].dwOutputPrecision = dwOutputPrecision;
pListOfFonts[i].dwQuality = dwQuality;
pListOfFonts[i].dwPitchAndFamily = dwPitchAndFamily;
strcpy(pListOfFonts[i].szFacename, szFacename);
// return the new font handle
return iNewFontHandle;
}
BOOL B2D_ChangeFontHeight(int hFontHandle, unsigned int iHeight)
{
// check that drawing has been started
if (_CheckBlitz2DHasStarted("B2D_ChangeFontHeight") == FALSE)
{
return FALSE;
}
// check that a valid font handle was sent
if (hFontHandle < HANDLES_START_AT
|| hFontHandle >= HANDLES_START_AT + iNumberOfFontsCreated)
{
ALERT("Invalid image handle", "B2D_DeleteFont");
return FALSE;
}
// delete font
switch (iMode)
{
case B2D_MODE_DIRECTX:
DX_ChangeFontHeight(hFontHandle, iHeight);
break;
case B2D_MODE_GDIPLUS:
GDIP_ChangeFontHeight(hFontHandle, iHeight);
break;
}
return TRUE;
}
BOOL B2D_DeleteFont(int hFontHandle)
{
// check that drawing has been started
if (_CheckBlitz2DHasStarted("B2D_DeleteFont") == FALSE)
{
return FALSE;
}
// was this font ever created?
if (hFontHandle <= 0)
{
// no, so just return sucess
return TRUE;
}
// check that a valid font handle was sent
if (hFontHandle < HANDLES_START_AT
|| hFontHandle >= HANDLES_START_AT + iNumberOfFontsCreated)
{
ALERT("Invalid image handle", "B2D_DeleteFont");
return FALSE;
}
// delete the font
switch (iMode)
{
case B2D_MODE_DIRECTX:
DX_DeleteFont(hFontHandle);
break;
case B2D_MODE_GDIPLUS:
GDIP_DeleteFont(hFontHandle);
break;
}
// sucess
return TRUE;
}
int B2D_LoadImage(char* szFilename, int iWidth, int iHeight)
{
int iNewImageHandle;
int i;
// check that drawing has been started
if (_CheckBlitz2DHasStarted("B2D_LoadImage") == FALSE)
{
return FALSE;
}
// allocate more space for this image's data
pListOfImages = (IMAGE*)realloc(pListOfImages, sizeof(IMAGE) * (iNumberOfImagesLoaded+1));
// check memory was allocated
if (pListOfImages == NULL)
{
ALERT("Memory not allocated", "B2D_LoadImage");
return -1;
}
// calculate this image's handle and the array index
iNewImageHandle = iNumberOfImagesLoaded + HANDLES_START_AT;
i = iNumberOfImagesLoaded;
// increment number of images loaded counter
iNumberOfImagesLoaded ++;
// initialize variables
pListOfImages[i].pImageDX = NULL;
pListOfImages[i].pImageGDIP = NULL;
pListOfImages[i].pImageGDI = NULL;
// load the image
BOOL bResult;
switch (iMode)
{
case B2D_MODE_DIRECTX:
bResult = DX_LoadImage(i, szFilename, iWidth, iHeight);
break;
case B2D_MODE_GDIPLUS:
bResult = GDIP_LoadImage(i, szFilename, iWidth, iHeight);
break;
}
// was image loaded OK?
if (bResult == FALSE)
{
return -1;
}
// successfully loaded
return iNewImageHandle;
}
BOOL B2D_DeleteImage(int hImageHandle)
{
// check that drawing has been started
if (_CheckBlitz2DHasStarted("B2D_DeleteImage") == FALSE)
{
return FALSE;
}
// was this image ever loaded?
if (hImageHandle <= 0)
{
// no, so just return success
return TRUE;
}
// check that a valid image handle was sent
if (hImageHandle < HANDLES_START_AT
|| hImageHandle >= HANDLES_START_AT + iNumberOfImagesLoaded)
{
ALERT("Invalid image handle", "B2D_DeleteImage");
return FALSE;
}
// delete the image
switch (iMode)
{
case B2D_MODE_DIRECTX:
return DX_DeleteImage(hImageHandle);
case B2D_MODE_GDIPLUS:
return GDIP_DeleteImage(hImageHandle);
}
// should never get here
return FALSE;
}
int B2D_ChangeImage(int hImageHandle, char* szFilename, int iWidth, int iHeight)
{
int i;
// if hImageHandle == NULL then a previous image hasn't been loaded
if (hImageHandle <= 0)
{
return B2D_LoadImage(szFilename, iWidth, iHeight);
}
else
{
// check for valid image handle
if (hImageHandle < HANDLES_START_AT
|| hImageHandle >= iNumberOfImagesLoaded + HANDLES_START_AT)
{
ALERT("Invalid image handle", "B2D_ChangeImage");
return -1;
}
// delete current image
B2D_DeleteImage(hImageHandle);
// initialize variables
i = hImageHandle - HANDLES_START_AT;
pListOfImages[i].pImageDX = NULL;
pListOfImages[i].pImageGDIP = NULL;
pListOfImages[i].pImageGDI = NULL;
// load the image
BOOL bResult;
switch (iMode)
{
case B2D_MODE_DIRECTX:
bResult = DX_LoadImage(i, szFilename, iWidth, iHeight);
break;
case B2D_MODE_GDIPLUS:
bResult = GDIP_LoadImage(i, szFilename, iWidth, iHeight);
break;
}
if (bResult == TRUE)
{
return hImageHandle;
}
else
{
return -1;
}
}
}
BOOL B2D_StartDrawingTo(int hSurfaceHandle)
{
// is another surface currently selected?
if (hCurrentSurfaceHandleSelected != 0)
{
// yes, so finish drawing to that one
B2D_FinishedDrawing();
}
// check that a valid surface handle was sent
if (hSurfaceHandle < HANDLES_START_AT
|| hSurfaceHandle >= HANDLES_START_AT + iNumberOfOffscreenSurfacesCreated)
{
ALERT("Invalid surface handle", "B2D_StartDrawingTo");
return FALSE;
}
// reset pen colours etc... for this surface
_ResetSurfaceAttributesToDefaults(hSurfaceHandle);
// start drawing
BOOL bResult;
switch (iMode)
{
case B2D_MODE_DIRECTX:
bResult = DX_StartDrawingTo(hSurfaceHandle);
break;
case B2D_MODE_GDIPLUS:
bResult = GDIP_StartDrawingTo(hSurfaceHandle);
break;
}
if (bResult == FALSE)
{
return -1;
}
// success
return TRUE;
}
BOOL B2D_FinishedDrawing()
{
switch (iMode)
{
case B2D_MODE_DIRECTX:
return DX_FinishedDrawing();
case B2D_MODE_GDIPLUS:
return GDIP_FinishedDrawing();
}
// no such mode
return FALSE;
}
BOOL B2D_Present()
{
// has drawing actually been started?
if (hCurrentSurfaceHandleSelected == 0)
{
// no, so just return
return TRUE;
}
else
{
// yes, so finish drawing to that surface
B2D_FinishedDrawing();
}
// present the back buffer
switch (iMode)
{
case B2D_MODE_DIRECTX:
return DX_Present();
case B2D_MODE_GDIPLUS:
return GDIP_Present();
}
// no such mode
return FALSE;
}
BOOL B2D_Clear(int iRed, int iGreen, int iBlue, float fOpacity)
{
// check that drawing has been started
if (_CheckDrawingHasStarted("B2D_ClearRect") == FALSE)
{
return FALSE;
}
// clear the whole surface
switch (iMode)
{
case B2D_MODE_DIRECTX:
return DX_ClearRect(NULL, iRed, iGreen, iBlue, fOpacity);
case B2D_MODE_GDIPLUS:
return GDIP_ClearRect(NULL, iRed, iGreen, iBlue, fOpacity);
}
// no such mode
return FALSE;
}
BOOL B2D_ClearRect(RECT_F* pRect, int iRed, int iGreen, int iBlue, float fOpacity)
{
// check that drawing has been started
if (_CheckDrawingHasStarted("B2D_ClearRect") == FALSE)
{
return FALSE;
}
// clear the rect
switch (iMode)
{
case B2D_MODE_DIRECTX:
return DX_ClearRect(pRect, iRed, iGreen, iBlue, fOpacity);
case B2D_MODE_GDIPLUS:
return GDIP_ClearRect(pRect, iRed, iGreen, iBlue, fOpacity);
}
// no such mode
return FALSE;
}
BOOL B2D_BltSurface(int hSurfaceHandle, float x, float y)
{
RECT_F rSource;
RECT_F rDestination;
int i;
// check that drawing has been started
if (_CheckDrawingHasStarted("B2D_BltSurface") == FALSE)
{
return FALSE;
}
// get index of this surface handle
i = _GetSurfaceArrayIndexFromHandle(hSurfaceHandle);
// calculate coordinates
rSource.left = 0;
rSource.right = (float)pListOfOffscreenSurfaces[i].iWidth;
rSource.top = 0;
rSource.bottom = (float)pListOfOffscreenSurfaces[i].iHeight;
rDestination.left = x;
rDestination.right = x + (float)pListOfOffscreenSurfaces[i].iWidth;
rDestination.top = y;
rDestination.bottom = y + (float)pListOfOffscreenSurfaces[i].iHeight;
// drawing to a minimized window
if (rDestination.right == 0)
{
return TRUE;
}
// BLT the surface
switch (iMode)
{
case B2D_MODE_DIRECTX:
return DX_BltSurfaceStretched(hSurfaceHandle, &rSource, &rDestination);
case B2D_MODE_GDIPLUS:
return GDIP_BltSurfaceStretched(hSurfaceHandle, &rSource, &rDestination);
}
// no such mode
return FALSE;
}
BOOL B2D_BltSurfaceStretched(int hSurfaceHandle, RECT_F* pSrc, RECT_F* pDest)
{
// check that drawing has been started
if (_CheckDrawingHasStarted("B2D_BltSurfaceStretched") == FALSE)
{
return FALSE;
}
// drawing to a minimized window
if (pDest->right == 0)
{
return TRUE;
}
// do the strtech BLT
switch (iMode)
{
case B2D_MODE_DIRECTX:
return DX_BltSurfaceStretched(hSurfaceHandle, pSrc, pDest);
case B2D_MODE_GDIPLUS:
return GDIP_BltSurfaceStretched(hSurfaceHandle, pSrc, pDest);
}
// no such mode
return FALSE;
}
BOOL B2D_DrawImage(int hImageHandle, float x, float y, float fRotate, float fOpacity)
{
// check that drawing has been started
if (_CheckDrawingHasStarted("B2D_DrawImage") == FALSE)
{
return FALSE;
}
// draw the image
switch (iMode)
{
case B2D_MODE_DIRECTX:
return DX_DrawImage(hImageHandle, x, y, -1, -1, fRotate, fOpacity, 0, 0, 1.0, 1.0);
case B2D_MODE_GDIPLUS:
return GDIP_DrawImage(hImageHandle, x, y, -1, -1, fRotate, fOpacity, 0, 0, 1.0, 1.0);
}
// no such mode
return FALSE;
}
BOOL B2D_DrawImageCenteredAt(int hImageHandle, float x, float y, float fRotate, float fOpacity)
{
int i;
// check that drawing has been started
if (_CheckDrawingHasStarted("B2D_DrawImageCenteredAt") == FALSE)
{
return FALSE;
}
// get the index of this image handle
i = hImageHandle - HANDLES_START_AT;
// draw the image
if (i >= 0)
{
switch (iMode)
{
case B2D_MODE_DIRECTX:
return DX_DrawImage(hImageHandle,
x - pListOfImages[i].iActualWidth/2,
y - pListOfImages[i].iActualHeight/2,
-1, -1,
fRotate,
fOpacity,
0, 0, 1.0, 1.0);
case B2D_MODE_GDIPLUS:
return GDIP_DrawImage(hImageHandle,
x - pListOfImages[i].iActualWidth/2,
y - pListOfImages[i].iActualHeight/2,
-1, -1,
fRotate,
fOpacity,
0, 0, 1.0, 1.0);
}
}
// no such mode
return FALSE;
}
BOOL B2D_DrawImageStretchedAtlas(int hImageHandle, float x, float y, float fSizeX, float fSizeY, float fRotate, float fOpacity, float fFromX, float fFromY, float fFromSizeX, float fFromSizeY)
{
int i;
float fToX, fToY;
// check that drawing has been started
if (_CheckDrawingHasStarted("B2D_DrawImage") == FALSE)
{
return FALSE;
}
// get the index of this image handle
i = hImageHandle - HANDLES_START_AT;
if (i >= 0)
{
// work out frame position
fToX = (fFromX + fFromSizeX) / pListOfImages[i].iActualWidth;
fToY = (fFromY + fFromSizeY) / pListOfImages[i].iActualHeight;
fFromX = fFromX / pListOfImages[i].iActualWidth;
fFromY = fFromY / pListOfImages[i].iActualHeight;
// draw the image
switch (iMode)
{
case B2D_MODE_DIRECTX:
return DX_DrawImage(hImageHandle,
x, y,
fSizeX, fSizeY,
fRotate,
fOpacity,
fFromX, fFromY,
fToX, fToY);
case B2D_MODE_GDIPLUS:
return GDIP_DrawImage(hImageHandle,
x, y,
fSizeX, fSizeY,
fRotate,
fOpacity,
fFromX, fFromY,
fToX, fToY);
}
}
// no such mode
return FALSE;
}
BOOL B2D_DrawImageFrame(int hImageHandle, float x, float y, float fRotate, float fOpacity, int iFrameX, int iFrameY, int iFrameSizeX, int iFrameSizeY)
{
int i;
float fFromX, fFromY;
float fToX, fToY;
float fSizeX, fSizeY;
// check that drawing has been started
if (_CheckDrawingHasStarted("B2D_DrawImage") == FALSE)
{
return FALSE;
}
// get the index of this image handle
i = hImageHandle - HANDLES_START_AT;
if (i >= 0)
{
// work out frame position
fFromX = (float)(iFrameX) * iFrameSizeX / pListOfImages[i].iActualWidth;
fFromY = (float)(iFrameY) * iFrameSizeY / pListOfImages[i].iActualHeight;
fToX = (float)((iFrameX+1) * iFrameSizeX - 1) / pListOfImages[i].iActualWidth;
fToY = (float)((iFrameY+1) * iFrameSizeY - 1) / pListOfImages[i].iActualHeight;
// size
fSizeX = pListOfImages[i].iActualWidth * (fToX - fFromX);
fSizeY = pListOfImages[i].iActualHeight * (fToY - fFromY);
// draw the image
switch (iMode)
{
case B2D_MODE_DIRECTX:
return DX_DrawImage(hImageHandle,
x, y,
fSizeX, fSizeY,
fRotate,
fOpacity,
fFromX, fFromY,
fToX, fToY);
case B2D_MODE_GDIPLUS:
return GDIP_DrawImage(hImageHandle,
x, y,
fSizeX, fSizeY,
fRotate,
fOpacity,
fFromX, fFromY,
fToX, fToY);
}
}
// no such mode
return FALSE;
}
BOOL B2D_DrawImageFrameStretched(int hImageHandle, float x, float y, float fSizeX, float fSizeY, float fRotate, float fOpacity, int iFrameX, int iFrameY, int iFrameSizeX, int iFrameSizeY)
{
int i;
float fFromX, fFromY;
float fToX, fToY;
// check that drawing has been started
if (_CheckDrawingHasStarted("B2D_DrawImage") == FALSE)
{
return FALSE;
}
// get the index of this image handle
i = hImageHandle - HANDLES_START_AT;
if (i >= 0)
{
// work out frame position
fFromX = (float)(iFrameX) * iFrameSizeX / pListOfImages[i].iActualWidth;
fFromY = (float)(iFrameY) * iFrameSizeY / pListOfImages[i].iActualHeight;
fToX = (float)((iFrameX+1) * iFrameSizeX - 1) / pListOfImages[i].iActualWidth;
fToY = (float)((iFrameY+1) * iFrameSizeY - 1) / pListOfImages[i].iActualHeight;
// draw the image
switch (iMode)
{
case B2D_MODE_DIRECTX:
return DX_DrawImage(hImageHandle,
x, y,
fSizeX, fSizeY,
fRotate,
fOpacity,
fFromX, fFromY,
fToX, fToY);
case B2D_MODE_GDIPLUS:
return GDIP_DrawImage(hImageHandle,
x, y,
fSizeX, fSizeY,
fRotate,
fOpacity,
fFromX, fFromY,
fToX, fToY);
}
}
// no such mode
return FALSE;
}
BOOL B2D_DrawImageFrameCenteredAt(int hImageHandle, float x, float y, float fRotate, float fOpacity, int iFrameX, int iFrameY, int iFrameSizeX, int iFrameSizeY)
{
int i;
float fFromX, fFromY;
float fToX, fToY;
// check that drawing has been started
if (_CheckDrawingHasStarted("B2D_DrawImageCenteredAt") == FALSE)
{
return FALSE;
}
// get the index of this image handle
i = hImageHandle - HANDLES_START_AT;
// draw the image
if (i >= 0)
{
// work out frame position
fFromX = (float)(iFrameX) * iFrameSizeX / pListOfImages[i].iActualWidth;
fFromY = (float)(iFrameY) * iFrameSizeY / pListOfImages[i].iActualHeight;
fToX = (float)((iFrameX+1) * iFrameSizeX - 1) / pListOfImages[i].iActualWidth;
fToY = (float)((iFrameY+1) * iFrameSizeY - 1) / pListOfImages[i].iActualHeight;
// draw the image
switch (iMode)
{
case B2D_MODE_DIRECTX:
return DX_DrawImage(hImageHandle,
x - iFrameSizeX/2,
y - iFrameSizeY/2,
-1, -1,
fRotate,
fOpacity,
fFromX, fFromY, fToX, fToY);
case B2D_MODE_GDIPLUS:
return GDIP_DrawImage(hImageHandle,
x - iFrameSizeX/2,
y - iFrameSizeY/2,
-1, -1,
fRotate,
fOpacity,
fFromX, fFromY, fToX, fToY);
}
}
// no such mode
return FALSE;
}
BOOL B2D_DrawImageStretched(int hImageHandle, float x, float y, float fSizeX, float fSizeY, float fRotate, float fOpacity)
{
int i;
// check that drawing has been started
if (_CheckDrawingHasStarted("B2D_DrawImageStretched") == FALSE)
{
return FALSE;
}
// get the index of this image handle
i = hImageHandle - HANDLES_START_AT;
// draw the image
if (i >= 0)
{
switch (iMode)
{
case B2D_MODE_DIRECTX:
return DX_DrawImage(hImageHandle,
x,
y,
fSizeX, fSizeY,
fRotate,
fOpacity,
0, 0, 1.0, 1.0); //, (fSizeX-1) / fSizeX, (fSizeY-1) / fSizeY);
case B2D_MODE_GDIPLUS:
return GDIP_DrawImage(hImageHandle,
x,
y,
fSizeX, fSizeY,
fRotate,
fOpacity,
0, 0, 1.0, 1.0);
}
}
// no such mode
return FALSE;
}
BOOL B2D_DrawLine(float fFromX, float fFromY, float fToX, float fToY, float fWidth)
{
int iCurrentSurface;
// check that drawing has been started
if (_CheckDrawingHasStarted("B2D_DrawLine") == FALSE)
{
return FALSE;
}
// get array index of currently selected surface
iCurrentSurface = _GetSurfaceArrayIndexFromHandle(hCurrentSurfaceHandleSelected);
// draw the line
switch (iMode)
{
case B2D_MODE_DIRECTX:
return DX_DrawLine(fFromX, fFromY,
fToX, fToY,
fWidth,
pListOfOffscreenSurfaces[iCurrentSurface].iRed,
pListOfOffscreenSurfaces[iCurrentSurface].iGreen,
pListOfOffscreenSurfaces[iCurrentSurface].iBlue,
pListOfOffscreenSurfaces[iCurrentSurface].iOpacity);
case B2D_MODE_GDIPLUS:
return GDIP_DrawLine(fFromX, fFromY,
fToX, fToY,
fWidth,
pListOfOffscreenSurfaces[iCurrentSurface].iRed,
pListOfOffscreenSurfaces[iCurrentSurface].iGreen,
pListOfOffscreenSurfaces[iCurrentSurface].iBlue,
pListOfOffscreenSurfaces[iCurrentSurface].iOpacity);
}
// no such mode
return FALSE;
}
BOOL B2D_DrawBox(float fLeft, float fTop, float fRight, float fBottom, float fWidth)
{
int iCurrentSurface;
// check that drawing has been started
if (_CheckDrawingHasStarted("B2D_DrawLine") == FALSE)
{
return FALSE;
}
// get array index of currently selected surface
iCurrentSurface = _GetSurfaceArrayIndexFromHandle(hCurrentSurfaceHandleSelected);
// draw the line
fRight --;
fBottom --;
switch (iMode)
{
case B2D_MODE_DIRECTX:
if (DX_DrawLine(fLeft, fTop, fRight, fTop, fWidth, pListOfOffscreenSurfaces[iCurrentSurface].iRed, pListOfOffscreenSurfaces[iCurrentSurface].iGreen, pListOfOffscreenSurfaces[iCurrentSurface].iBlue, pListOfOffscreenSurfaces[iCurrentSurface].iOpacity) == FALSE
|| DX_DrawLine(fRight, fTop, fRight, fBottom, fWidth, pListOfOffscreenSurfaces[iCurrentSurface].iRed, pListOfOffscreenSurfaces[iCurrentSurface].iGreen, pListOfOffscreenSurfaces[iCurrentSurface].iBlue, pListOfOffscreenSurfaces[iCurrentSurface].iOpacity) == FALSE
|| DX_DrawLine(fRight, fBottom, fLeft, fBottom, fWidth, pListOfOffscreenSurfaces[iCurrentSurface].iRed, pListOfOffscreenSurfaces[iCurrentSurface].iGreen, pListOfOffscreenSurfaces[iCurrentSurface].iBlue, pListOfOffscreenSurfaces[iCurrentSurface].iOpacity) == FALSE
|| DX_DrawLine(fLeft, fBottom, fLeft, fTop, fWidth, pListOfOffscreenSurfaces[iCurrentSurface].iRed, pListOfOffscreenSurfaces[iCurrentSurface].iGreen, pListOfOffscreenSurfaces[iCurrentSurface].iBlue, pListOfOffscreenSurfaces[iCurrentSurface].iOpacity) == FALSE)
{
return FALSE;
}
return TRUE;
case B2D_MODE_GDIPLUS:
if (GDIP_DrawLine(fLeft, fTop, fRight, fTop, fWidth, pListOfOffscreenSurfaces[iCurrentSurface].iRed, pListOfOffscreenSurfaces[iCurrentSurface].iGreen, pListOfOffscreenSurfaces[iCurrentSurface].iBlue, pListOfOffscreenSurfaces[iCurrentSurface].iOpacity) == FALSE
|| GDIP_DrawLine(fRight, fTop, fRight, fBottom, fWidth, pListOfOffscreenSurfaces[iCurrentSurface].iRed, pListOfOffscreenSurfaces[iCurrentSurface].iGreen, pListOfOffscreenSurfaces[iCurrentSurface].iBlue, pListOfOffscreenSurfaces[iCurrentSurface].iOpacity) == FALSE
|| GDIP_DrawLine(fRight, fBottom, fLeft, fBottom, fWidth, pListOfOffscreenSurfaces[iCurrentSurface].iRed, pListOfOffscreenSurfaces[iCurrentSurface].iGreen, pListOfOffscreenSurfaces[iCurrentSurface].iBlue, pListOfOffscreenSurfaces[iCurrentSurface].iOpacity) == FALSE
|| GDIP_DrawLine(fLeft, fBottom, fLeft, fTop, fWidth, pListOfOffscreenSurfaces[iCurrentSurface].iRed, pListOfOffscreenSurfaces[iCurrentSurface].iGreen, pListOfOffscreenSurfaces[iCurrentSurface].iBlue, pListOfOffscreenSurfaces[iCurrentSurface].iOpacity) == FALSE)
{
return FALSE;
}
return TRUE;
}
// no such mode
return FALSE;
}
BOOL B2D_DrawBox3D(float fLeft, float fTop, float fRight, float fBottom, float fWidth)
{
int iCurrentSurface;
// check that drawing has been started
if (_CheckDrawingHasStarted("B2D_DrawLine") == FALSE)
{
return FALSE;
}
// get array index of currently selected surface
iCurrentSurface = _GetSurfaceArrayIndexFromHandle(hCurrentSurfaceHandleSelected);
// draw the line
fRight --;
fBottom --;
switch (iMode)
{
case B2D_MODE_DIRECTX:
if (DX_DrawLine(fLeft, fTop, fRight, fTop, fWidth, pListOfOffscreenSurfaces[iCurrentSurface].iRed, pListOfOffscreenSurfaces[iCurrentSurface].iGreen, pListOfOffscreenSurfaces[iCurrentSurface].iBlue, pListOfOffscreenSurfaces[iCurrentSurface].iOpacity) == FALSE
|| DX_DrawLine(fRight, fTop, fRight, fBottom, fWidth, 0,0,0, pListOfOffscreenSurfaces[iCurrentSurface].iOpacity) == FALSE
|| DX_DrawLine(fRight, fBottom, fLeft, fBottom, fWidth, 0,0,0, pListOfOffscreenSurfaces[iCurrentSurface].iOpacity) == FALSE
|| DX_DrawLine(fLeft, fBottom, fLeft, fTop, fWidth, pListOfOffscreenSurfaces[iCurrentSurface].iRed, pListOfOffscreenSurfaces[iCurrentSurface].iGreen, pListOfOffscreenSurfaces[iCurrentSurface].iBlue, pListOfOffscreenSurfaces[iCurrentSurface].iOpacity) == FALSE)
{
return FALSE;
}
return TRUE;
case B2D_MODE_GDIPLUS:
if (GDIP_DrawLine(fLeft, fTop, fRight, fTop, fWidth, pListOfOffscreenSurfaces[iCurrentSurface].iRed, pListOfOffscreenSurfaces[iCurrentSurface].iGreen, pListOfOffscreenSurfaces[iCurrentSurface].iBlue, pListOfOffscreenSurfaces[iCurrentSurface].iOpacity) == FALSE
|| GDIP_DrawLine(fRight, fTop, fRight, fBottom, fWidth, 0,0,0, pListOfOffscreenSurfaces[iCurrentSurface].iOpacity) == FALSE
|| GDIP_DrawLine(fRight, fBottom, fLeft, fBottom, fWidth, 0,0,0, pListOfOffscreenSurfaces[iCurrentSurface].iOpacity) == FALSE
|| GDIP_DrawLine(fLeft, fBottom, fLeft, fTop, fWidth, pListOfOffscreenSurfaces[iCurrentSurface].iRed, pListOfOffscreenSurfaces[iCurrentSurface].iGreen, pListOfOffscreenSurfaces[iCurrentSurface].iBlue, pListOfOffscreenSurfaces[iCurrentSurface].iOpacity) == FALSE)
{
return FALSE;
}
return TRUE;
}
// no such mode
return FALSE;
}
BOOL B2D_DrawText(char* szString, float x, float y, int iAlignment)
{
int iCurrentSurface;
// check that drawing has been started
if (_CheckDrawingHasStarted("B2D_DrawText") == FALSE)
{
return FALSE;
}
// check there is some text to draw
if (szString == NULL
|| strlen(szString) == 0)
{
return TRUE;
}
// get array index of currently selected surface
iCurrentSurface = _GetSurfaceArrayIndexFromHandle(hCurrentSurfaceHandleSelected);
// draw text
switch (iMode)
{
case B2D_MODE_DIRECTX:
return DX_DrawTextEx(szString,
x, y,
NULL,
iAlignment,
pListOfOffscreenSurfaces[iCurrentSurface].iRed,
pListOfOffscreenSurfaces[iCurrentSurface].iGreen,
pListOfOffscreenSurfaces[iCurrentSurface].iBlue,
pListOfOffscreenSurfaces[iCurrentSurface].iOpacity);
case B2D_MODE_GDIPLUS:
return GDIP_DrawTextEx(szString,
x, y,
NULL,
iAlignment,
pListOfOffscreenSurfaces[iCurrentSurface].iRed,
pListOfOffscreenSurfaces[iCurrentSurface].iGreen,
pListOfOffscreenSurfaces[iCurrentSurface].iBlue,
pListOfOffscreenSurfaces[iCurrentSurface].iOpacity);
}
// no such mode
return FALSE;
}
BOOL B2D_DrawTextWithShadow(char* szString, float x, float y, int iAlignment, int iShadowX, int iShadowY)
{
int iCurrentSurface;
// check that drawing has been started
if (_CheckDrawingHasStarted("B2D_DrawText") == FALSE)
{
return FALSE;
}
// check there is some text to draw
if (szString == NULL
|| strlen(szString) == 0)
{
return TRUE;
}
// get array index of currently selected surface
iCurrentSurface = _GetSurfaceArrayIndexFromHandle(hCurrentSurfaceHandleSelected);
// draw text
switch (iMode)
{
case B2D_MODE_DIRECTX:
if (DX_DrawTextEx(szString,
x + iShadowX, y + iShadowY,
NULL,
iAlignment,
0,
0,
0,
pListOfOffscreenSurfaces[iCurrentSurface].iOpacity) == FALSE)
{
return FALSE;
}
if (DX_DrawTextEx(szString,
x, y,
NULL,
iAlignment,
pListOfOffscreenSurfaces[iCurrentSurface].iRed,
pListOfOffscreenSurfaces[iCurrentSurface].iGreen,
pListOfOffscreenSurfaces[iCurrentSurface].iBlue,
pListOfOffscreenSurfaces[iCurrentSurface].iOpacity) == FALSE)
{
return FALSE;
}
return TRUE;
case B2D_MODE_GDIPLUS:
if (GDIP_DrawTextEx(szString,
x + iShadowX, y + iShadowY,
NULL,
iAlignment,
0,
0,
0,
pListOfOffscreenSurfaces[iCurrentSurface].iOpacity) == FALSE)
{
return FALSE;
}
if (GDIP_DrawTextEx(szString,
x, y,
NULL,
iAlignment,
pListOfOffscreenSurfaces[iCurrentSurface].iRed,
pListOfOffscreenSurfaces[iCurrentSurface].iGreen,
pListOfOffscreenSurfaces[iCurrentSurface].iBlue,
pListOfOffscreenSurfaces[iCurrentSurface].iOpacity) == FALSE)
{
return FALSE;
}
return TRUE;
}
// no such mode
return FALSE;
}
BOOL B2D_DrawTextCenteredAt(char* szString, float x, float y)
{
int iCurrentSurface;
// check that drawing has been started
if (_CheckDrawingHasStarted("B2D_DrawTextCenteredAt") == FALSE)
{
return FALSE;
}
// check there is some text to draw
if (szString == NULL
|| strlen(szString) == 0)
{
return TRUE;
}
// get array index of currently selected surface
iCurrentSurface = _GetSurfaceArrayIndexFromHandle(hCurrentSurfaceHandleSelected);
// draw text centered at point
switch (iMode)
{
case B2D_MODE_DIRECTX:
return DX_DrawTextEx(szString,
x, y,
NULL,
DT_CENTER | DT_VCENTER,
pListOfOffscreenSurfaces[iCurrentSurface].iRed,
pListOfOffscreenSurfaces[iCurrentSurface].iGreen,
pListOfOffscreenSurfaces[iCurrentSurface].iBlue,
pListOfOffscreenSurfaces[iCurrentSurface].iOpacity);
case B2D_MODE_GDIPLUS:
return GDIP_DrawTextEx(szString,
x, y,
NULL,
DT_CENTER | DT_VCENTER,
pListOfOffscreenSurfaces[iCurrentSurface].iRed,
pListOfOffscreenSurfaces[iCurrentSurface].iGreen,
pListOfOffscreenSurfaces[iCurrentSurface].iBlue,
pListOfOffscreenSurfaces[iCurrentSurface].iOpacity);
}
// no such mode
return FALSE;
}
BOOL B2D_DrawTextCenteredAtWithShadow(char* szString, float x, float y, int iShadowX, int iShadowY)
{
int iCurrentSurface;
// check that drawing has been started
if (_CheckDrawingHasStarted("B2D_DrawTextCenteredAt") == FALSE)
{
return FALSE;
}
// check there is some text to draw
if (szString == NULL
|| strlen(szString) == 0)
{
return TRUE;
}
// get array index of currently selected surface
iCurrentSurface = _GetSurfaceArrayIndexFromHandle(hCurrentSurfaceHandleSelected);
// draw text centered at point
switch (iMode)
{
case B2D_MODE_DIRECTX:
if (DX_DrawTextEx(szString,
x + iShadowX, y + iShadowY,
NULL,
DT_CENTER | DT_VCENTER,
0,
0,
0,
pListOfOffscreenSurfaces[iCurrentSurface].iOpacity) == FALSE)
{
return FALSE;
}
if (DX_DrawTextEx(szString,
x, y,
NULL,
DT_CENTER | DT_VCENTER,
pListOfOffscreenSurfaces[iCurrentSurface].iRed,
pListOfOffscreenSurfaces[iCurrentSurface].iGreen,
pListOfOffscreenSurfaces[iCurrentSurface].iBlue,
pListOfOffscreenSurfaces[iCurrentSurface].iOpacity) == FALSE)
{
return FALSE;
}
return TRUE;
case B2D_MODE_GDIPLUS:
if (GDIP_DrawTextEx(szString,
x + iShadowX, y + iShadowY,
NULL,
DT_CENTER | DT_VCENTER,
0,
0,
0,
pListOfOffscreenSurfaces[iCurrentSurface].iOpacity) == FALSE)
{
return FALSE;
}
if (GDIP_DrawTextEx(szString,
x, y,
NULL,
DT_CENTER | DT_VCENTER,
pListOfOffscreenSurfaces[iCurrentSurface].iRed,
pListOfOffscreenSurfaces[iCurrentSurface].iGreen,
pListOfOffscreenSurfaces[iCurrentSurface].iBlue,
pListOfOffscreenSurfaces[iCurrentSurface].iOpacity) == FALSE)
{
return FALSE;
}
return TRUE;
}
// no such mode
return FALSE;
}
BOOL B2D_DrawTextInRect(char* szString, RECT_F* pRect, int iAlignment)
{
int iCurrentSurface;
// check that drawing has been started
if (_CheckDrawingHasStarted("B2D_DrawTextInRect") == FALSE)
{
return FALSE;
}
// check there is some text to draw
if (szString == NULL
|| strlen(szString) == 0)
{
return TRUE;
}
// get array index of currently selected surface
iCurrentSurface = _GetSurfaceArrayIndexFromHandle(hCurrentSurfaceHandleSelected);
// draw text in rect
switch (iMode)
{
case B2D_MODE_DIRECTX:
return DX_DrawTextEx(szString,
(float)pRect->left, (float)pRect->right,
pRect,
iAlignment,
pListOfOffscreenSurfaces[iCurrentSurface].iRed,
pListOfOffscreenSurfaces[iCurrentSurface].iGreen,
pListOfOffscreenSurfaces[iCurrentSurface].iBlue,
pListOfOffscreenSurfaces[iCurrentSurface].iOpacity);
case B2D_MODE_GDIPLUS:
return GDIP_DrawTextEx(szString,
(float)pRect->left, (float)pRect->right,
pRect,
iAlignment,
pListOfOffscreenSurfaces[iCurrentSurface].iRed,
pListOfOffscreenSurfaces[iCurrentSurface].iGreen,
pListOfOffscreenSurfaces[iCurrentSurface].iBlue,
pListOfOffscreenSurfaces[iCurrentSurface].iOpacity);
}
// no such mode
return FALSE;
}
/////////////////////////////////////
// Set Pen attributes //
/////////////////////////////////////
BOOL B2D_SetPenColor(int iRed, int iGreen, int iBlue, float fOpacity)
{
int i;
// check that drawing has been started
if (_CheckDrawingHasStarted("B2D_SetPenColor") == FALSE)
{
return FALSE;
}
// find which surface is currently selected
i = _GetSurfaceArrayIndexFromHandle(hCurrentSurfaceHandleSelected);
// set the colour and opacity
pListOfOffscreenSurfaces[i].iRed = B2D_MIN(B2D_MAX(iRed, 0), 255);
pListOfOffscreenSurfaces[i].iGreen = B2D_MIN(B2D_MAX(iGreen, 0), 255);
pListOfOffscreenSurfaces[i].iBlue = B2D_MIN(B2D_MAX(iBlue, 0), 255);
pListOfOffscreenSurfaces[i].iOpacity = B2D_MIN(B2D_MAX((int)(255.0f * fOpacity), 0), 255);
// success
return TRUE;
}
BOOL B2D_SetFillColor(int iRed, int iGreen, int iBlue, float fOpacity)
{
int i;
// check that drawing has been started
if (_CheckDrawingHasStarted("B2D_SetFillColor") == FALSE)
{
return FALSE;
}
// find which surface is currently selected
i = _GetSurfaceArrayIndexFromHandle(hCurrentSurfaceHandleSelected);
// set the colour and opacity
pListOfOffscreenSurfaces[i].iBackgroundRed = B2D_MIN(B2D_MAX(iRed, 0), 255);
pListOfOffscreenSurfaces[i].iBackgroundGreen = B2D_MIN(B2D_MAX(iGreen, 0), 255);
pListOfOffscreenSurfaces[i].iBackgroundBlue = B2D_MIN(B2D_MAX(iBlue, 0), 255);
pListOfOffscreenSurfaces[i].iBackgroundOpacity = B2D_MIN(B2D_MAX((int)(255.0f * fOpacity), 0), 255);
// success
return TRUE;
}
BOOL B2D_SetPenAntiAlias(BOOL bAntiAlias)
{
int i;
// check that drawing has been started
if (_CheckDrawingHasStarted("B2D_SetPenAntiAlias") == FALSE)
{
return FALSE;
}
// find which surface is currently selected
i = _GetSurfaceArrayIndexFromHandle(hCurrentSurfaceHandleSelected);
// set anti-alias
if (bAntiAlias == TRUE)
{
pListOfOffscreenSurfaces[i].bAntiAlias = TRUE;
}
else
{
pListOfOffscreenSurfaces[i].bAntiAlias = FALSE;
}
// success
return TRUE;
}
BOOL B2D_SetFont(int hFontHandle)
{
int i;
// check that drawing has been started
if (_CheckDrawingHasStarted("B2D_SetFont") == FALSE)
{
return FALSE;
}
// if sent a negative value just use the default font
if (hFontHandle < 0)
{
hFontHandle = HANDLES_START_AT;
}
// check for valid font handle
if (hFontHandle < HANDLES_START_AT
|| hFontHandle >= HANDLES_START_AT + iNumberOfFontsCreated)
{
ALERT("Font handle is invalid", "B2D_SetFont");
return FALSE;
}
// find which surface is currently selected
i = _GetSurfaceArrayIndexFromHandle(hCurrentSurfaceHandleSelected);
// select this font
pListOfOffscreenSurfaces[i].hFontHandleSelected = hFontHandle;
// success
return TRUE;
}
//////////////////////////////////
// Get attributes //
//////////////////////////////////
int B2D_GetFontHeight(int hFontHandle)
{
int i;
// asking for height of the currently selected font?
if (hFontHandle == -1)
{
// yes, so check that drawing has been started
if (_CheckDrawingHasStarted("B2D_GetFontHeight") == FALSE)
{
return 0;
}
// get array index of currently selected surface
i = _GetSurfaceArrayIndexFromHandle(hCurrentSurfaceHandleSelected);
// get font handle of font in currently selected surface
hFontHandle = pListOfOffscreenSurfaces[i].hFontHandleSelected;
}
else
{
// no, so check that font handle is valid
if (hFontHandle < HANDLES_START_AT
|| hFontHandle >= HANDLES_START_AT + iNumberOfFontsCreated)
{
ALERT("Font handle is invalid", "B2D_GetFontHeight");
return 0;
}
}
// return height
return pListOfFonts[hFontHandle - HANDLES_START_AT].iHeight;
}
int B2D_GetSurfaceWidth(int hSurfaceHandle)
{
int iSurface;
// check that drawing has been started
if (_CheckDrawingHasStarted("B2D_GetSurfaceWidth") == FALSE)
{
return 0;
}
// use current surface?
if (hSurfaceHandle == -1)
{
hSurfaceHandle = hCurrentSurfaceHandleSelected;
}
// check that surface handle is valid
if (_CheckValidSurfaceHandle(hSurfaceHandle, "B2D_GetSurfaceWidth") == FALSE)
{
return 0;
}
// calculate this surfaces's array index
iSurface = _GetSurfaceArrayIndexFromHandle(hSurfaceHandle);
// return width
return pListOfOffscreenSurfaces[iSurface].iWidth;
}
int B2D_GetSurfaceHeight(int hSurfaceHandle)
{
int iSurface;
// check that drawing has actually been started so there is a current surface!
if (_CheckDrawingHasStarted("B2D_GetSurfaceHeight") == FALSE)
{
return 0;
}
// use current surface?
if (hSurfaceHandle == -1)
{
// use the current surface handle
hSurfaceHandle = hCurrentSurfaceHandleSelected;
}
// check that surface handle is valid
if (_CheckValidSurfaceHandle(hSurfaceHandle, "B2D_GetSurfaceHeight") == FALSE)
{
return 0;
}
// calculate this surfaces's array index
iSurface = _GetSurfaceArrayIndexFromHandle(hSurfaceHandle);
// return height
return pListOfOffscreenSurfaces[iSurface].iHeight;
}
int B2D_GetImageWidth(int hImageHandle)
{
int i;
// check that a valid image handle was sent
if (hImageHandle < HANDLES_START_AT
|| hImageHandle >= HANDLES_START_AT + iNumberOfImagesLoaded)
{
ALERT("Invalid image handle", "B2D_GetImageWidth");
return FALSE;
}
// get the index of this image handle
i = hImageHandle - HANDLES_START_AT;
// return width
return (pListOfImages[i].iActualWidth);
}
int B2D_GetImageHeight(int hImageHandle)
{
int i;
// check that a valid image handle was sent
if (hImageHandle < HANDLES_START_AT
|| hImageHandle >= HANDLES_START_AT + iNumberOfImagesLoaded)
{
ALERT("Invalid image handle", "B2D_GetImageHeight");
return FALSE;
}
// get the index of this image handle
i = hImageHandle - HANDLES_START_AT;
// return width
return (pListOfImages[i].iActualHeight);
}
///////////////////////////////////////////////////////////
// //
// GDI Plus //
// //
///////////////////////////////////////////////////////////
//////////////////////////////////////
// Initialize GDIPlus //
//////////////////////////////////////
BOOL GDIP_Start(HWND hWnd)
{
RECT rect;
// get DC to the window
hdcWindow = GetDC(hWnd);
// create working HDCs
hdcSurface = CreateCompatibleDC(hdcWindow);
SetMapMode(hdcSurface, GetMapMode(hdcWindow));
hdcFrom = CreateCompatibleDC(hdcWindow);
SetMapMode(hdcFrom, GetMapMode(hdcWindow));
// create GDI+ surface
Graphics graphics(hdcSurface);
// create space for the back buffer's current pen settings
iNumberOfOffscreenSurfacesCreated = 1;
pListOfOffscreenSurfaces = (SURFACE*)realloc(pListOfOffscreenSurfaces, sizeof(SURFACE) * 1);
if (pListOfOffscreenSurfaces == NULL)
{
ALERT("Memory not allocated", "GDIP_Start");
return FALSE;
}
_ResetSurfaceAttributesToDefaults(BACK_BUFFER);
GetClientRect(hWnd, &rect);
pListOfOffscreenSurfaces[0].iWidth = rect.right;
pListOfOffscreenSurfaces[0].iHeight = rect.bottom;
// create a 'back buffer'
pListOfOffscreenSurfaces[0].pGraphicsGDIP = CreateCompatibleBitmap(hdcWindow, rect.right, rect.bottom);
HBITMAP hBitmapOld;
hBitmapOld = (HBITMAP)SelectObject(hdcSurface, pListOfOffscreenSurfaces[0].pGraphicsGDIP);
FillRect(hdcSurface, &rect, (HBRUSH)(GetStockObject(BLACK_BRUSH)));
SelectObject(hdcSurface, hBitmapOld);
// make a default font
B2D_CreateFont(16, FW_NORMAL, FALSE, "Arial");
// success
return TRUE;
}
////////////////////////////////
// Stop GDIPlus //
////////////////////////////////
void GDIP_Stop()
{
int i;
// free DCs
SelectObject(hdcSurface, hSurfaceBitmapOld);
DeleteDC(hdcSurface);
DeleteDC(hdcFrom);
ReleaseDC(hWindow, hdcWindow);
// free all images
if (pListOfImages != NULL)
{
for (i=0; i<iNumberOfImagesLoaded; i++)
{
// free the GDI+ image
if (pListOfImages[i].pImageGDIP != NULL)
{
delete pListOfImages[i].pImageGDIP;
}
// free the GDI image
if (pListOfImages[i].pImageGDI != NULL)
{
DeleteObject(pListOfImages[i].pImageGDI);
}
}
// free image data memory
free(pListOfImages);
pListOfImages = NULL;
}
// free all surfaces
if (pListOfOffscreenSurfaces != NULL)
{
for (i=0; i<iNumberOfOffscreenSurfacesCreated; i++) // do release surface number 0 as it signifies the back buffer
{
DeleteObject(pListOfOffscreenSurfaces[i].pGraphicsGDIP);
}
// free surface data memory
free(pListOfOffscreenSurfaces);
pListOfOffscreenSurfaces = NULL;
}
// free all fonts
if (pListOfFonts != NULL)
{
for (i=0; i<iNumberOfFontsCreated; i++)
{
if (pListOfFonts[i].pFontGDIP != NULL)
{
delete pListOfFonts[i].pFontGDIP;
//DeleteObject(pListOfFonts[i].hFont);
}
}
// free image data memory
free(pListOfFonts);
pListOfFonts = NULL;
}
}
///////////////////////////////////////////////
// The window has been resized //
///////////////////////////////////////////////
BOOL GDIP_Resize(HWND hWnd)
{
// delete the existing back buffer
if (pListOfOffscreenSurfaces[0].pGraphicsGDIP != NULL)
{
DeleteObject(pListOfOffscreenSurfaces[0].pGraphicsGDIP);
pListOfOffscreenSurfaces[0].pGraphicsGDIP = NULL;
}
// store the client window size
GetClientRect(hWnd, &rClient);
// create a new back buffer
pListOfOffscreenSurfaces[0].pGraphicsGDIP = CreateCompatibleBitmap(hdcWindow, rClient.right, rClient.bottom);
// success
return TRUE;
}
///////////////////////////////////////////////
// Create an Offscreen surface //
///////////////////////////////////////////////
BOOL GDIP_CreateOffscreenSurface(int i, int iWidth, int iHeight)
{
HDC hdcTo;
RECT rect;
// create the buffer
pListOfOffscreenSurfaces[i].pGraphicsGDIP = CreateCompatibleBitmap(hdcWindow, iWidth, iHeight);
if (pListOfOffscreenSurfaces[i].pGraphicsGDIP == NULL)
{
return FALSE;
}
// clear it
rect.left = 0;
rect.right = iWidth;
rect.top = 0;
rect.bottom = iHeight;
hdcTo = CreateCompatibleDC(hdcWindow);
FillRect(hdcTo, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH));
DeleteDC(hdcTo);
// success
return TRUE;
}
BOOL GDIP_CreateFontEx(int i,
unsigned int iHeight,
unsigned int iWidth,
unsigned int iWeight,
unsigned int iMipLevels,
BOOL bItalic,
DWORD dwCharSet,
DWORD dwOutputPrecision,
DWORD dwQuality,
DWORD dwPitchAndFamily,
char* szFacename)
{
// create font family
WCHAR wcFacename[MAX_PATH];
mbstowcs(wcFacename, szFacename, MAX_PATH);
FontFamily fontFamily(wcFacename);
// calculate style
int iStyle = 0;
if (bItalic == TRUE)
{
iStyle |= FontStyleItalic;
}
if (iWeight >= FW_BOLD)
{
iStyle |= FontStyleBold;
}
// create the font (GDI+ fonts seem to be larger so I've scaled the height by 0.8)
pListOfFonts[i].pFontGDIP = new Font(&fontFamily, (REAL)(iHeight) * 0.8f, iStyle, UnitPixel);
/*
LOGFONT logfont;
// make the font
logfont.lfHeight = iHeight;
logfont.lfWidth = iWidth;
logfont.lfEscapement = 0;
logfont.lfOrientation = 0;
logfont.lfWeight = iWeight;
logfont.lfItalic = bItalic;
logfont.lfUnderline = FALSE;
logfont.lfStrikeOut = FALSE;
logfont.lfCharSet = (BYTE)dwCharSet;
logfont.lfOutPrecision = (BYTE)dwOutputPrecision;
logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
logfont.lfQuality = (BYTE)dwQuality;
logfont.lfPitchAndFamily = (BYTE)dwPitchAndFamily;
strcpy(logfont.lfFaceName, szFacename) ;
pListOfFonts[i].hFont = CreateFontIndirect(&logfont);
*/
// success
return TRUE;
}
//////////////////////////////////////
// Change font height //
//////////////////////////////////////
void GDIP_ChangeFontHeight(int hFontHandle, int iHeight)
{
int i;
i = hFontHandle - HANDLES_START_AT;
if (i >= 0
&& i < iNumberOfFontsCreated)
{
// release this font
delete pListOfFonts[i].pFontGDIP;
// set new height
pListOfFonts[i].iHeight = iHeight;
// create this font
GDIP_CreateFontEx(i,
pListOfFonts[i].iHeight,
pListOfFonts[i].iWidth,
pListOfFonts[i].iWeight,
pListOfFonts[i].iMipLevels,
pListOfFonts[i].bItalic,
pListOfFonts[i].dwCharSet,
pListOfFonts[i].dwOutputPrecision,
pListOfFonts[i].dwQuality,
pListOfFonts[i].dwPitchAndFamily,
pListOfFonts[i].szFacename);
}
}
///////////////////////////////
// Delete font //
///////////////////////////////
void GDIP_DeleteFont(int hFontHandle)
{
int i;
i = hFontHandle - HANDLES_START_AT;
if (i >= 0
&& i < iNumberOfFontsCreated)
{
if (pListOfFonts[i].pFontGDIP != NULL)
{
delete pListOfFonts[i].pFontGDIP;
pListOfFonts[i].pFontGDIP = NULL;
}
else
{
ALERT("hFontHandle was already deleted", "GDIP_DeleteFont");
}
}
else
{
ALERT("hFontHandle was out of range", "GDIP_DeleteFont");
}
}
BOOL GDIP_LoadImage(int i, char* szFilename, int iWidth, int iHeight)
{
// is this image a BMP? If so then using GDI is quicker than GDI+ and can be used when there's 100% opacity
if (strstr(szFilename, ".bmp") != NULL
|| strstr(szFilename, ".BMP") != NULL)
{
pListOfImages[i].pImageGDI = (HBITMAP)LoadImage(NULL, szFilename, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE );
}
else
{
pListOfImages[i].pImageGDI = NULL;
}
// load the GDI+ image
WCHAR wcFilename[MAX_PATH];
mbstowcs(wcFilename, szFilename, MAX_PATH);
pListOfImages[i].pImageGDIP = Bitmap::FromFile(wcFilename, FALSE);
// did it load?
if (pListOfImages[i].pImageGDIP == NULL
&& pListOfImages[i].pImageGDI == NULL)
{
return FALSE;
}
// TODO: could check through every pixel and if none have a non-100% opacity then GDI could be used to draw this image instead?
// record size
pListOfImages[i].iActualWidth = iWidth;
pListOfImages[i].iActualHeight = iHeight;
pListOfImages[i].iTextureWidth = iWidth;
pListOfImages[i].iTextureHeight = iHeight;
// success
return TRUE;
}
BOOL GDIP_DeleteImage(int hImageHandle)
{
int iImage;
// calculate this image's array index
iImage = hImageHandle - HANDLES_START_AT;
// free the GDI+ image
if (pListOfImages[iImage].pImageGDIP != NULL)
{
delete pListOfImages[iImage].pImageGDIP;
pListOfImages[iImage].pImageGDIP = NULL;
}
// free the GDI image
if (pListOfImages[iImage].pImageGDI != NULL)
{
DeleteObject(pListOfImages[iImage].pImageGDI);
pListOfImages[iImage].pImageGDI = NULL;
}
return TRUE;
}
BOOL GDIP_StartDrawingTo(int hSurfaceHandle)
{
int i;
// remember the surface that is now selected
hCurrentSurfaceHandleSelected = hSurfaceHandle;
// select the offscreen surface
i = _GetSurfaceArrayIndexFromHandle(hCurrentSurfaceHandleSelected);
hSurfaceBitmapOld = (HBITMAP)SelectObject(hdcSurface, pListOfOffscreenSurfaces[i].pGraphicsGDIP);
// success
return TRUE;
}
BOOL GDIP_FinishedDrawing()
{
// reselect old bitmap
SelectObject(hdcSurface, hSurfaceBitmapOld);
// no surface is now current
hCurrentSurfaceHandleSelected = 0;
// success
return TRUE;
}
BOOL GDIP_Present()
{
HBITMAP hBitmapOld;
// select the back buffer
hBitmapOld = (HBITMAP)SelectObject(hdcFrom, pListOfOffscreenSurfaces[0].pGraphicsGDIP);
// BLT the back buffer to the screen
BitBlt(hdcWindow, 0, 0, rClient.right, rClient.bottom, hdcFrom, 0, 0, SRCCOPY);
// reselect original bitmap
SelectObject(hdcFrom, hBitmapOld);
// success
return TRUE;
}
BOOL GDIP_ClearRect(RECT_F* pRect, int iRed, int iGreen, int iBlue, float fOpacity)
{
HBRUSH hBrush;
int i;
RectF rectF;
RECT rect;
//if (iOpacity == 255) <-- don't use opacity because DirectX can't do this!
{
// create brush
hBrush = CreateSolidBrush(PALETTERGB(iRed, iGreen, iBlue));
// clear the rect
if (pRect == NULL)
{
i = _GetSurfaceArrayIndexFromHandle(hCurrentSurfaceHandleSelected);
rect.left = 0;
rect.right = pListOfOffscreenSurfaces[i].iWidth;
rect.top = 0;
rect.bottom = pListOfOffscreenSurfaces[i].iHeight;
}
else
{
rect.left = (long)pRect->left;
rect.right = (long)pRect->right;
rect.top = (long)pRect->top;
rect.bottom = (long)pRect->bottom;
}
FillRect(hdcSurface, &rect, hBrush);
// delete the brush
DeleteObject(hBrush);
}
/*
else
{
Graphics graphics(hdcSurface);
// create brush
SolidBrush brush(Color(iOpacity, iRed, iGreen, iBlue));
// calculate the coordinates
if (pRect == NULL)
{
i = _GetSurfaceArrayIndexFromHandle(hCurrentSurfaceHandleSelected);
rectF.X = 0;
rectF.Width = (float)pListOfOffscreenSurfaces[i].iWidth;
rectF.Y = 0;
rectF.Height = (float)pListOfOffscreenSurfaces[i].iHeight;
}
else
{
rectF.X = (float)pRect->left;
rectF.Width = (float)(pRect->right - pRect->left);
rectF.Y = (float)pRect->top;
rectF.Height = (float)(pRect->bottom - pRect->top);
}
// clear the rect
graphics.FillRectangle(&brush, rectF);
}
*/
// success
return TRUE;
}
BOOL GDIP_BltSurfaceStretched(int hSurfaceHandle, RECT_F* pSrc, RECT_F* pDest)
{
int i;
HBITMAP hBitmapOld;
RECT rSource;
// select the surface to BLT from
i = _GetSurfaceArrayIndexFromHandle(hSurfaceHandle);
// select the surface image
hBitmapOld = (HBITMAP)SelectObject(hdcFrom, pListOfOffscreenSurfaces[i].pGraphicsGDIP);
// do the BLT
if (pSrc == NULL)
{
// BLT the whole surface
rSource.left = 0;
rSource.right = pListOfOffscreenSurfaces[i].iWidth;
rSource.top = 0;
rSource.bottom = pListOfOffscreenSurfaces[i].iHeight;
StretchBlt(hdcSurface,
(int)pDest->left, (int)pDest->top, (int)(pDest->right - pDest->left), (int)(pDest->bottom - pDest->top),
hdcFrom,
(int)rSource.left, (int)rSource.top, (int)(rSource.right - rSource.left), (int)(rSource.bottom - rSource.top),
SRCCOPY);
}
else
{
// BLT just a section
StretchBlt(hdcSurface,
(int)pDest->left, (int)pDest->top, (int)(pDest->right - pDest->left), (int)(pDest->bottom - pDest->top),
hdcFrom,
(int)pSrc->left, (int)pSrc->top, (int)(pSrc->right - pSrc->left), (int)(pSrc->bottom - pSrc->top),
SRCCOPY);
}
// tidy up
SelectObject(hdcFrom, hBitmapOld);
// success
return TRUE;
}
BOOL GDIP_DrawImage(int hImageHandle, float x, float y, float fSizeX, float fSizeY, float fRotate, float fOpacity, float fFromX, float fFromY, float fToX, float fToY)
{
int iImage;
// check that a valid image handle was sent
if (hImageHandle < HANDLES_START_AT
|| hImageHandle >= HANDLES_START_AT + iNumberOfImagesLoaded)
{
ALERT("Invalid image handle", "B2D_DrawImage");
return FALSE;
}
// get the index of this image handle
iImage = hImageHandle - HANDLES_START_AT;
// use actual size if -1 was sent as a parameter
if (fSizeX < 0)
{
fSizeX = (float)pListOfImages[iImage].iActualWidth;
}
if (fSizeY < 0)
{
fSizeY = (float)pListOfImages[iImage].iActualHeight;
}
// use GDI (if it's just a BMP file and the opacity is set to 100%)
if (pListOfImages[iImage].pImageGDI != NULL
&& fOpacity == 1.0f)
{
HBITMAP hBitmapOld;
hBitmapOld = (HBITMAP)SelectObject(hdcFrom, pListOfImages[iImage].pImageGDI);
// do the BLT
BitBlt(hdcSurface,
(int)x,
(int)y,
(int)fSizeX,
(int)fSizeY,
hdcFrom,
(int)fFromX,
(int)fFromY,
SRCCOPY);
// reselect old bitmap
SelectObject(hdcFrom, hBitmapOld);
}
else
{
// use GDI+
Graphics graphics(hdcSurface);
// calculate position
Rect destination;
destination.X = (int)x;
destination.Y = (int)y;
destination.Width = (int)fSizeX;
destination.Height = (int)fSizeY;
// is it being drawn with some transparency?
if (fOpacity != 1.0f)
{
// yes, so create the color matrix etc...
ColorMatrix ClrMatrix = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, fOpacity, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
ImageAttributes ImgAttr;
ImgAttr.SetColorMatrix(&ClrMatrix, ColorMatrixFlagsDefault, ColorAdjustTypeBitmap);
// draw the semi-transparent image
graphics.DrawImage(pListOfImages[iImage].pImageGDIP,
destination,
(int)(fFromX * pListOfImages[iImage].iActualWidth),
(int)(fFromY * pListOfImages[iImage].iActualHeight),
(int)((fToX-fFromX) * pListOfImages[iImage].iActualWidth),
(int)((fToY-fFromY) * pListOfImages[iImage].iActualHeight),
UnitPixel,
&ImgAttr);
}
else
{
// no, so just draw the image
graphics.DrawImage(pListOfImages[iImage].pImageGDIP,
destination,
(int)(fFromX * pListOfImages[iImage].iActualWidth),
(int)(fFromY * pListOfImages[iImage].iActualHeight),
(int)((fToX-fFromX) * pListOfImages[iImage].iActualWidth),
(int)((fToY-fFromY) * pListOfImages[iImage].iActualHeight),
UnitPixel,
NULL);
}
}
// success
return TRUE;
}
BOOL GDIP_DrawLine(float fFromX, float fFromY, float fToX, float fToY, float fWidth, int iRed, int iGreen, int iBlue, int iOpacity)
{
HPEN hPen;
HPEN hPenOld;
// create the colored pen
hPen = CreatePen(PS_SOLID, (int)fWidth, PALETTERGB(iRed, iGreen, iBlue));
// select the pen
hPenOld = (HPEN)SelectObject(hdcSurface, hPen);
// draw the line
MoveToEx(hdcSurface, (int)fFromX, (int)fFromY, NULL);
LineTo(hdcSurface, (int)fToX, (int)fToY);
// tidy up
SelectObject(hdcSurface, hPenOld);
DeleteObject(hPen);
// success
return TRUE;
}
BOOL GDIP_DrawTextEx(char* szString, float x, float y, RECT_F* pRect, int iAlignment, int iRed, int iGreen, int iBlue, int iOpacity)
{
int i;
PointF origin;
RectF rBox;
// convert text to WCHAR
WCHAR wcString[1024];
mbstowcs(wcString, szString, 1024);
// get surface index
i = _GetSurfaceArrayIndexFromHandle(hCurrentSurfaceHandleSelected);
// create surface
Graphics graphics(hdcSurface);
// clear the rect?
if (pRect != NULL)
{
/*
HBRUSH hBrush, hBrushOld;
hBrush = CreateSolidBrush(PALETTERGB(pListOfOffscreenSurfaces[i].iBackgroundRed,
pListOfOffscreenSurfaces[i].iBackgroundGreen,
pListOfOffscreenSurfaces[i].iBackgroundBlue));
hBrushOld = (HBRUSH)SelectObject(hdcSurface, hBrush);
FillRect(hdcSurface, pRect, hBrush);
SelectObject(hdcSurface, hBrushOld);
DeleteObject(hBrush);
*/
if (pListOfOffscreenSurfaces[i].iBackgroundOpacity != 0)
{
GDIP_ClearRect(pRect, pListOfOffscreenSurfaces[i].iBackgroundRed,
pListOfOffscreenSurfaces[i].iBackgroundGreen,
pListOfOffscreenSurfaces[i].iBackgroundBlue,
1.0f);
}
rBox.X = (float)(pRect->left);
rBox.Width = (float)(pRect->right - pRect->left);
rBox.Y = (float)(pRect->top);
rBox.Height = (float)(pRect->bottom - pRect->top);
}
else
{
rBox.X = x;// - 1280;
rBox.Width = 0;// + 1280;
rBox.Y = y;// - 200;
rBox.Height = 0;// + 200;
}
// create colour
SolidBrush brush(Color((BYTE)iOpacity,
(BYTE)iRed,
(BYTE)iGreen,
(BYTE)iBlue));
// measure size of text
PointF layoutOrigin(0, 0);
RectF boundRect;
graphics.MeasureString(wcString,
-1,
pListOfFonts[pListOfOffscreenSurfaces[i].hFontHandleSelected - HANDLES_START_AT].pFontGDIP,
layoutOrigin,
&boundRect);
// calculate position
if ((iAlignment & DT_RIGHT) == DT_RIGHT)
{
origin.X = (rBox.X + rBox.Width) - boundRect.Width;
}
else if ((iAlignment & DT_CENTER) == DT_CENTER)
{
origin.X = (float)(rBox.X + rBox.Width/2) - boundRect.Width/2;
}
else
{
origin.X = (float)rBox.X;
}
if ((iAlignment & DT_BOTTOM) == DT_BOTTOM)
{
origin.Y = (rBox.Y + rBox.Height) - boundRect.Height;
}
else if ((iAlignment & DT_VCENTER) == DT_VCENTER)
{
origin.Y = (float)(rBox.Y + rBox.Height/2) - boundRect.Height/2;
}
else
{
origin.Y = (float)rBox.Y;
}
// draw the string
graphics.DrawString(wcString,
-1,
pListOfFonts[pListOfOffscreenSurfaces[i].hFontHandleSelected - HANDLES_START_AT].pFontGDIP,
origin,
&brush);
/*
//HFONT hFontOld;
hFontOld = (HFONT)SelectObject(hdcSurface, pListOfFonts[pListOfOffscreenSurfaces[i].hFontHandleSelected - HANDLES_START_AT].hFont);
if (pListOfOffscreenSurfaces[i].bTransparentText == TRUE)
{
SetBkMode(hdcSurface, TRANSPARENT);
}
else
{
SetBkMode(hdcSurface, OPAQUE);
}
if ((iAlignment & DT_CENTER) == DT_CENTER)
{
x = (pRect->left + pRect->right)/2;
y = pRect->top;
SetTextAlign(hdcSurface, TA_CENTER);
}
else if ((iAlignment & DT_RIGHT) == DT_RIGHT)
{
x = pRect->right;
y = pRect->top;
SetTextAlign(hdcSurface, TA_RIGHT);
}
else
{
x = pRect->left;
y = pRect->top;
SetTextAlign(hdcSurface, TA_LEFT);
}
SetTextColor(hdcSurface, PALETTERGB(pListOfOffscreenSurfaces[i].iRed, pListOfOffscreenSurfaces[i].iGreen, pListOfOffscreenSurfaces[i].iBlue));
SetBkColor(hdcSurface, PALETTERGB(pListOfOffscreenSurfaces[i].iBackgroundRed, pListOfOffscreenSurfaces[i].iBackgroundGreen, pListOfOffscreenSurfaces[i].iBackgroundBlue));
TextOut(hdcSurface, x, y, szString, strlen(szString));
SelectObject(hdcSurface, hFontOld);
*/
return TRUE;
}
//////////////////////////////////////////////////////////
// //
// DirectX //
// //
//////////////////////////////////////////////////////////
///////////////////////////////////////
// Initialize Direct3D //
///////////////////////////////////////
BOOL DX_Start(HWND hWnd)
{
pD3D = NULL;
pd3dDevice = NULL;
// load the main DirectX DLL
hModuleD3D9 = LoadLibrary("D3D9.DLL");
if (hModuleD3D9 == NULL)
{
ALERT("Failed to load D3D9.dll", "DX_Start")
iFatalError = B2D_ERROR_NO_DIRECTX9;
return FALSE;
}
// load the D3DX9 DLL (used for loading images, drawing text, drawing lines)
iFatalError = 43;
hModuleD3DX9 = LoadLibrary("D3DX9_43.dll");
if (!hModuleD3DX9) { hModuleD3DX9 = LoadLibrary("D3DX9_42.dll"); iFatalError = 42; }; // try older DLLs
if (!hModuleD3DX9) { hModuleD3DX9 = LoadLibrary("D3DX9_41.dll"); iFatalError = 41; };
if (!hModuleD3DX9) { hModuleD3DX9 = LoadLibrary("D3DX9_40.dll"); iFatalError = 40; };
if (!hModuleD3DX9) { hModuleD3DX9 = LoadLibrary("D3DX9_39.dll"); iFatalError = 39; };
if (!hModuleD3DX9) { hModuleD3DX9 = LoadLibrary("D3DX9_38.dll"); iFatalError = 38; };
if (!hModuleD3DX9) { hModuleD3DX9 = LoadLibrary("D3DX9_37.dll"); iFatalError = 37; };
if (!hModuleD3DX9) { hModuleD3DX9 = LoadLibrary("D3DX9_36.dll"); iFatalError = 36; };
if (!hModuleD3DX9) { hModuleD3DX9 = LoadLibrary("D3DX9_35.dll"); iFatalError = 35; };
if (!hModuleD3DX9) { hModuleD3DX9 = LoadLibrary("D3DX9_34.dll"); iFatalError = 34; };
if (!hModuleD3DX9) { hModuleD3DX9 = LoadLibrary("D3DX9_33.dll"); iFatalError = 33; };
if (!hModuleD3DX9) { hModuleD3DX9 = LoadLibrary("D3DX9_32.dll"); iFatalError = 32; };
if (!hModuleD3DX9) { hModuleD3DX9 = LoadLibrary("D3DX9_31.dll"); iFatalError = 31; };
if (!hModuleD3DX9) { hModuleD3DX9 = LoadLibrary("D3DX9_30.dll"); iFatalError = 30; };
if (!hModuleD3DX9) { hModuleD3DX9 = LoadLibrary("D3DX9_29.dll"); iFatalError = 29; };
if (!hModuleD3DX9) { hModuleD3DX9 = LoadLibrary("D3DX9_28.dll"); iFatalError = 28; };
if (!hModuleD3DX9) { hModuleD3DX9 = LoadLibrary("D3DX9_27.dll"); iFatalError = 27; };
if (!hModuleD3DX9) { hModuleD3DX9 = LoadLibrary("D3DX9_26.dll"); iFatalError = 26; };
if (!hModuleD3DX9) { hModuleD3DX9 = LoadLibrary("D3DX9_25.dll"); iFatalError = 25; };
if (!hModuleD3DX9) { hModuleD3DX9 = LoadLibrary("D3DX9_24.dll"); iFatalError = 24; };
if (!hModuleD3DX9) { hModuleD3DX9 = LoadLibrary("D3DX9_23.dll"); iFatalError = 23; };
if (!hModuleD3DX9) { hModuleD3DX9 = LoadLibrary("D3DX9_22.dll"); iFatalError = 22; };
if (!hModuleD3DX9) { hModuleD3DX9 = LoadLibrary("D3DX9_21.dll"); iFatalError = 21; };
if (!hModuleD3DX9) { hModuleD3DX9 = LoadLibrary("D3DX9_20.dll"); iFatalError = 20; };
if (!hModuleD3DX9) { hModuleD3DX9 = LoadLibrary("D3DX9_19.dll"); iFatalError = 19; };
if (!hModuleD3DX9) { hModuleD3DX9 = LoadLibrary("D3DX9_18.dll"); iFatalError = 18; };
if (hModuleD3DX9 == NULL)
{
ALERT("Failed to load D3DX9_nn.dll", "DX_Start")
iFatalError = B2D_ERROR_NO_D3DX9;
return FALSE;
}
// get pointers to the D3DX functions that this file uses
pFunc_D3DXCreateTextureFromFile = (PD3DXCreateTextureFromFile) GetProcAddress(hModuleD3DX9, "D3DXCreateTextureFromFileA");
pFunc_PD3DXCreateFont = (PD3DXCreateFont) GetProcAddress(hModuleD3DX9, "D3DXCreateFontA");
pFunc_PD3DXCreateLine = (PD3DXCreateLine) GetProcAddress(hModuleD3DX9, "D3DXCreateLine");
pFunc_PD3DXCreateTexture = (PD3DXCreateTexture) GetProcAddress(hModuleD3DX9, "D3DXCreateTexture");
if (pFunc_D3DXCreateTextureFromFile == NULL
|| pFunc_PD3DXCreateFont == NULL
|| pFunc_PD3DXCreateLine == NULL)
{
ALERT("Couldn't locate vital D3DX functions within D3DX9_nn.dll", "DX_Start")
iFatalError = B2D_ERROR_COULDNT_LOCATE_D3DX9_FUNCTIONS;
return FALSE;
}
// create the directX object
typedef IDirect3D9* (WINAPI *DIRECT3DCREATE_PTR)(UINT SDKVersion);
DIRECT3DCREATE_PTR pFunc_D3DCreate = (DIRECT3DCREATE_PTR)GetProcAddress(hModuleD3D9, "Direct3DCreate9");
if (!pFunc_D3DCreate)
{
ALERT("Unable to start Direct3D", "DX_Start")
iFatalError = B2D_ERROR_COULDNT_LOCATE_CREATE_FUNCTION;
return FALSE;
}
pD3D = pFunc_D3DCreate(D3D_SDK_VERSION);
if (pD3D == NULL)
{
ALERT("Unable to create Direct3D object", "DX_Start")
iFatalError = B2D_ERROR_COULDNT_CREATE_DIRECTX_OBJECT;
return FALSE;
}
// get the display mode
D3DDISPLAYMODE d3ddm;
pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);
// fill the presentation parameters structure
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = d3ddm.Format; //D3DFMT_UNKNOWN;
d3dpp.BackBufferCount = 1;
d3dpp.BackBufferWidth = GetSystemMetrics(SM_CXSCREEN);
d3dpp.BackBufferHeight = GetSystemMetrics(SM_CYSCREEN);
d3dpp.hDeviceWindow = hWnd;
//d3dpp.EnableAutoDepthStencil = true;
//d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
// create a default DirectX device
if (FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp,
&pd3dDevice)))
{
ALERT("Unable to create the Direct3D device", "DX_Start");
iFatalError = B2D_ERROR_COULDNT_CREATE_DEVICE;
return FALSE;
}
// create the vertex buffer
if (FAILED(pd3dDevice->CreateVertexBuffer(4 * sizeof(CUSTOMVERTEX),
0,
D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT,
&vertexBuffer,
NULL)))
{
ALERT("Unable to create vertex buffer", "DX_Start");
iFatalError = B2D_ERROR_COULDNT_CREATE_VERTEX_BUFFER;
return FALSE;
}
pd3dDevice->SetStreamSource(0, vertexBuffer, 0, sizeof(CUSTOMVERTEX));
// set vertex shader
pd3dDevice->SetVertexShader(NULL);
pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
// set render state
pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
//pd3dDevice->SetRenderState ( D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA );
// store original render target of the back buffer (used to create offscreen surfaces later)
pd3dDevice->GetRenderTarget(0, &backBufferTarget);
// create space for the back buffer's current pen settings
iNumberOfOffscreenSurfacesCreated = 1;
pListOfOffscreenSurfaces = (SURFACE*)realloc(pListOfOffscreenSurfaces, sizeof(SURFACE) * 1);
if (pListOfOffscreenSurfaces == NULL)
{
ALERT("Memory not allocated", "DX_Start");
iFatalError = B2D_ERROR_COULDNT_ALLOCATE_MEMORY;
return FALSE;
}
_ResetSurfaceAttributesToDefaults(BACK_BUFFER);
pListOfOffscreenSurfaces[0].iWidth = d3dpp.BackBufferWidth;
pListOfOffscreenSurfaces[0].iHeight = d3dpp.BackBufferHeight;
hImageHandleSelectedDX = -1;
// make a default font
B2D_CreateFont(16, FW_NORMAL, FALSE, "Arial");
// clear the back buffer to black
if (pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0) != D3D_OK)
{
ALERT("Failed to clear back buffer", "DX_Start");
iFatalError = B2D_ERROR_COULDNT_CLEAR;
return FALSE;
}
// success
return TRUE;
}
////////////////////////////////
// Stop DirectX //
////////////////////////////////
void DX_Stop()
{
int i;
// free all images
if (pListOfImages != NULL)
{
for (i=0; i<iNumberOfImagesLoaded; i++)
{
if (pListOfImages[i].pImageDX != NULL)
{
(pListOfImages[i].pImageDX)->Release();
}
}
// free image data memory
free(pListOfImages);
pListOfImages = NULL;
}
// free all surfaces
if (pListOfOffscreenSurfaces != NULL)
{
for (i=1; i<iNumberOfOffscreenSurfacesCreated; i++) // don't release surface number 0 as it signifies the back buffer
{
if (pListOfOffscreenSurfaces[i].pSurfaceDX != NULL)
{
(pListOfOffscreenSurfaces[i].pSurfaceDX)->Release();
}
}
// free surface data memory
free(pListOfOffscreenSurfaces);
pListOfOffscreenSurfaces = NULL;
}
// free all fonts
if (pListOfFonts != NULL)
{
for (i=0; i<iNumberOfFontsCreated; i++)
{
if (pListOfFonts[i].pFontDX != NULL)
{
(pListOfFonts[i].pFontDX)->Release();
}
}
// free image data memory
free(pListOfFonts);
pListOfFonts = NULL;
}
// release the device
if (pd3dDevice != NULL)
{
pd3dDevice->Release();
pd3dDevice = NULL;
}
// release directX object
if (pD3D != NULL)
{
pD3D->Release();
pD3D = NULL;
}
// free DLL
if (hModuleD3DX9 != NULL)
{
FreeLibrary(hModuleD3DX9);
}
if (hModuleD3D9 != NULL)
{
FreeLibrary(hModuleD3D9);
}
}
///////////////////////////////////////////////
// The window has been resized //
///////////////////////////////////////////////
BOOL DX_Resize(HWND hWnd)
{
// store the client window size
RECT rect;
GetClientRect(hWnd, &rect);
if (rect.right - rect.left != 0)
{
rClient = rect;
}
return TRUE;
}
///////////////////////////////////////////////
// Create an Offscreen surface //
///////////////////////////////////////////////
BOOL DX_CreateOffscreenSurface(int i, int iWidth, int iHeight)
{
char szMessage[256];
// get the description of the orginal back buffer's surface
D3DSURFACE_DESC desc;
backBufferTarget->GetDesc(&desc);
// create our surface as a render target
//LPDIRECT3DTEXTURE9 pTexture;
switch (pFunc_PD3DXCreateTexture(pd3dDevice,
iWidth, iHeight,
1,
D3DUSAGE_RENDERTARGET,
D3DFMT_A8R8G8B8,
D3DPOOL_DEFAULT,
&(pListOfOffscreenSurfaces[i].pSurfaceDX)))
/*
switch (pd3dDevice->CreateRenderTarget(iWidth, iHeight,
D3DFMT_A8R8G8B8, //D3DFMT_X8R8G8B8
desc.MultiSampleType, desc.MultiSampleQuality,
FALSE,
&(pListOfOffscreenSurfaces[i].pSurfaceDX),
NULL) )
*/
{
case D3DERR_NOTAVAILABLE:
ALERT("Command not available", "B2D_CreateOffscreenSurface");
return FALSE;
case D3DERR_INVALIDCALL:
ALERT("Invalid Call", "B2D_CreateOffscreenSurface");
return FALSE;
case D3DERR_OUTOFVIDEOMEMORY:
wsprintf(szMessage, "Not enough video memory to create surface of size width=%d height=%d", iWidth, iHeight);
ALERT(szMessage, "B2D_CreateOffscreenSurface");
return FALSE;
case E_OUTOFMEMORY:
wsprintf(szMessage, "Not enough memory to create surface of size width=%d height=%d", iWidth, iHeight);
ALERT(szMessage, "B2D_CreateOffscreenSurface");
return FALSE;
//case D3D_OK:
// pTexture->GetSurfaceLevel(0, &(pListOfOffscreenSurfaces[i].pSurfaceDX));
}
// clear it
int hOriginalSurfaceHandleSelected;
hOriginalSurfaceHandleSelected = hCurrentSurfaceHandleSelected;
_SetNewRenderTarget(i + HANDLES_START_AT);
pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 1.0f, 0);
// restore current render target (never needs to happen if you create all your offscreen buffers before doing any drawing)
if (hOriginalSurfaceHandleSelected != 0)
{
_SetNewRenderTarget(hOriginalSurfaceHandleSelected);
}
else
{
hCurrentSurfaceHandleSelected = 0;
}
// success
return TRUE;
}
///////////////////////////////
// Create Font //
///////////////////////////////
BOOL DX_CreateFontEx(int i,
unsigned int iHeight,
unsigned int iWidth,
unsigned int iWeight,
unsigned int iMipLevels,
BOOL bItalic,
DWORD dwCharSet,
DWORD dwOutputPrecision,
DWORD dwQuality,
DWORD dwPitchAndFamily,
char* szFacename)
{
// create a D3DX font object
switch (pFunc_PD3DXCreateFont(pd3dDevice,
iHeight,
iWidth,
iWeight,
iMipLevels,
bItalic,
dwCharSet,
dwOutputPrecision,
dwQuality,
dwPitchAndFamily,
szFacename,
&(pListOfFonts[i].pFontDX)))
{
case D3DERR_INVALIDCALL:
ALERT("Invalid Call", "B2D_CreateFontEx");
return FALSE;
case D3DXERR_INVALIDDATA:
ALERT("Invalid data", "B2D_CreateFontEx");
return FALSE;
case E_OUTOFMEMORY:
ALERT("Out of memory", "B2D_CreateFontEx");
return FALSE;
}
// pre-load font - takes up memory but should speed up text drawing
pListOfFonts[i].pFontDX->PreloadCharacters(32, 255);
return TRUE;
}
//////////////////////////////////////
// Change font height //
//////////////////////////////////////
void DX_ChangeFontHeight(int hFontHandle, int iHeight)
{
int i;
i = hFontHandle - HANDLES_START_AT;
if (i >= 0
&& i < iNumberOfFontsCreated)
{
// release this font
if (pListOfFonts[i].pFontDX != NULL)
{
(pListOfFonts[i].pFontDX)->Release();
}
// set new height
pListOfFonts[i].iHeight = iHeight;
// create this font
DX_CreateFontEx(i,
pListOfFonts[i].iHeight,
pListOfFonts[i].iWidth,
pListOfFonts[i].iWeight,
pListOfFonts[i].iMipLevels,
pListOfFonts[i].bItalic,
pListOfFonts[i].dwCharSet,
pListOfFonts[i].dwOutputPrecision,
pListOfFonts[i].dwQuality,
pListOfFonts[i].dwPitchAndFamily,
pListOfFonts[i].szFacename);
}
}
/////////////////////////////////
// Delete a font //
/////////////////////////////////
void DX_DeleteFont(int hFontHandle)
{
int i;
i = hFontHandle - HANDLES_START_AT;
if (i >= 0
&& i < iNumberOfFontsCreated)
{
if (pListOfFonts[i].pFontDX != NULL)
{
(pListOfFonts[i].pFontDX)->Release();
pListOfFonts[i].pFontDX = NULL;
}
else
{
ALERT("hFontHandle was already deleted", "DX_DeleteFont");
}
}
else
{
ALERT("hFontHandle was out of range", "DX_DeleteFont");
}
}
/////////////////////////////////
// Load an image //
/////////////////////////////////
BOOL DX_LoadImage(int i, char* szFilename, int iWidth, int iHeight)
{
char szMessage[256];
// load the image
switch (pFunc_D3DXCreateTextureFromFile(pd3dDevice, szFilename, &(pListOfImages[i].pImageDX)))
{
case D3DERR_NOTAVAILABLE:
ALERT("Command not available", "B2D_LoadImage");
return FALSE;
case D3DERR_OUTOFVIDEOMEMORY:
wsprintf(szMessage, "Out of video memory to load file:\n\n %s", szFilename);
ALERT(szMessage, "B2D_LoadImage");
return FALSE;
case D3DERR_INVALIDCALL:
ALERT("Invalid Call", "B2D_LoadImage");
return FALSE;
case D3DXERR_INVALIDDATA:
wsprintf(szMessage, "Couldn't find file:\n\n %s", szFilename);
ALERT(szMessage, "B2D_LoadImage");
return FALSE;
case E_OUTOFMEMORY:
wsprintf(szMessage, "Out of memory to load file:\n\n %s", szFilename);
ALERT(szMessage, "B2D_LoadImage");
return FALSE;
}
// record actual size as specified
pListOfImages[i].iActualWidth = iWidth;
pListOfImages[i].iActualHeight = iHeight;
// get this image's texture size (which will 2, 4, 8, 16, 32 or 64 etc...)
D3DSURFACE_DESC description;
pListOfImages[i].pImageDX->GetLevelDesc(0, &description);
pListOfImages[i].iTextureWidth = description.Width;
pListOfImages[i].iTextureHeight = description.Height;
// success
return TRUE;
}
BOOL DX_DeleteImage(int hImageHandle)
{
int iImage;
// calculate this image's array index
iImage = hImageHandle - HANDLES_START_AT;
// delete it
if (pListOfImages[iImage].pImageDX != NULL)
{
(pListOfImages[iImage].pImageDX)->Release();
pListOfImages[iImage].pImageDX = NULL;
return TRUE;
}
return FALSE;
}
/////////////////////////////////////////////////////////////////////////////////
// Start and Stop drawing to the back buffer or Offscreen surface //
/////////////////////////////////////////////////////////////////////////////////
BOOL DX_StartDrawingTo(int hSurfaceHandle)
{
// set the render target to this surface
_SetNewRenderTarget(hSurfaceHandle);
// begin scene
pd3dDevice->BeginScene();
// success
return TRUE;
}
BOOL DX_FinishedDrawing()
{
// finished drawing to this surface
pd3dDevice->EndScene();
// mark that no surface is current now
hCurrentSurfaceHandleSelected = 0;
// success
return TRUE;
}
BOOL DX_Present()
{
/*
HRESULT hr;
if (m_bDeviceLost)
{
// Test the cooperative level to see if it's okay to render
if( FAILED( hr = pd3dDevice->TestCooperativeLevel() ) )
{
// If the device was lost, do not render until we get it back
if (D3DERR_DEVICELOST == hr)
{
return S_OK;
}
// Check if the device needs to be reset.
if ( D3DERR_DEVICENOTRESET == hr )
{
// If we are windowed, read the desktop mode and use the same format for
// the back buffer
//if ( m_bWindowed )
{
D3DAdapterInfo* pAdapterInfo = m_d3dSettings.PAdapterInfo();
m_pD3D->GetAdapterDisplayMode( pAdapterInfo->AdapterOrdinal, &m_d3dSettings.Windowed_DisplayMode );
m_d3dpp.BackBufferFormat = m_d3dSettings.Windowed_DisplayMode.Format;
}
//if ( FAILED( hr = Reset3DEnvironment() ) )
// return hr;
return hr;
}
m_bDeviceLost = FALSE;
}
}
*/
// draw whole of screen
if (pd3dDevice->Present(&rClient, &rClient, NULL, NULL) == D3DERR_DEVICELOST)
{
//MessageBox(NULL, "D3DERR_DEVICELOST", "", MB_OK);
m_bDeviceLost = TRUE;
}
// success
return TRUE;
}
///////////////////////////////////////////
// Set a new render target //
///////////////////////////////////////////
BOOL _SetNewRenderTarget(int hSurfaceHandle)
{
int iSurface;
// check it isn't already selected
if (hSurfaceHandle == hCurrentSurfaceHandleSelected)
{
// already selected so just return
return TRUE;
}
// remember the surface that is now selected
hCurrentSurfaceHandleSelected = hSurfaceHandle;
// is it the back buffer (HANDLES_START_AT) or an offscreen surface (> HANDLES_START_AT)
if (hSurfaceHandle == BACK_BUFFER)
{
// back buffer
if (pd3dDevice->SetRenderTarget(0, backBufferTarget) != D3D_OK)
{
ALERT("Failed to set back buffer as render target", "_SetNewRenderTarget");
return FALSE;
}
}
else
{
// offscreen surface, so calculate this surfaces's array index
iSurface = _GetSurfaceArrayIndexFromHandle(hSurfaceHandle);
IDirect3DSurface9* pSurface;
pListOfOffscreenSurfaces[iSurface].pSurfaceDX->GetSurfaceLevel(0, &pSurface);
if (pd3dDevice->SetRenderTarget(0, pSurface) != D3D_OK)
{
ALERT("Failed to set offscreen surface as render target", "_SetNewRenderTarget");
return FALSE;
}
}
// success
return TRUE;
}
///////////////////////////////////
// Clear a surface //
///////////////////////////////////
BOOL DX_ClearRect(RECT_F* pRect, int iRed, int iGreen, int iBlue, float fOpacity)
{
int iOpacity;
iOpacity = (int)(fOpacity * 255);
// clearing all or just a part?
if (pRect == NULL)
{
// clear all of the surface
if (pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(iOpacity, iRed, iGreen, iBlue), 1.0f, 0) != D3D_OK)
{
ALERT("Failed to clear surface", "B2D_ClearRect");
return FALSE;
}
}
else
{
// setup the rectangle to be cleared
D3DRECT d3Rect;
d3Rect.x1 = (long)pRect->left;
d3Rect.x2 = (long)pRect->right;
d3Rect.y1 = (long)pRect->top;
d3Rect.y2 = (long)pRect->bottom;
// clear the surface
if (pd3dDevice->Clear(1, &d3Rect, D3DCLEAR_TARGET, D3DCOLOR_ARGB(iOpacity, iRed, iGreen, iBlue), 1.0f, 0) != D3D_OK)
{
ALERT("Failed to clear surface", "B2D_ClearRect");
return FALSE;
}
}
// success
return TRUE;
}
///////////////////////////////
// BLT surface //
///////////////////////////////
BOOL DX_BltSurfaceStretched(int hSurfaceHandle, RECT_F* pSrc, RECT_F* pDest)
{
RECT rSource;
RECT rDestination;
int iSurface;
// check that a valid surface handle was sent
if (_CheckValidSurfaceHandle(hSurfaceHandle, "DX_BltSurfaceStretched") == FALSE)
{
return FALSE;
}
// calculate this surfaces's array index
iSurface = _GetSurfaceArrayIndexFromHandle(hSurfaceHandle);
// was a source rect specified?
if (pSrc == NULL)
{
// no, so just use the whole size of the surface
rSource.left = 0;
rSource.right = pListOfOffscreenSurfaces[iSurface].iWidth;
rSource.top = 0;
rSource.bottom = pListOfOffscreenSurfaces[iSurface].iHeight;
}
else
{
// yes, so use the rect that was specified
rSource.left = (long)pSrc->left;
rSource.right = (long)pSrc->right;
rSource.top = (long)pSrc->top;
rSource.bottom = (long)pSrc->bottom;
}
// destination
rDestination.left = (long)pDest->left;
rDestination.right = (long)pDest->right;
rDestination.top = (long)pDest->top;
rDestination.bottom = (long)pDest->bottom;
// stop the coordinates from going negative (and crashing StretchRect!) by adjusting the source rect
if (rDestination.left < 0)
{
rSource.left -= (long)pDest->left;
rDestination.left = 0;
}
if (rDestination.top < 0)
{
rSource.top -= (long)pDest->top;
rDestination.top = 0;
}
// check anything is being drawn at all
if (rSource.left >= rSource.right
|| rSource.top >= rSource.bottom)
{
return TRUE;
}
if (rDestination.left >= rDestination.right
|| rDestination.top >= rDestination.bottom)
{
return TRUE;
}
// BLTing to the back buffer or an offscreen surface?
if (hCurrentSurfaceHandleSelected == BACK_BUFFER)
{
// do the stretch BLT to the back buffer using StretchRect so it's stretched better (and it doesn't need transparency anyway)
IDirect3DSurface9* pSurface;
pListOfOffscreenSurfaces[iSurface].pSurfaceDX->GetSurfaceLevel(0, &pSurface);
if (pd3dDevice->StretchRect(pSurface,
&rSource,
backBufferTarget,
&rDestination,
D3DTEXF_LINEAR) != D3D_OK)
//D3DTEXF_NONE) != D3D_OK)
{
ALERT("Failed to StretchRect to back buffer", "DX_BltSurfaceStretched");
return FALSE;
}
}
else
{
// do the stretch BLT to offscreen buffers using quads so that it can make use of transparency
CUSTOMVERTEX* vertices;
// lock the vertex buffer
if (FAILED(vertexBuffer->Lock(0, 0, (void**)&vertices, 0)))
{
ALERT("Failed to lock vertex buffer", "B2D_DrawImage");
return FALSE;
}
// create the color to set the opacity level
D3DCOLOR vertexColor = D3DCOLOR_ARGB(255, 255, 255, 255);
float x = pDest->left, y = pDest->top;
float fSizeX = pDest->right - pDest->left, fSizeY = pDest->bottom - pDest->top;
float fFromX = 0, fFromY = 0;
float fToX = 1, fToY = 1;
// setup vertices
vertices[0].color = vertexColor;
vertices[0].z = 0.0f;
vertices[0].rhw = 1.0f;
vertices[0].u = fFromX;
vertices[0].v = fFromY;
vertices[1].color = vertexColor;
vertices[1].z = 0.0f;
vertices[1].rhw = 1.0f;
vertices[1].u = fToX;
vertices[1].v = fFromY;
vertices[2].color = vertexColor;
vertices[2].z = 0.0f;
vertices[2].rhw = 1.0f;
vertices[2].u = fToX;
vertices[2].v = fToY;
vertices[3].color = vertexColor;
vertices[3].z = 0.0f;
vertices[3].rhw = 1.0f;
vertices[3].u = fFromX;
vertices[3].v = fToY;
// A -0.5f modifier is applied to vertex coordinates to match texture
// and screen coords. Some drivers may compensate for this
// automatically, but on others texture alignment errors are introduced
// More information on this can be found in the Direct3D 9 documentation
// no rotation
vertices[0].x = x - 0.5f;
vertices[0].y = y - 0.5f;
vertices[1].x = x + fSizeX - 0.5f;
vertices[1].y = y - 0.5f;
vertices[2].x = x + fSizeX - 0.5f;
vertices[2].y = y + fSizeY - 0.5f;
vertices[3].x = x - 0.5f;
vertices[3].y = y + fSizeY - 0.5f;
// unlock the vertex buffer
vertexBuffer->Unlock();
// select this texture
if (pd3dDevice->SetTexture(0, pListOfOffscreenSurfaces[iSurface].pSurfaceDX) != S_OK)
{
ALERT("Failed to set texture", "DX_DrawImage");
return FALSE;
}
hImageHandleSelectedDX = -1;
// draw image
if (pd3dDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2) != S_OK)
{
ALERT("Failed to draw image", "DX_DrawImage");
return FALSE;
}
}
// success
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////////////
// Draw a textured quad on the back-buffer or a Render Target surface //
//////////////////////////////////////////////////////////////////////////////////////
BOOL DX_DrawImage(int hImageHandle, float x, float y, float fSizeX, float fSizeY, float fRotate, float fOpacity, float fFromX, float fFromY, float fToX, float fToY)
{
CUSTOMVERTEX* vertices;
int iImage;
int iSurface;
// check that a valid image handle was sent
if (hImageHandle < HANDLES_START_AT
|| hImageHandle >= HANDLES_START_AT + iNumberOfImagesLoaded)
{
ALERT("Invalid image handle", "B2D_DrawImage");
return FALSE;
}
// lock the vertex buffer
if (FAILED(vertexBuffer->Lock(0, 0, (void**)&vertices, 0)))
{
ALERT("Failed to lock vertex buffer", "B2D_DrawImage");
return FALSE;
}
// calculate this image's array index
iImage = hImageHandle - HANDLES_START_AT;
iSurface = _GetSurfaceArrayIndexFromHandle(hCurrentSurfaceHandleSelected);
// use actual size if -1 was sent as a parameter
if (fSizeX < 0)
{
fSizeX = (float)pListOfImages[iImage].iActualWidth;
}
if (fSizeY < 0)
{
fSizeY = (float)pListOfImages[iImage].iActualHeight;
}
// create the color to set the opacity level
D3DCOLOR vertexColor = D3DCOLOR_ARGB((int)(255*fOpacity), 255, 255, 255);
// setup vertices
vertices[0].color = vertexColor;
vertices[0].z = 0.0f;
vertices[0].rhw = 1.0f;
vertices[0].u = fFromX;
vertices[0].v = fFromY;
vertices[1].color = vertexColor;
vertices[1].z = 0.0f;
vertices[1].rhw = 1.0f;
vertices[1].u = fToX;
vertices[1].v = fFromY;
vertices[2].color = vertexColor;
vertices[2].z = 0.0f;
vertices[2].rhw = 1.0f;
vertices[2].u = fToX;
vertices[2].v = fToY;
vertices[3].color = vertexColor;
vertices[3].z = 0.0f;
vertices[3].rhw = 1.0f;
vertices[3].u = fFromX;
vertices[3].v = fToY;
// handle rotation
if (fRotate == 0)
{
// A -0.5f modifier is applied to vertex coordinates to match texture
// and screen coords. Some drivers may compensate for this
// automatically, but on others texture alignment errors are introduced
// More information on this can be found in the Direct3D 9 documentation
// no rotation
vertices[0].x = x - 0.5f;
vertices[0].y = y - 0.5f;
vertices[1].x = x + fSizeX - 0.5f;
vertices[1].y = y - 0.5f;
vertices[2].x = x + fSizeX - 0.5f;
vertices[2].y = y + fSizeY - 0.5f;
vertices[3].x = x - 0.5f;
vertices[3].y = y + fSizeY - 0.5f;
}
else
{
// calculate origin
float fTop, fBottom, fLeft, fRight;
fTop = -fSizeY/2;
fBottom = +fSizeY/2;
fLeft = -fSizeX/2;
fRight = +fSizeX/2;
// rotate vertices about the origin
float fCos, fSin;
fCos = cosf(fRotate/RADIANS);
fSin = sinf(fRotate/RADIANS);
vertices[0].x = fLeft * fCos -
fTop * fSin;
vertices[0].y = fLeft * fSin +
fTop * fCos;
vertices[1].x = fRight * fCos -
fTop * fSin;
vertices[1].y = fRight * fSin +
fTop * fCos;
vertices[2].x = fRight * fCos -
fBottom * fSin;
vertices[2].y = fRight * fSin +
fBottom * fCos;
vertices[3].x = fLeft * fCos -
fBottom * fSin;
vertices[3].y = fLeft * fSin +
fBottom * fCos;
// translate vertices to proper position
vertices[0].x += x;
vertices[0].y += y;
vertices[1].x += x;
vertices[1].y += y;
vertices[2].x += x;
vertices[2].y += y;
vertices[3].x += x;
vertices[3].y += y;
}
// unlock the vertex buffer
vertexBuffer->Unlock();
// set this image as the texture (unless this texture is already selected!)
if (hImageHandleSelectedDX != hImageHandle)
{
// remember that this texture is now selected
hImageHandleSelectedDX = hImageHandle;
// select this texture
if (pd3dDevice->SetTexture(0, pListOfImages[iImage].pImageDX) != S_OK)
{
ALERT("Failed to set texture", "DX_DrawImage");
return FALSE;
}
}
// draw image
if (pd3dDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2) != S_OK)
{
ALERT("Failed to draw image", "DX_DrawImage");
return FALSE;
}
// success
return TRUE;
}
///////////////////////////////
// Draw a line //
///////////////////////////////
BOOL DX_DrawLine(float fFromX, float fFromY, float fToX, float fToY, float fWidth, int iRed, int iGreen, int iBlue, int iOpacity)
{
BOOL bReturn;
int iCurrentSurface;
bReturn = TRUE;
// get array index of currently selected surface
iCurrentSurface = _GetSurfaceArrayIndexFromHandle(hCurrentSurfaceHandleSelected);
// setup
LPD3DXLINE line;
pFunc_PD3DXCreateLine(pd3dDevice, &line);
D3DXVECTOR2 lines[] = {D3DXVECTOR2(0.5f + fFromX, 0.5f + fFromY),
D3DXVECTOR2(0.5f + fToX, 0.5f + fToY)};
//D3DXVECTOR2 lines[] = {D3DXVECTOR2( (float)fFromX, (float)fFromY),
// D3DXVECTOR2( (float)fToX, (float)fToY)};
line->SetWidth(fWidth);
line->SetAntialias(pListOfOffscreenSurfaces[iCurrentSurface].bAntiAlias);
// draw
line->Begin();
if (line->Draw(lines, 2, D3DCOLOR_RGBA(iRed,
iGreen,
iBlue,
iOpacity)) != D3D_OK)
{
ALERT("Failed to draw line", "DX_DrawLine");
bReturn = FALSE;
}
line->End();
// release
line->Release();
// success
return bReturn;
}
/////////////////////////////
// Draw Text //
/////////////////////////////
BOOL DX_DrawTextEx(char* szString, float x, float y, RECT_F* pRect, int iAlignment, int iRed, int iGreen, int iBlue, int iOpacity)
{
// TODO: use D3DFont instead?
int iCurrentSurface;
int iCurrentFont;
RECT rPosition;
// get array index of currently selected surface
iCurrentSurface = _GetSurfaceArrayIndexFromHandle(hCurrentSurfaceHandleSelected);
// clear background if a rect was specified
if (pRect != NULL)
{
// clear rect
D3DRECT d3Rect;
d3Rect.x1 = (long)pRect->left;
d3Rect.x2 = (long)pRect->right;
d3Rect.y1 = (long)pRect->top;
d3Rect.y2 = (long)pRect->bottom;
if (pListOfOffscreenSurfaces[iCurrentSurface].iBackgroundOpacity > 0)
{
if (pd3dDevice->Clear(1,
&d3Rect,
D3DCLEAR_TARGET,
D3DCOLOR_XRGB(pListOfOffscreenSurfaces[iCurrentSurface].iBackgroundRed,
pListOfOffscreenSurfaces[iCurrentSurface].iBackgroundGreen,
pListOfOffscreenSurfaces[iCurrentSurface].iBackgroundBlue),
1.0f,
0) != D3D_OK)
{
ALERT("Failed to clear opaque background", "DX_DrawText");
return FALSE;
}
}
// position text in this box
rPosition.left = (long)pRect->left;
rPosition.right = (long)pRect->right;
rPosition.top = (long)pRect->top;
rPosition.bottom = (long)pRect->bottom;
}
else
{
// position text in this box
if ((iAlignment & DT_RIGHT) == DT_RIGHT)
{
rPosition.left = (long)x-1280;
rPosition.right = (long)x;
}
else if ((iAlignment & DT_CENTER) == DT_CENTER)
{
rPosition.left = (long)x-1280;
rPosition.right = (long)x+1280;
}
else
{
rPosition.left = (long)x;
rPosition.right = (long)x+1280;
}
if ((iAlignment & DT_BOTTOM) == DT_BOTTOM)
{
rPosition.top = (long)y-1280;
rPosition.bottom = (long)y;
}
else if ((iAlignment & DT_VCENTER) == DT_VCENTER)
{
rPosition.top = (long)y-1280;
rPosition.bottom = (long)y+1280;
}
else
{
rPosition.top = (long)y;
rPosition.bottom = (long)y+1280;
}
}
// set the font color
D3DCOLOR fontColor;
fontColor = D3DCOLOR_RGBA(iRed,
iGreen,
iBlue,
iOpacity);
// draw text
iCurrentFont = pListOfOffscreenSurfaces[iCurrentSurface].hFontHandleSelected - HANDLES_START_AT;
if (pListOfFonts[iCurrentFont].pFontDX->DrawText(NULL,
szString,
-1,
&rPosition,
iAlignment,
fontColor) == 0)
{
ALERT("Failed to draw text", "DX_DrawText");
return FALSE;
}
// success
return TRUE;
}
////////////////////////
// Misc //
////////////////////////
int _GetSurfaceArrayIndexFromHandle(int hSurfaceHandle)
{
return hSurfaceHandle - HANDLES_START_AT;
}
BOOL _CheckValidSurfaceHandle(int hSurfaceHandle, const char* szFunction)
{
// make sure handle is between HANDLES_START_AT and HANDLES_START_AT+iNumberOfOffscreenSurfacesCreated
if (hSurfaceHandle < HANDLES_START_AT
|| hSurfaceHandle >= HANDLES_START_AT + iNumberOfOffscreenSurfacesCreated)
{
// fail
ALERT("Invalid surface handle", szFunction);
return FALSE;
}
// success
return TRUE;
}
BOOL _CheckDrawingHasStarted(const char* szFunctionName)
{
// make sure a surface has been selected to draw to
if (hCurrentSurfaceHandleSelected == 0)
{
// fail
ALERT("Drawing has not been started!", szFunctionName);
return FALSE;
}
// success
return TRUE;
}
BOOL _CheckBlitz2DHasStarted(const char* szFunctionName)
{
if (bBlitz2DStarted == FALSE)
{
// fail
ALERT("Blitz2D has not been started!", szFunctionName);
return FALSE;
}
// success
return TRUE;
}
////////////////////////////////////////////////////////
// Set default values for a new surface //
////////////////////////////////////////////////////////
void _ResetSurfaceAttributesToDefaults(int hSurfaceHandle)
{
int i;
// calculate the array index
i = _GetSurfaceArrayIndexFromHandle(hSurfaceHandle);
// set the defaults
pListOfOffscreenSurfaces[i].iRed = 255; // white text/lines
pListOfOffscreenSurfaces[i].iGreen = 255;
pListOfOffscreenSurfaces[i].iBlue = 255;
pListOfOffscreenSurfaces[i].iOpacity = 255;
pListOfOffscreenSurfaces[i].iBackgroundRed = 0; // black background
pListOfOffscreenSurfaces[i].iBackgroundGreen = 0;
pListOfOffscreenSurfaces[i].iBackgroundBlue = 0;
pListOfOffscreenSurfaces[i].iBackgroundOpacity = 255;
pListOfOffscreenSurfaces[i].bAntiAlias = TRUE; // anti-aliasing
pListOfOffscreenSurfaces[i].hFontHandleSelected = HANDLES_START_AT; // use the default font
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment