Created
June 26, 2022 11:38
-
-
Save aliakseis/482017335ee3d5942ca0af11b0f4cd71 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/////////////////////////////////////////////////////////////////////////////////// | |
// // | |
// 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