Here are a few extensions I have written for DarkSDK to do some additional tasks. This is mainly simple stuff and tatters of them have been seen around the boards before but I figured it would be nice for me to put what I have in its entirity here to share
Some still need a little more work perhaps, I will put them all in my DarkSDK Collection post in the code snippets when I am content with them.
For now simply open up the code tags and place the code into appropriate files (header and cpp provided)
First the text extension - I have to thank Cloggy for this, its the text portion of his d3dextras dll he wrote for dbp. He shared the source with me on msn and I set about porting it to DarkSDK.
Text.h:
enum {
ALIGN_LEFT = 0,
ALIGN_CENTER,
ALIGN_RIGHT
};
void InitText();
void SetFont(int nFont, LPSTR pFont, int nFontSize, int nFontBold, int nFontItalic);
void StartText(void);
void EndText(void);
void AAText(int nFont, int x, int y, int nAlign, LPSTR pString);
void SetTextCol(int r, int g, int b, int a);
Text.cpp:
//#######################################
// Fast Antialiased Text
// Use instead of normal dbText()
//
// Thanks to Cloggy from tgc forums for
// the original dll code.
//
// Converted from dbp dll to DarkSDK
// addon by Sephnroth
//#######################################
#include "DarkSDK.h"
#include "d3d9.h"
int g_nRed=255;
int g_nGreen=255;
int g_nBlue=255;
int g_nAlpha=255;
int g_nFontSize;
bool g_Bold = false;
bool g_Italic = false;
char g_strFont[LF_FACESIZE];
ID3DXFont* g_pFont[20];
ID3DXFont* g_pFont2 = NULL;
ID3DXFont* g_pStatsFont = NULL;
IDirect3DDevice9* g_pd3dDevice = NULL;
ID3DXSprite* g_pTextSprite = NULL;
void InitText() {
g_pd3dDevice = dbGetDirect3DDevice();
}
void SetTextCol(int r, int g, int b, int a) {
g_nRed = r;
g_nGreen = g;
g_nBlue = b;
g_nAlpha = a;
}
void SetFont(int nFont, LPSTR pFont, int nFontSize, int nFontBold, int nFontItalic) {
HRESULT hr;
if (nFont > 20) {
return;
}
HDC hDC = GetDC(NULL);
int nLogPixelsY = GetDeviceCaps(hDC, LOGPIXELSY);
ReleaseDC(NULL, hDC);
int g_nFontSize = -nFontSize * nLogPixelsY / 72;
if (nFont == 1)
lstrcpy(g_strFont, pFont);
if (nFontBold == 1) {
g_Bold = true;
} else {
g_Bold = false;
}
if (nFontItalic == 1) {
g_Italic = true;
} else {
g_Italic = false;
}
hr = D3DXCreateFont( g_pd3dDevice, // D3D device
g_nFontSize, // Height
0, // Width
g_Bold ? FW_BOLD : FW_NORMAL, // Weight
1, // MipLevels, 0 = autogen mipmaps
g_Italic, // Italic
DEFAULT_CHARSET, // CharSet
OUT_DEFAULT_PRECIS, // OutputPrecision
DEFAULT_QUALITY, // Quality
DEFAULT_PITCH | FF_DONTCARE, // PitchAndFamily
pFont, // pFaceName
&g_pFont[nFont]); // ppFont
g_pFont[nFont]->PreloadGlyphs(32,180);
if (g_pTextSprite == NULL)
hr = D3DXCreateSprite( g_pd3dDevice, &g_pTextSprite );
}
void StartText(void) {
g_pTextSprite->Begin(D3DXSPRITE_ALPHABLEND | D3DXSPRITE_SORT_TEXTURE);
}
void EndText(void) {
g_pTextSprite->End();
}
void AAText(int nFont, int x, int y, int nAlign, LPSTR pString) {
RECT rc;
if (nFont > 20)
return;
SetRect(&rc, x, y, 0, 0 );
switch (nAlign) {
case 1:
{
g_pFont[nFont]->DrawText( g_pTextSprite, pString, -1, &rc, DT_CALCRECT, D3DCOLOR_ARGB( g_nAlpha, g_nRed, g_nGreen, g_nBlue ));
rc.left=x-((rc.right-x)/2);
rc.right=x+((rc.right-x)/2);
break;
}
case 2:
{
g_pFont[nFont]->DrawText( g_pTextSprite, pString, -1, &rc, DT_CALCRECT, D3DCOLOR_ARGB( g_nAlpha, g_nRed, g_nGreen, g_nBlue ));
rc.left=x-(rc.right-x);
rc.right=x+(rc.right-x);
break;
}
}
g_pFont[nFont]->DrawText( g_pTextSprite, pString, -1, &rc, DT_NOCLIP, D3DCOLOR_ARGB( g_nAlpha, g_nRed, g_nGreen, g_nBlue ));
}
You only need to InitText() once at the start of your program. Setup some fonts like you would create objects (you may want to make some constants for your font id's) and then simply call AAText() passing a font id to draw your text. You must call AAText() between StartText() and EndText() functions. Try and batch all your text in one go using only one Start/End block and you will get the best speed. You can use multiple blocks but the less you use the faster it will go - this is much faster than normal dbText(). You may use SetTextCol() to set the colour of the text at any time and you can set its alpha for transparent text! The header includes some constants for align codes which I recommend you use instead of passing just numbers to the AAText() function - makes it easier to read. Oh, and dont call any sdk commands which perform a drawing operation (dbBox() for example) inbetween StartText() and EndText() - it will only end in tears.
Primitives Extension - not many people may find a use for this one but I have. Adds a few extra objects which you can create. A ramp (you might want to call it a wedge), a paralellogram (like a ramp but has equal sized ends rather than one being a point) and also a 3d line which I cant take credit for because its from the Code Snippets forum, I simply ported it to darksdk.
ExtendedPrimitives.h:
#define vpx(x) dbGetVertexDataPositionX(x)
#define vpy(x) dbGetVertexDataPositionY(x)
#define vpz(x) dbGetVertexDataPositionZ(x)
#define LockVertex(o) dbLockVertexDataForLimb(o, 0)
#define UnlockVertex() dbUnlockVertexData()
#define SetVertex(v, xp, yp, zp) dbSetVertexDataPosition(v, xp, yp, zp)
void MakeObjectRamp(int id, float width, float height, float depth);
void MakeObjectParallelogram(int id, float width, float height, float depth);
void Make3DLine(int id, float X1, float Y1, float Z1, float X2, float Y2, float Z2, int col);
ExtendedPrimitives.cpp:
#include "DarkSDK.h"
#include "ExtendedPrimitives.h"
void MakeObjectRamp(int id, float width, float height, float depth) {
if (dbObjectExist(id))
dbDeleteObject(id);
dbMakeObjectBox(id, width, height, depth);
LockVertex(id);
SetVertex(0, vpx(0), vpy(3), vpz(0));
SetVertex(10, vpx(10), vpy(3), vpz(0));
SetVertex(20, vpx(20), vpy(3), vpz(20));
SetVertex(1, vpx(1), vpy(2), vpz(1));
SetVertex(11, vpx(11), vpy(2), vpz(11));
SetVertex(16, vpx(16), vpy(2), vpz(16));
UnlockVertex();
dbMakeMeshFromObject(1, id);
dbMakeObject(id, 1, 0);
}
void MakeObjectParallelogram(int id, float width, float height, float depth) {
if (dbObjectExist(id))
dbDeleteObject(id);
dbMakeObjectBox(id, width, height, depth);
LockVertex(id);
SetVertex(0, vpx(0), vpy(0) + height, vpz(0));
SetVertex(10, vpx(10), vpy(10) + height, vpz(10));
SetVertex(20, vpx(20), vpy(20) + height, vpz(20));
SetVertex(1, vpx(1), vpy(1) + height, vpz(1));
SetVertex(11, vpx(11), vpy(11) + height, vpz(11));
SetVertex(16, vpx(16), vpy(16) + height, vpz(16));
SetVertex(2, vpx(2), vpy(2) + height, vpz(2));
SetVertex(3, vpx(3), vpy(3) + height, vpz(3));
SetVertex(19, vpx(19), vpy(19) + height, vpz(19));
SetVertex(21, vpx(21), vpy(21) + height, vpz(21));
SetVertex(13, vpx(13), vpy(13) + height, vpz(13));
SetVertex(14, vpx(14), vpy(14) + height, vpz(14));
UnlockVertex();
dbMakeMeshFromObject(1, id);
dbMakeObject(id, 1, 0);
}
void Make3DLine(int id, float X1, float Y1, float Z1, float X2, float Y2, float Z2, int col) {
if (dbObjectExist(id))
dbDeleteObject(id);
dbMakeObjectTriangle(id, X1, Y1, Z1, X2, Y2, Z2, X2, Y2, Z2);
dbColorObject(id, col);
dbSetObjectWireframe(id, 1);
}
Finally, ExtendedImage. This will allow you to perform drawing operations into darkbasic Image types - usually you would have to call your drawing commands like Box etc onto a bitmap and then use GetImage() to make a texture out of it, you can draw streight to the image with these. The image must, naturally, exist.
You can draw pixels, lines and circles. Its pretty fast (fast enough for the dynamic texture generation in Iro) as it uses breshams-based integer maths functions instead of floating point.
ExtendedImage.h:
void PutImagePixel(int Dest, int x, int y, DWORD c);
void DrawImageLine(int Dest, int x1, int y1, int x2, int y2, DWORD c2);
void DrawImageCircle(int Dest, int CX, int CY, int R, DWORD c);
int GetMemOffset(int format);
ExtendedImage.cpp:
#include "DarkSDK.h"
#include "d3d9.h"
#include "ExtendedImage.h"
void PutImagePixel(int Dest, int x, int y, DWORD c) {
LPDIRECT3DSURFACE9 DestSurface = 0;
D3DLOCKED_RECT DestRect;
D3DSURFACE_DESC DestDesc;
int dmem_loc;
int w, h, b;
unsigned char *DestAddr;
dbGetImagePointer(Dest)->GetSurfaceLevel(0, &DestSurface);
DestSurface->GetDesc(&DestDesc);
DestSurface->LockRect(&DestRect, 0, 0);
DestAddr = (unsigned char*)DestRect.pBits;
w = dbGetImageWidth(Dest);
h = dbGetImageHeight(Dest);
b = GetMemOffset(DestDesc.Format);
if (x >= 0 && x < w-1 && y >= 0 && y < h-1) {
dmem_loc = (x * b) + ((y) * DestRect.Pitch);
*(DWORD*)(DestAddr + dmem_loc) = c;
}
DestSurface->UnlockRect();
DestSurface->Release();
DestSurface = 0;
}
void DrawImageLine(int Dest, int x1, int y1, int x2, int y2, DWORD c2) {
LPDIRECT3DSURFACE9 DestSurface = 0;
D3DLOCKED_RECT DestRect;
D3DSURFACE_DESC DestDesc;
int dmem_loc;
int w, h, b;
unsigned char *DestAddr;
dbGetImagePointer(Dest)->GetSurfaceLevel(0, &DestSurface);
DestSurface->GetDesc(&DestDesc);
DestSurface->LockRect(&DestRect, 0, 0);
DestAddr = (unsigned char*)DestRect.pBits;
w = dbGetImageWidth(Dest);
h = dbGetImageHeight(Dest);
b = GetMemOffset(DestDesc.Format);
int u = 0;
int dx, dy, c, M, xinc = 1, yinc = 1;
int hits=0;
int x3 = x1;
int y3 = y1;
dx = x2 - x1;
dy = y2 - y1;
if (dx < 0) { xinc = -1; dx = -dx; }
if (dy < 0) { yinc = -1; dy = -dy; }
if (dy < dx) {
c = 2 * dx;
M = 2 * dy;
while (x3 != x2) {
if (x3 >= 0 && x3 < w-1 && y3 >= 0 && y3 < h-1) {
dmem_loc = (x3 * b) + ((y3) * DestRect.Pitch);
*(DWORD*)(DestAddr + dmem_loc) = c2;
}
x3 += xinc;
u += M;
if (u > dx) { y3 += yinc; u -= c; }
}
} else {
c = 2 * dy;
M = 2 * dx;
while(y3 != y2) {
if (x3 >= 0 && x3 < w-1 && y3 >= 0 && y3 < h-1) {
dmem_loc = (x3 * b) + ((y3) * DestRect.Pitch);
*(DWORD*)(DestAddr + dmem_loc) = c2;
}
y3 += yinc;
u += M;
if(u > dy) { x3 += xinc; u -= c; }
}
}
if (x3 >= 0 && x3 < w-1 && y3 >= 0 && y3 < h-1) {
dmem_loc = (x3 * b) + ((y3) * DestRect.Pitch);
*(DWORD*)(DestAddr + dmem_loc) = c2;
}
DestSurface->UnlockRect();
DestSurface->Release();
DestSurface = 0;
}
void DrawImageCircle(int Dest, int CX, int CY, int R, DWORD c) {
LPDIRECT3DSURFACE9 DestSurface = 0;
D3DLOCKED_RECT DestRect;
D3DSURFACE_DESC DestDesc;
int dmem_loc;
int w, h;
unsigned char *DestAddr;
dbGetImagePointer(Dest)->GetSurfaceLevel(0, &DestSurface);
DestSurface->GetDesc(&DestDesc);
DestSurface->LockRect(&DestRect, 0, 0);
DestAddr = (unsigned char*)DestRect.pBits;
int X, Y;
int XChange, YChange;
int RadiusError;
X = R;
Y = 0;
XChange = 1 - 2 * R;
YChange = 1;
RadiusError = 0;
w = dbGetImageWidth(Dest);
h = dbGetImageHeight(Dest);
while(X > Y) {
/*
dbDot(CX+X, CY+Y);// {point in octant 1}
dbDot(CX-X, CY+Y);// {point in octant 4}
// dbDot(CX-X, CY-Y);// {point in octant 5}
// dbDot(CX+X, CY-Y);// {point in octant 8}
// dbDot(CX+Y, CY+X);// {point in octant 2}
// dbDot(CX-Y, CY+X);// {point in octant 3}
dbDot(CX-Y, CY-X);// {point in octant 6}
dbDot(CX+Y, CY-X);
*/
if (CX+X >= 0 && CX+X < w-1 && CY+Y >= 0 && CY+Y < h-1) {
dmem_loc = ((CX+X) * 4) + ((CY +Y) * DestRect.Pitch);
*(DWORD*)(DestAddr + dmem_loc) = c;
}
if (CX-X >= 0 && CX-X < w-1 && CY+Y >= 0 && CY+Y < h-1) {
dmem_loc = ((CX-X) * 4) + ((CY +Y) * DestRect.Pitch);
*(DWORD*)(DestAddr + dmem_loc) = c;
}
if (CX-X >= 0 && CX-X < w-1 && CY-Y >= 0 && CY-Y < h-1) {
dmem_loc = ((CX-X) * 4) + ((CY -Y) * DestRect.Pitch);
*(DWORD*)(DestAddr + dmem_loc) = c;
}
if (CX+X >= 0 && CX+X < w-1 && CY-Y >= 0 && CY-Y < h-1) {
dmem_loc = ((CX+X) * 4) + ((CY -Y) * DestRect.Pitch);
*(DWORD*)(DestAddr + dmem_loc) = c;
}
if (CX+Y >= 0 && CX+Y < w-1 && CY+X >= 0 && CY+X < h-1) {
dmem_loc = ((CX+Y) * 4) + ((CY +X) * DestRect.Pitch);
*(DWORD*)(DestAddr + dmem_loc) = c;
}
if (CX-Y >= 0 && CX-Y < w-1 && CY+X >= 0 && CY+X < h-1) {
dmem_loc = ((CX-Y) * 4) + ((CY +X) * DestRect.Pitch);
*(DWORD*)(DestAddr + dmem_loc) = c;
}
if (CX-Y >= 0 && CX-Y < w-1 && CY-X >= 0 && CY-X < h-1) {
dmem_loc = ((CX-Y) * 4) + ((CY -X) * DestRect.Pitch);
*(DWORD*)(DestAddr + dmem_loc) = c;
}
if (CX+Y >= 0 && CX+Y < w-1 && CY-X >= 0 && CY-X < h-1) {
dmem_loc = ((CX+Y) * 4) + ((CY -X) * DestRect.Pitch);
*(DWORD*)(DestAddr + dmem_loc) = c;
}
Y++;
RadiusError += YChange;
YChange += 2;
if (2 * RadiusError + XChange > 0 ) {
X--;
RadiusError += XChange;
XChange += 2;
}
}
DestSurface->UnlockRect();
DestSurface->Release();
DestSurface = 0;
}
int GetMemOffset(int format) {
//if (dbScreenDepth() == 16)
//return 3;
switch(format) {
case D3DFMT_R8G8B8:
return 3;
break;
case D3DFMT_A8R8G8B8:
return 4;
break;
case D3DFMT_X8R8G8B8:
return 4;
break;
case D3DFMT_R5G6B5:
return 2;
break;
case D3DFMT_X1R5G5B5:
return 2;
break;
case D3DFMT_A1R5G5B5:
return 2;
break;
case D3DFMT_A4R4G4B4:
return 2;
break;
case D3DFMT_R3G3B2:
return 1;
break;
case D3DFMT_A8:
return 1;
break;
case D3DFMT_A8R3G3B2:
return 2;
break;
case D3DFMT_X4R4G4B4:
return 2;
break;
case D3DFMT_A2B10G10R10:
return 4;
break;
case D3DFMT_A8B8G8R8:
return 4;
break;
case D3DFMT_X8B8G8R8:
return 4;
break;
case D3DFMT_G16R16:
return 4;
break;
case D3DFMT_A2R10G10B10:
return 4;
break;
}
return 0;
}
Despite my attempt at checking the format (as you can see) it still seems to have problems when the screen depth is set to 16 - not entirely sure why :/
Anyway! Hope they are usful to someone. I will add/improve as time goes by - if you make your own additions and improvments then let me know! Maybe we will one day end up with a big set of community made extensions