DBP images use DX surfaces which once locked can be accessed directly. Here's a little snippet I played around with some time ago that might help you out...
Basically you lock the surface and grab the parameters of it including the pointer to directly manipulate the pixel data.
#include "windows.h"
#include "commctrl.h"
#include "DBP-entry.h"
#include "DBPro.hpp"
#include "d3dx9.h"
#include "main.h"
int GetMemOffset(int format)
{
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;
}
EXPORTC void ImageDot(int ImageID, 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;
DBPro::GetImageTexturePtr(ImageID)->GetSurfaceLevel(0, &DestSurface);
DestSurface->GetDesc(&DestDesc);
DestSurface->LockRect(&DestRect, 0, 0);
DestAddr = (unsigned char*)DestRect.pBits;
w = DBPro::ImageWidth(ImageID);
h = DBPro::ImageHeight(ImageID);
b = GetMemOffset(DestDesc.Format);
if (x >= 0 && x <= w && y >= 0 && y <= h) {
dmem_loc = (x * b) + ((y) * DestRect.Pitch);
*(DWORD*)(DestAddr + dmem_loc) = c;
}
DestSurface->UnlockRect();
DestSurface->Release();
DestSurface = 0;
}
EXPORTC void ImageWrappedDot(int ImageID, 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;
DBPro::GetImageTexturePtr(ImageID)->GetSurfaceLevel(0, &DestSurface);
DestSurface->GetDesc(&DestDesc);
DestSurface->LockRect(&DestRect, 0, 0);
DestAddr = (unsigned char*)DestRect.pBits;
w = DBPro::ImageWidth(ImageID);
h = DBPro::ImageHeight(ImageID);
b = GetMemOffset(DestDesc.Format);
x %= w; y %= h;
dmem_loc = (x * b) + ((y) * DestRect.Pitch);
*(DWORD*)(DestAddr + dmem_loc) = c;
DestSurface->UnlockRect();
DestSurface->Release();
DestSurface = 0;
}
EXPORTC void ImagePasteToImage(int Src, int Dst, int DstX, int DstY)
{
LPDIRECT3DSURFACE9 SrcSurface = 0;
D3DLOCKED_RECT SrcRect;
D3DSURFACE_DESC SrcDesc;
LPDIRECT3DSURFACE9 DstSurface = 0;
D3DLOCKED_RECT DstRect;
D3DSURFACE_DESC DstDesc;
unsigned char *SrcAddr, *DstAddr;
if ( 0 == DBPro::ImageExist(Src) ) return; // if either image doesn't exist
if ( 0 == DBPro::ImageExist(Dst) ) return;
DBPro::GetImageTexturePtr(Src)->GetSurfaceLevel(0, &SrcSurface); // DX surface stuff
DBPro::GetImageTexturePtr(Dst)->GetSurfaceLevel(0, &DstSurface);
int SrcW = DBPro::ImageWidth(Src);
int SrcH = DBPro::ImageHeight(Src);
int DstW = DBPro::ImageWidth(Dst);
int DstH = DBPro::ImageHeight(Dst);
if ( DstX > DstW || DstY > DstH ) return; // if out of image area
if ( DstX + SrcW < 0 || DstY + SrcH < 0 ) return;
int SrcXOffset = 0, SrcYOffset = 0; // needed to clip source image
if ( DstX < 0 )
{
SrcW += DstX;
if ( SrcW < 1 ) return; // out of image area
SrcXOffset = -DstX;
DstX = 0;
}
if ( DstY < 0 )
{
SrcH += DstY;
if ( SrcH < 1 ) return; // out of image area
SrcYOffset = -DstY;
DstY = 0;
}
if ( DstX + SrcW > DstW )
{
SrcW -= ( DstX + SrcW - DstW );
if ( SrcW < 1 ) return;
}
if ( DstY + SrcH > DstH )
{
SrcH -= ( DstY + SrcH - DstH );
if ( SrcH < 1 ) return;
}
DstSurface->GetDesc(&DstDesc);
DstSurface->LockRect(&DstRect, 0, 0);
DstAddr = (unsigned char*)DstRect.pBits;
int DstOffset = GetMemOffset(DstDesc.Format);
SrcSurface->GetDesc(&SrcDesc);
SrcSurface->LockRect(&SrcRect, 0, 0);
SrcAddr = (unsigned char*)SrcRect.pBits;
int SrcOffset = GetMemOffset(SrcDesc.Format);
int SrcPitch = SrcRect.Pitch;
int DstPitch = DstRect.Pitch;
unsigned char *SrcPtr, *DstPtr;
int y;
for ( y = 0; y < SrcH; y++ )
{
SrcPtr = ( y + SrcYOffset ) * SrcPitch + ( SrcXOffset * SrcOffset) + SrcAddr;
DstPtr = ( y + DstY ) * DstPitch + ( DstX * DstOffset ) + DstAddr;
#ifndef WL_OPTIMISE_ASM
int x;
for ( x = 0; x < SrcW; x++ )
{
*(DWORD*)DstPtr = *(DWORD*)SrcPtr;
DstPtr += DstOffset;
SrcPtr += SrcOffset;
}
#else
__asm {
mov edx, [DstPtr]
mov ecx, [SrcPtr]
mov ebx, [SrcW]
innerloop: mov eax, [ecx]
mov [edx], eax
add edx, 4
add ecx, 4
dec ebx
jne innerloop
}
#endif
}
DstSurface->UnlockRect();
DstSurface->Release();
DstSurface = 0;
SrcSurface->UnlockRect();
SrcSurface->Release();
SrcSurface = 0;
return;
}
EXPORTC void MakeBlankImage(int ImageID, int Width, int Height)
{
DBPro::MakeImage(ImageID, Width, Height);
}
EXPORTC void ImageCls(int ImageID, DWORD colour)
{
LPDIRECT3DSURFACE9 DestSurface = 0;
D3DLOCKED_RECT DestRect;
D3DSURFACE_DESC DestDesc;
int w, h;
unsigned char *DestAddr;
DBPro::GetImageTexturePtr(ImageID)->GetSurfaceLevel(0, &DestSurface);
DestSurface->GetDesc(&DestDesc);
DestSurface->LockRect(&DestRect, 0, 0);
DestAddr = (unsigned char*)DestRect.pBits;
w = DBPro::ImageWidth(ImageID);
h = DBPro::ImageHeight(ImageID);
int pitch = DestRect.Pitch;
//int b = GetMemOffset(DestDesc.Format); // using 4 bytes at mo
#ifndef WL_OPTIMISE_ASM
while ( h-- )
{
DWORD *ptr = (DWORD*)DestAddr;
int loop = w;
while ( loop-- )
{
*ptr++ = colour;
}
DestAddr += pitch;
}
#else
__asm {
mov eax, [colour]
mainloop: mov edx, [DestAddr]
mov ecx, [w]
innerloop: mov [edx], eax
add edx, 4
dec ecx
jne innerloop
mov edx, [pitch]
add [DestAddr], edx
dec [h]
jne mainloop
}
#endif
DestSurface->UnlockRect();
DestSurface->Release();
DestSurface = 0;
return;
}
EXPORTC void ImageFillRect(int ImageID, int x, int y, int w, int h, int colour)
{
LPDIRECT3DSURFACE9 DestSurface = 0;
D3DLOCKED_RECT DestRect;
D3DSURFACE_DESC DestDesc;
unsigned char *DestAddr;
int ImageWid = DBPro::ImageWidth(ImageID);
int ImageHgt = DBPro::ImageHeight(ImageID);
// Check rect boundaries
if ( x >= ImageWid || y >= ImageHgt ) return;
if ( x + w < 0 || y + h < 0 ) return;
if ( x + w > ImageWid ) w -= ( x + w - ImageWid );
if ( y + h > ImageHgt ) h -= ( y + h - ImageHgt );
if ( x < 0 ) { w += x; x = 0; }
if ( y < 0 ) { h += y; y = 0; }
if ( w < 1 ) return;
if ( h < 1 ) return;
DBPro::GetImageTexturePtr(ImageID)->GetSurfaceLevel(0, &DestSurface);
DestSurface->GetDesc(&DestDesc);
DestSurface->LockRect(&DestRect, 0, 0);
DestAddr = (unsigned char*)DestRect.pBits;
int pitch = DestRect.Pitch;
int poff = GetMemOffset(DestDesc.Format);
DestAddr += ( x * poff ) + ( y * pitch );
#ifndef WL_OPTIMISE_ASM
DWORD *ptr;
int loopw;
while ( h-- )
{
ptr = (DWORD*)DestAddr;
loopw = w;
while ( loopw-- )
{
*ptr++ = colour;
}
DestAddr += pitch;
}
#else
// This optimisation improved speed on my laptop from 90 FPS up to 100 FPS
__asm {
mov eax, [colour]
mainloop: mov edx, [DestAddr]
mov ecx, [w]
innerloop: mov [edx], eax
add edx, 4
dec ecx
jne innerloop
mov edx, [pitch]
add [DestAddr], edx
dec [h]
jne mainloop
}
#endif
DestSurface->UnlockRect();
DestSurface->Release();
DestSurface = 0;
return;
}
/* Useful references:
Advanced SSE/MMX Alpha blending - http://my.opera.com/Vorlath/blog/2006/12/20/project-v-advanced-alpha-blending
General Alpha blending - http://stackoverflow.com/questions/1102692/how-to-do-alpha-blend-fast
Normal C Alpha blend algorithm:
unsigned int AlphaBlend(const unsigned int bg, const unsigned int src)
{
unsigned int a = src >> 24; // alpha
// If source pixel is transparent, just return the background
if (0 == a)
return bg;
// alpha blending the source and background colors
unsigned int rb = (((src & 0x00ff00ff) * a) +
((bg & 0x00ff00ff) * (0xff - a))) & 0xff00ff00;
unsigned int g = (((src & 0x0000ff00) * a) +
((bg & 0x0000ff00) * (0xff - a))) & 0x00ff0000;
return (src & 0xff000000) | ((rb | g) >> 8);
}
*/
EXPORTC void ImagePasteToImageAlpha(int Src, int Dst, int DstX, int DstY)
{
LPDIRECT3DSURFACE9 SrcSurface = 0;
D3DLOCKED_RECT SrcRect;
D3DSURFACE_DESC SrcDesc;
LPDIRECT3DSURFACE9 DstSurface = 0;
D3DLOCKED_RECT DstRect;
D3DSURFACE_DESC DstDesc;
unsigned char *SrcAddr, *DstAddr;
if ( 0 == DBPro::ImageExist(Src) ) return; // if either image doesn't exist
if ( 0 == DBPro::ImageExist(Dst) ) return;
DBPro::GetImageTexturePtr(Src)->GetSurfaceLevel(0, &SrcSurface); // DX surface stuff
DBPro::GetImageTexturePtr(Dst)->GetSurfaceLevel(0, &DstSurface);
int SrcW = DBPro::ImageWidth(Src);
int SrcH = DBPro::ImageHeight(Src);
int DstW = DBPro::ImageWidth(Dst);
int DstH = DBPro::ImageHeight(Dst);
if ( DstX > DstW || DstY > DstH ) return; // if out of image area
if ( DstX + SrcW < 0 || DstY + SrcH < 0 ) return;
int SrcXOffset = 0, SrcYOffset = 0; // needed to clip source image
if ( DstX < 0 )
{
SrcW += DstX;
if ( SrcW < 1 ) return; // out of image area
SrcXOffset = -DstX;
DstX = 0;
}
if ( DstY < 0 )
{
SrcH += DstY;
if ( SrcH < 1 ) return; // out of image area
SrcYOffset = -DstY;
DstY = 0;
}
if ( DstX + SrcW > DstW )
{
SrcW -= ( DstX + SrcW - DstW );
if ( SrcW < 1 ) return;
}
if ( DstY + SrcH > DstH )
{
SrcH -= ( DstY + SrcH - DstH );
if ( SrcH < 1 ) return;
}
DstSurface->GetDesc(&DstDesc);
DstSurface->LockRect(&DstRect, 0, 0);
DstAddr = (unsigned char*)DstRect.pBits;
int DstOffset = GetMemOffset(DstDesc.Format);
SrcSurface->GetDesc(&SrcDesc);
SrcSurface->LockRect(&SrcRect, 0, 0);
SrcAddr = (unsigned char*)SrcRect.pBits;
int SrcOffset = GetMemOffset(SrcDesc.Format);
int SrcPitch = SrcRect.Pitch;
int DstPitch = DstRect.Pitch;
unsigned char *SrcPtr, *DstPtr;
int y;
unsigned int src;
unsigned int a; // using x86 register
unsigned int rb;
unsigned int g; // using x86 register
unsigned int bg;
unsigned int nega;
for ( y = 0; y < SrcH; y++ )
{
SrcPtr = ( y + SrcYOffset ) * SrcPitch + ( SrcXOffset * SrcOffset) + SrcAddr;
DstPtr = ( y + DstY ) * DstPitch + ( DstX * DstOffset ) + DstAddr;
int x;
#ifndef WL_OPTIMISE_ASM
for ( x = 0; x < SrcW; x++ )
{
src = *(DWORD*)SrcPtr;
a = src >> 24;
if ( a ) // if alpha is 0 then don't do anything
{
bg = *(DWORD*)DstPtr;
rb = (((src & 0x00ff00ff) * a) + ((bg & 0x00ff00ff) * (0xff - a))) & 0xff00ff00;
g = (((src & 0x0000ff00) * a) + ((bg & 0x0000ff00) * (0xff - a))) & 0x00ff0000;
*(DWORD*)DstPtr = (src & 0xff000000) | ((rb | g) >> 8);
}
DstPtr += DstOffset;
SrcPtr += SrcOffset;
}
#else
__asm {
mov eax, [SrcW] // setup main x loop
mov [x], eax
loopx:
mov ebx, [SrcPtr] // start pixel on line
mov eax, [ebx] // store pixel in Src
mov [src], eax
add ebx, 4 // next src pixel
mov [SrcPtr], ebx
shr eax, 24 // get alpha from pixel
je donothing // is alpha 0
mov edx, eax
// edx = ALPHA / ebx = bg / nega = (0xff - a)
// using registers for optimisation
mov eax, 0xff
sub eax, edx
mov [nega], eax
mov ebx, [DstPtr] // get background pixel bg
mov [bg], ebx
mov eax, [src] // process rb
and eax, 0x00ff00ff
mul edx
mov ecx, eax
mov eax, ebx
and eax, 0x00ff00ff
mul [nega]
add eax, ecx
and eax, 0xff00ff00
mov [rb], eax
mov eax, [src] // process g
and eax, 0x0000ff00
mul edx
mov ecx, eax
mov eax, ebx
and eax, 0x0000ff00
mul [nega]
add eax, ecx
and eax, 0x00ff0000
or eax, [rb] // put rb and g together
shr eax, 8
mov ecx, [src]
and ecx, 0xff000000
or eax, ecx
mov ecx, [DstPtr] // store new pixel
mov [ecx], eax
donothing:
mov eax, 4 // next pixel on dest line
mov [DstPtr], eax
mov eax, 1
add [x], eax
jne loopx
}
#endif
}
DstSurface->UnlockRect();
DstSurface->Release();
DstSurface = 0;
SrcSurface->UnlockRect();
SrcSurface->Release();
SrcSurface = 0;
return;
}
EXPORTC DWORD prepare_font(char* fname,int fsize,int fstyle)
{
font_def *fd = new font_def(fname,fsize,fstyle);
font_defs.push_back(fd);
return (DWORD)fd;
}
Mental arithmetic? Me? (That's for computers) I can't subtract a fart from a plate of beans!
Warning! May contain Nuts!