void dbGetBitmapData( int iID, DWORD* dwWidth, DWORD* dwHeight, DWORD* dwDepth, LPSTR* pData, DWORD* dwDataSize, bool bLockData );
Let's look at what these are and why they're needed. Notice that with a couple of exceptions it wants you to pass the address of various data elements. This is because the function is designed to return multiple pieces of data instead of one data type. So you pass it the address where you want it to put the data.
In the case of pData you're not passing a long pointer to a string. You're passing the address of a long pointer to a string into which the function will place an address.
To be honest, I've used this as part of a class that accesses image data and I have a comment by the side of my LPSTR pData that says "// not sure what this is but it's needed".
Looking at my code I can't see that I ever need to use that information beyond the need to provide a place to put it.
It's late and I don't have the time to dig out all the dependent support headers. However, at the risk of letting out code that needs to be treated gingerly, I'll provide the header and code for my image class just in case it might help. Some of the dependence is on my Bitmap class and at least a rectangle structure I've defined somewhere else so I'm providing this for instructional purposes. It will show you some techniques for accessing image data directly. I'm sure that bitmaps can be accessed pretty much the same way.
Image.h
/////////////////////////////////////
// Image class - header file
// Intent: To encapuslate the Dark GDK image as
// a class
// Author: Lilith
// Start Date: 02/23/08
#include "DarkGDK.h"
#include <string.h>
#include <Bitmap.h>
#include "windef.h"
#include <d3dx9.h>
#include "dbStuff.h"
#ifndef _IMAGE_H_LAC_
#define _IMAGE_H_LAC_
class Image
{
typedef struct ImageData{
DWORD width; // width of viewable area
DWORD height; // height of image
DWORD depth; // color depth in bits
DWORD size; // size of image in bytes
UINT pitch8; // number of bytes across in the image, regardless of width
UINT pitch32; // number of DWORDS across in the image, regardless of width
UINT8 bpp; // bits per pixel
DWORD *bytes; // pointer to beginning of image data for DWORD-sized data
LPDIRECT3DTEXTURE9 data; // pointer to the data structure for this image
void *imgPtr; // raw pointer to the image data
LPSTR pData; // not sure what this is but it's needed
D3DLOCKED_RECT imgData;
}ImageData;
private:
bool imageActive;
int iFlag;
bool locked;
ImageData thisImage;
DWORD fgColor; // foreground color for drawing
DWORD bgColor; // background color for clearing
char imageFile [128];
ImageData GetData (int imgnum);
protected:
static int nextImageNumber;
int imageNumber;
public:
Image ()
{
imageActive = false;
locked = false;
iFlag = 0;
imageNumber = nextImageNumber++;
thisImage.width = thisImage.height = thisImage.depth = thisImage.size = 0;
}
Image (char *file, int iflg = 0)
{
imageActive = false;
locked = false;
iFlag = iflg;
thisImage.width = thisImage.height = thisImage.depth = thisImage.size = 0;
imageNumber = nextImageNumber++;
iFlag = iflg;
strcpy (imageFile, file);
Load ();
}
Image (int w, int h)
{
imageNumber = nextImageNumber++;
thisImage.data = dbMakeImage (imageNumber, w, h);
thisImage = GetData(imageNumber);
}
~Image ()
{
if (Exist()) Delete(); // tells GDK to get rid of the image
// recovers the image number
if (imageNumber == (nextImageNumber -1)) nextImageNumber--;
}
operator int () {return imageNumber;} // returns image number as recognized by GDK
void SetFile (char *fname); // establishes file associated with image
bool Load (); // loads the file into the image
static UINT ColorKey(int r, int g, int b); // sets the color key for transparency on file load
void SetColors (DWORD fg, DWORD bg); // sets the foreground and background colors
DWORD SetForeground (DWORD fg); // sets only the foreground color, returns that color
DWORD SetBackground (DWORD bg); // sets only the background color, returns that color
void CopyImage (int imgnumber, int xpos, int ypos);
void CopyFromImage (int imgnumber, dbRect fromRect, int xpos, int ypos );
int Width (void); // returns the width of the image
int Height (void); // returns the height of the image
void Resize (int w, int h); // set the image to a new size
void Lock (void); // lock the surface for readwriting
void Unlock (void); // unlock the surface after readwrite
////////////////////////////////
// the Plot function places a dot at x/y of color clr
// it assumes that the surface is already locked
// the programmer is responsible for making sure that the image
// is locked before calling this function and unlocking it after the operation
// is complete. If a number of points are plotted, the locking and unlocking
// only needs to be done once
DWORD Plot (int x, int y, DWORD clr); // places a pixel of color clr at x/y
DWORD Point (int x, int y); // returns the pixel color at x/y
// the Dot function is similar to the Plot function except that it locks the image
// before each read or write
DWORD Dot (int x, int y); // place a dot of the foreground color on the image at x/y
DWORD Dot (int x, int y, DWORD clr); // places a dot of the given color at x/y on the image
// the GetDot function locks the image before each read
DWORD GetDot (int x, int y); // get the color of the dot at x/y on the image
DWORD Clr (void); // clears the image to the current background color
DWORD Clr (int clr); // clears the image to the specified color, returns the color
DWORD Line (int x1, int y1, int x2, int y2, DWORD clr); // draws a line in the specified color
DWORD Line (int x1, int y1, int x2, int y2); // draws a line using the current foreground color
DWORD Line(point a, point b); // draws a line from point a to point b using current background color
DWORD Line(point a, point b, DWORD clr); // draws a line from point a to point b using specified color
DWORD Box (int x1, int y1, int x2, int y2, bool fill = false);
// draws a box with top left corner at x1/y1 and bottom right corner at x2/y2
// uses foreground color, not filled by default
DWORD Box (int x1, int y1, int x2, int y2, DWORD clr, bool fill = false);
// draws a box with top left corner at x1/y1 and bottom right corner at x2/y2
// uses specified color, not filled by default
DWORD Circle (int cx, int cy, int radius, bool fill = false);
DWORD Circle (int cx, int cy, int radius, DWORD clr, bool fill = false);
DWORD Circle (point center, int radius, bool fill = false);
DWORD Circle (point center, int radius, DWORD clr, bool fill = false);
void PasteToScreen(int x, int y, int iflg = 0);
void PasteToBitmap(Bitmap bm, int x, int y);
void CopyFromBitmap(Bitmap bm, int left, int top, int right, int bottom, int texture = 1);
void CopyFromBitmap (Bitmap bm); // copies the entire bitmap
bool Exist ();
void Delete ();
};
#endif
Image.cpp
/////////////////////////////////////
// Image class - definition file
// Intent: To encapuslate the Dark GDK image as
// a class
// Author: Lilith
// Start Date: 02/23/08
#include "Utility.h"
#include "Bitmap.h"
#include "Image.h"
int Image::nextImageNumber = 1;
bool Image::Load()
{
if (dbFileExist(imageFile) == 0) return false;
dbLoadImage (imageFile, imageNumber, iFlag);
thisImage = GetData(imageNumber);
return true;
}
Image::ImageData Image::GetData(int imgnum)
{
ImageData temp;
if (Exist()){
// first get the easy data
dbGetImageData (imgnum, &temp.width, &temp.height, &temp.depth, &temp.pData, &temp.size, true);
// now get the pointer to the image/texture object
temp.data = dbGetImagePointer (imgnum);
temp.bpp = temp.depth / 8;
temp.pitch32 = temp.size / temp.height;
HRESULT result = temp.data->LockRect(0, &temp.imgData, NULL, 0);
if (result == D3D_OK) {
temp.imgPtr = temp.imgData.pBits;
temp.pitch8 = temp.imgData.Pitch;
temp.data->UnlockRect(0);
return temp;
}
} // if we got here then the image doesn't exist or wouldn't lock, return empty data
temp.width = temp.height = temp.size = temp.depth = temp.bpp = 0;
temp.pitch8 = 0;
temp.pData = NULL;
temp.data = NULL;
return temp;
}
int Image::Width (void)
{
return thisImage.width;
}
int Image::Height(void)
{
return thisImage.height;
}
void Image::Resize(int w, int h)
{
dbDeleteImage(imageNumber); // get rid of the old image
dbMakeImage(imageNumber, w, h); // create a new image of the requried size
thisImage = GetData(imageNumber); // realign the new parameters
}
void Image::CopyImage (int imgnumber, int xpos, int ypos)
{ // this function copies an image in its entirety
// to the xpos/ypos coordinates of the current image
ImageData src; // structure for information regarding source image
src = GetData (imgnumber);
src.data->LockRect(0, &src.imgData, NULL, 0);
Lock(); // lock the current image
src.pitch32 = src.imgData.Pitch / sizeof (DWORD);
// get the pointer to this image at x/y
DWORD *destPtr;
DWORD *srcPtr;
for (int row = 0; row < src.height; row++) {
srcPtr = (DWORD *)src.imgPtr + row * src.pitch32;
destPtr = thisImage.bytes + (ypos + row) * thisImage.pitch32 + xpos;
for (int col = 0; col < src.width; col++) {
*destPtr++ = *srcPtr++; // copy the row
}
}
Unlock();
src.data->UnlockRect(0);
}
void Image::CopyFromImage (int imgnumber, dbRect fromRect, int xpos, int ypos )
{ // this function copies a rectangle out of the source image
// to the xpos/ypos coordinates of the current image. clipping
// is applied to prevent over run.
// intermediate rectangle
// right/bottom is bogus for now
dbRect intRect (xpos, ypos, xpos, ypos);
ImageData src; // structure for information regarding source image
src = GetData (imgnumber);
// get the rectangle for the source image and clip it if necessary
// first check fromRect. if it's coords make it a point, adjust
// to copy the entire image.
if (fromRect.left == fromRect.right && fromRect.top == fromRect.bottom) {
fromRect.left = fromRect.top = 0; //
fromRect.width(src.width);
fromRect.height(src.height);
}
dbRect srcRect(0 > fromRect.left ? 0 : fromRect.left,
0 > fromRect.top ? 0 : fromRect.top,
src.width < fromRect.right ? src.width : fromRect.right,
src.height < fromRect.bottom ? src.height : fromRect.bottom);
// intermediate rectangle sits in the destination image with the
// coordinates of the left/top where the source image is to be placed
// the width is adjusted to that of the source image so we can adjust
// the final width/height to make sure it doesn't fall outside the
// the destination image
intRect.width(srcRect.width()); // adjust intermediate rectable to
intRect.height(srcRect.height()); // the dimensions of the source rect
dbRect finalRect (intRect.left > 0 ? intRect.left : 0,
intRect.top > 0 ? intRect.top : 0,
intRect.right < thisImage.width ? intRect.right : thisImage.width,
intRect.bottom < thisImage.height ? intRect.bottom : thisImage.height);
// if the resulting rectangle has no area we just quit right here
if (finalRect.width() == 0 || finalRect.height() == 0) return;
// otherwise, take the source and adjust its width/height to
// that of the final rectangle while keeping the same coordinates
srcRect.width(finalRect.width());
srcRect.height(finalRect.height());
// going into this assuming the src is locked already
Lock(); // lock the current image
src.data->LockRect(0, &src.imgData, NULL, 0);
src.pitch32 = src.imgData.Pitch / sizeof (DWORD);
// get the pointer to this image at x/y
DWORD *destPtr;
DWORD *srcPtr;
for (int row = srcRect.top; row < srcRect.height(); row++) {
srcPtr = (DWORD *)src.imgPtr + row * src.pitch32 + srcRect.left;
destPtr = thisImage.bytes + (ypos + (row - srcRect.top) ) * thisImage.pitch32 + xpos;
for (int col = 0; col < srcRect.width(); col++) {
*destPtr++ = *srcPtr++; // copy the row
}
}
Unlock();
src.data->UnlockRect(0);
}
UINT Image::ColorKey(int r, int g, int b)
{
dbSetImageColorKey (r, g, b);
return r << 16 | g << 8 | b;
}
void Image::SetColors (DWORD fg, DWORD bg)
{
fgColor = fg;
bgColor = bg;
}
DWORD Image::SetForeground (DWORD fg)
{
return fgColor = fg;
}
DWORD Image::SetBackground (DWORD bg)
{
return bgColor = bg;
}
void Image::Lock(void)
{
thisImage.data->LockRect(0, &thisImage.imgData, NULL, 0);
thisImage.imgPtr = thisImage.imgData.pBits;
thisImage.pitch32 = thisImage.imgData.Pitch / sizeof (DWORD);
thisImage.bytes = (DWORD *) thisImage.imgPtr;
locked = true;
}
void Image::Unlock(void)
{
thisImage.data->UnlockRect(0);
locked = false;
}
DWORD Image::Clr(void)
{
return Clr (bgColor);
}
DWORD Image::Clr (int clr)
{
Lock();
DWORD *ptr = thisImage.bytes;
for (int i = 0; i < thisImage.height * thisImage.pitch32; i++) *(ptr++) = clr;
Unlock();
return clr;
}
DWORD Image::Dot(int x, int y)
{ // if out of bounds, don't put
if (x < 0 || y < 0 || x > thisImage.width || y > thisImage.height) return 0;
Lock();
Plot(x, y, fgColor);
Unlock();
return fgColor;
}
DWORD Image::Dot(int x, int y, DWORD clr)
{ // if out of bounds, don't put
if (x < 0 || y < 0 || x > thisImage.width || y > thisImage.height) return 0;
Lock ();
Plot (x, y, clr);
Unlock();
return clr;
}
DWORD Image::GetDot(int x, int y)
{ // if out of bounds, return black
if (x < 0 || y < 0 || x > thisImage.width || y > thisImage.height) return 0;
Lock();
DWORD color = *(thisImage.bytes + y * thisImage.pitch32 + x);
Unlock();
return color;
}
DWORD Image::Plot(int x, int y, DWORD clr)
{ // puts color pixel at x/y coordinates. assumes image is locked
if (x >= 0 && x < thisImage.width && y >= 0 && y < thisImage.height) *(thisImage.bytes + y * thisImage.pitch32 + x) = clr ;
return clr;
}
DWORD Image::Point(int x, int y)
{
if (x >= 0 && x < thisImage.width && y >= 0 && y < thisImage.height) return *(thisImage.bytes + y * thisImage.pitch32 + x) ;
return 0;
}
DWORD Image::Line(int x0, int y0, int x1, int y1, DWORD clr)
{
Lock();
int dx = abs(x1 - x0),
dy = abs(y1 - y0);
bool steep = dy > dx;
if(steep)
{
std::swap(dx, dy);
std::swap(x0, y0);
std::swap(x1, y1);
}
int error = 0,
de = dy,
&x = steep ? y0 : x0,
&y = steep ? x0 : y0,
xstep = (x0 < x1) ? 1 : -1,
ystep = (y0 < y1) ? 1 : -1;
Plot(x, y, clr);
while(x0 != x1)
{
x0 += xstep;
error += de;
if( (error << 1) >= dx)
{
y0 += ystep;
error -= dx;
}
Plot(x, y, clr);
}
Unlock();
return clr;
}
DWORD Image::Line (int x1, int y1, int x2, int y2)
{
Line (x1, y1, x2, y2, fgColor);
return fgColor;
}
DWORD Image::Line(point a, point b)
{
Line(a.x, a.y, b.x, b.y, fgColor);
return fgColor;
}
DWORD Image::Line(point a, point b, DWORD clr)
{
Line(a.x, a.y, b.x, b.y, clr);
return clr;
}
DWORD Image::Box (int x1, int y1, int x2, int y2, bool fill)
{
Box(x1, y1, x2, y2, fgColor, fill);
return fgColor;
}
DWORD Image::Box (int x1, int y1, int x2, int y2, DWORD clr, bool fill)
{
Line(x1, y1, x2, y1, clr);
Line(x1, y2, x2, y2, clr);
if (fill) {
for (int row = y1+1; row < y2; row++)
Line (x1, row, x2, row, clr);
}else {
Line(x1, y1, x1, y2, clr);
Line(x2, y1, x2, y2, clr);
}
return clr;
}
DWORD Image::Circle (int cx, int cy, int radius, bool fill)
{
Circle (cx, cy, radius, fgColor, fill);
return fgColor;
}
DWORD Image::Circle (int cx, int cy, int radius, DWORD clr, bool fill)
{
Lock();
int xCenter=cx,yCenter=cy;
int x=0,y=radius;
int d=3-(2*radius);
while(x<=y){
Plot (xCenter+x,yCenter+y, clr);
Plot (xCenter+y,yCenter+x, clr);
Plot (xCenter-x,yCenter+y, clr);
Plot (xCenter+y,yCenter-x, clr);
Plot (xCenter-x,yCenter-y, clr);
Plot (xCenter-y,yCenter-x, clr);
Plot (xCenter+x,yCenter-y, clr);
Plot (xCenter-y,yCenter+x, clr);
if (fill) { // if we're doing a fill then we can
// TO DO : since these are horizontal lines we can probably
// speed things up by drawing a straight line using a pointer
// but make it a function
Line (xCenter+x + 1, yCenter+y, xCenter-x -1, yCenter+y, clr);
Line (xCenter+y + 1, yCenter+x, xCenter-y -1, yCenter+x, clr);
Line (xCenter+y + 1, yCenter-x, xCenter-y -1, yCenter-x, clr);
Line (xCenter-x + 1, yCenter-y, xCenter+x -1, yCenter-y, clr);
}
if (d<0)
d += (x << 2)+6;
else
{
d += ((x-y) << 2)+10;
y -= 1;
}
x++;
}
Unlock();
return clr;
}
DWORD Image::Circle (point center, int radius, bool fill)
{
Circle (center.x, center.y, radius, fgColor, fill);
return fgColor;
}
DWORD Image::Circle (point center, int radius, DWORD clr, bool fill)
{
Circle (center.x, center.y, radius, clr, fill);
return clr;
}
void Image::PasteToScreen (int x, int y, int iflag)
{
dbSetCurrentBitmap (Screen);
dbPasteImage (imageNumber, x, y, iflag);
}
void Image::PasteToBitmap (Bitmap n, int x, int y)
{
int currentBitmap = dbCurrentBitmap();
dbSetCurrentBitmap (n);
dbPasteImage (imageNumber, x, y);
dbSetCurrentBitmap(currentBitmap);
}
bool Image::Exist ()
{
return (dbImageExist(imageNumber) == 1);
}
void Image::Delete ()
{
if (Exist ()) dbDeleteImage(imageNumber);
}
void Image::SetFile(char *fname)
{
strcpy (imageFile, fname);
}
void Image::CopyFromBitmap(Bitmap bm, int left, int top, int right, int bottom, int texture)
{
dbSetCurrentBitmap (bm);
dbGetImage(imageNumber, left, top, right, left, texture);
}
void Image::CopyFromBitmap (Bitmap bm)
{
dbSetCurrentBitmap(bm);
dbGetImage(imageNumber, 0, 0, dbBitmapWidth(bm) - 1, dbBitmapHeight(bm) -1);
}
Lilith, Night Butterfly
I'm not a programmer but I play one in the office