question with surfaces

Started by
7 comments, last by omegasyphon 23 years, 9 months ago
how do i load a sprite from a 24bit image file onto a 32bit surface? also if i set the bits per pixel to 32 when creating the full screen mode does that set all surfaces to 32bpp?
Advertisement
Normally, the only difference between a 32bpp and 24bpp surface is that the extra 8 bits is for the alpha ( transparency ) channel. You can set the alpha channel to maximum (255) unless you are planning to use alpha blending elsewhere. As for creating surfaces in 32BPP mode, if you don''t specify a pixel format ( presuming you''re using DirectX ) when creating the surface, the pixel format defaults to the pixel format of the primary ( display )surface. In this case it would be 32bpp. I hope this helps. If you do a display mode switch after surfaces are allocated, remember to reallocate/restore them.

himh
In your pic you have only r,g,b triples ranging from 0 to 256 thats the same for 16,24 and 32-bit modes.The color is than mixed according to the r,g,b-values.The difference between 24 and 32 bit mode is just a difference in resolution.In 32 bit the resulting color can be mixed more precise as in 16-bit-mode.
I am not sure what you mean with your second question:
If you only draw the bitmap onto a 2d-surface requesting a 32-bit-mode from windows is all you need to do.
If you texture-map a poly with the image you´ll have to request the 32-bit-mode and upload the texture with the correct attributes(Depends on the Api you´re using).
HTH,XBTC!
well here is what im trying to do. my program loads a background image and displays an image that is loaded from a 24bit file onto a 32bpp surface but when i run it the colors are all screwed up and i dont know why also how do flood fill the background buffer lpddsbackground with the black color instead of an image file



// INCLUDES ///////////////////////////////////////////////
#define WIN32_LEAN_AND_MEAN
#define INITGUID

#include (windows.h) // include important windows stuff
#include (windowsx.h)
#include (mmsystem.h)
#include (iostream.h) // include important C/C++ stuff
#include (conio.h)
#include (malloc.h)
#include (memory.h)
#include (io.h)
#include (ddraw.h) // directX includes

// defines for windows
#define WINDOW_CLASS_NAME "WINXCLASS" // class name

#define WWIDTH 640 // size of window
#define WHEIGHT 480
#define BPP 32
#define BITMAP_ID 0x4D42 // universal id for a bitmap
#define MAXCOLORS 256
// MACROS /////////////////////////////////////////////////

// these read the keyboard asynchronously
#define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEYUP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)
#define DDRAW_INIT_STRUCT(ddstruct) { memset(&ddstruct,0,sizeof(ddstruct)); ddstruct.dwSize=sizeof(ddstruct); }
// this builds a 16 bit color value in 5.6.5 format (green dominate mode)
#define RGB16BIT(r,g,b) ((b%32) + ((g%64) << 6) + ((r%32) << 11))
// this builds a 32 bit color value in A.8.8.8 format (8-bit alpha mode)
#define RGB32BIT(a,r,g,b) ((b) + ((g) << 8) + ((r) << 16) + ((a) << 24))


// TYPES //////////////////////////////////////////////////

typedef unsigned short USHORT;
typedef unsigned char UCHAR;

typedef struct BITMAP_FILE_TAG
{
BITMAPFILEHEADER bitmapfileheader;
BITMAPINFOHEADER bitmapinfoheader;
PALETTEENTRY palette[256];
UCHAR *buffer;
} BITMAPFILE, *BITMAPFILEPTR;

typedef struct BITMAPOBJTYP
{
int x,y;
LPDIRECTDRAWSURFACE4 image;
} BITMAPOBJ, *BITMAPOBJPTR;

////////// directdraw objects/////////////
LPDIRECTDRAW lpdd1 = NULL;
LPDIRECTDRAW4 lpdd4 = NULL;
LPDIRECTDRAWSURFACE4 lpddsprimary = NULL;
LPDIRECTDRAWSURFACE4 lpddsback = NULL;
DDSURFACEDESC2 ddsd;
DDSCAPS2 ddscaps;
BITMAPFILE bitmap;
BITMAPOBJ sprite;
LPDIRECTDRAWSURFACE4 lpddsbackground = NULL;// this will hold the background image


int gwidth = -1;
int gheight = -1;

// GLOBALS ////////////////////////////////////////////////

HWND main_window_handle = NULL; // save the window handle
HINSTANCE main_instance = NULL; // save the instance
char buffer[80]; // used to print text
int window_closed = 0; // tracks if window is closed

// PROTOTYPES /////////////////////////////////////////////

int Game_Init(void *parms=NULL, int num_parms = 0);
int Game_Shutdown(void *parms=NULL, int num_parms = 0);
int Game_Main(void *parms=NULL, int num_parms = 0);
int loadbitmap(BITMAPFILEPTR bitmap, char *filename);
int unloadbitmap(BITMAPFILEPTR bitmap);
int flipbitmap(UCHAR *image, int bytes_per_line, int height);
LPDIRECTDRAWSURFACE4 createsurface(int width,int height, int memflags);
int DDraw_Fill_Surface(LPDIRECTDRAWSURFACE4 lpdds,int color);
int Scan_Image_Bitmap(BITMAPFILEPTR bitmap, LPDIRECTDRAWSURFACE4 lpdds, int cx,int cy);

int DDraw_Draw_Surface(LPDIRECTDRAWSURFACE4 source, int x, int y,
int width, int height, LPDIRECTDRAWSURFACE4 dest,
int transparent);
// FUNCTIONS //////////////////////////////////////////////
int loadbitmap(BITMAPFILEPTR bitmap, char *filename)
{
// this function opens a bitmap file and loads the data into bitmap

int file_handle, // the file handle
index; // looping index

UCHAR *temp_buffer = NULL; // used to convert 24 bit images to 16 bit
OFSTRUCT file_data; // the file data information

// open the file if it exists
if ((file_handle = OpenFile(filename,&file_data,OF_READ))==-1)
return(0);

// now load the bitmap file header
_lread(file_handle, &bitmap->bitmapfileheader,sizeof(BITMAPFILEHEADER));

// test if this is a bitmap file
if (bitmap->bitmapfileheader.bfType!=BITMAP_ID)
{
// close the file
_lclose(file_handle);

// return error
return(0);
} // end if

// now we know this is a bitmap, so read in all the sections

// first the bitmap infoheader

// now load the bitmap file header
_lread(file_handle, &bitmap->bitmapinfoheader,sizeof(BITMAPINFOHEADER));

// now load the color palette if there is one
if (bitmap->bitmapinfoheader.biBitCount == 8)
{
_lread(file_handle, &bitmap->palette,MAXCOLORS*sizeof(PALETTEENTRY));

// now set all the flags in the palette correctly and fix the reversed
// BGR RGBQUAD data format
for (index=0; index < MAXCOLORS; index++)
{
// reverse the red and green fields
int temp_color = bitmap->palette[index].peRed;
bitmap->palette[index].peRed = bitmap->palette[index].peBlue;
bitmap->palette[index].peBlue = temp_color;

// always set the flags word to this
bitmap->palette[index].peFlags = PC_NOCOLLAPSE;
} // end for index

} // end if

// finally the image data itself
_lseek(file_handle,-(int)(bitmap->bitmapinfoheader.biSizeImage),SEEK_END);

// now read in the image, if the image is 8 or 16 bit then simply read it
// but if its 24 bit then read it into a temporary area and then convert
// it to a 16 bit image

if (bitmap->bitmapinfoheader.biBitCount==8 // bitmap->bitmapinfoheader.biBitCount==16 //
bitmap->bitmapinfoheader.biBitCount==24)
{
// delete the last image if there was one
if (bitmap->buffer)
free(bitmap->buffer);

// allocate the memory for the image
if (!(bitmap->buffer = (UCHAR *)malloc(bitmap->bitmapinfoheader.biSizeImage)))
{
// close the file
_lclose(file_handle);

// return error
return(0);
} // end if

// now read it in
_lread(file_handle,bitmap->buffer,bitmap->bitmapinfoheader.biSizeImage);

} // end if
else
{
// serious problem
return(0);

} // end else


// close the file
_lclose(file_handle);

// flip the bitmap
flipbitmap(bitmap->buffer,
bitmap->bitmapinfoheader.biWidth*(bitmap->bitmapinfoheader.biBitCount/8),
bitmap->bitmapinfoheader.biHeight);

// return success
return(1);

} // end Load_Bitmap_File


int unloadbitmap(BITMAPFILEPTR bitmap)
{
// this function releases all memory associated with "bitmap"
if (bitmap->buffer)
{
// release memory
free(bitmap->buffer);

// reset pointer
bitmap->buffer = NULL;

} // end if

// return success
return(1);

} // end Unload_Bitmap_File


int flipbitmap(UCHAR *image, int bytes_per_line, int height)
{
// this function is used to flip bottom-up .BMP images

UCHAR *buffer; // used to perform the image processing
int index; // looping index

// allocate the temporary buffer
if (!(buffer = (UCHAR *)malloc(bytes_per_line*height)))
return(0);

// copy image to work area
memcpy(buffer,image,bytes_per_line*height);

// flip vertically
for (index=0; index < height; index++)
memcpy(ℑ[((height-1) - index)*bytes_per_line],
&buffer[index*bytes_per_line], bytes_per_line);

// release the memory
free(buffer);

// return success
return(1);

} // end Flip_Bitmap


int DDraw_Fill_Surface(LPDIRECTDRAWSURFACE4 lpdds,int color)
{
DDBLTFX ddbltfx; // this contains the DDBLTFX structure

// clear out the structure and set the size field
DDRAW_INIT_STRUCT(ddbltfx);

// set the dwfillcolor field to the desired color
ddbltfx.dwFillColor = color;

// ready to blt to surface
lpdds->Blt(NULL, // ptr to dest rectangle
NULL, // ptr to source surface, NA
NULL, // ptr to source rectangle, NA
DDBLT_COLORFILL / DDBLT_WAIT, // fill and wait
&ddbltfx); // ptr to DDBLTFX structure

// return success
return(1);
} // end DDraw_Fill_Surface

///////////////////////////////////////////////////////////////

int DDraw_Draw_Surface(LPDIRECTDRAWSURFACE4 source, // source surface to draw
int x, int y, // position to draw at
int width, int height, // size of source surface
LPDIRECTDRAWSURFACE4 dest, // surface to draw the surface on
int transparent = 1) // transparency flag
{
// draw a bob at the x,y defined in the BOB
// on the destination surface defined in dest

RECT dest_rect, // the destination rectangle
source_rect; // the source rectangle

// fill in the destination rect
dest_rect.left = x;
dest_rect.top = y;
dest_rect.right = x+width-1;
dest_rect.bottom = y+height-1;

// fill in the source rect
source_rect.left = 0;
source_rect.top = 0;
source_rect.right = width-1;
source_rect.bottom = height-1;

// test transparency flag

if (transparent)
{
// enable color key blit
// blt to destination surface
if (FAILED(dest->Blt(&dest_rect, source,
&source_rect,(DDBLT_WAIT / DDBLT_KEYSRC),
NULL)))
return(0);

} // end if
else
{
// perform blit without color key
// blt to destination surface
if (FAILED(dest->Blt(&dest_rect, source,
&source_rect,(DDBLT_WAIT),
NULL)))
return(0);

} // end if

// return success
return(1);

} // end DDraw_Draw_Surface

///////////////////////////////////////////////////////////////

int Scan_Image_Bitmap(BITMAPFILEPTR bitmap, // bitmap file to scan image data from
LPDIRECTDRAWSURFACE4 lpdds, // surface to hold data
int cx, int cy) // cell to scan image from
{
// this function extracts a bitmap out of a bitmap file

UCHAR *source_ptr, // working pointers
*dest_ptr;

DDSURFACEDESC2 ddsd; // direct draw surface description

// get the addr to destination surface memory

// set size of the structure
ddsd.dwSize = sizeof(ddsd);

// lock the display surface
lpdds->Lock(NULL,
&ddsd,
DDLOCK_WAIT / DDLOCK_SURFACEMEMORYPTR,
NULL);

// compute position to start scanning bits from
cx = cx*(ddsd.dwWidth+1) + 1;
cy = cy*(ddsd.dwHeight+1) + 1;

gwidth = ddsd.dwWidth;
gheight = ddsd.dwHeight;

// extract bitmap data
source_ptr = bitmap->buffer + cy*bitmap->bitmapinfoheader.biWidth+cx;

// assign a pointer to the memory surface for manipulation
dest_ptr = (UCHAR *)ddsd.lpSurface;

// iterate thru each scanline and copy bitmap
for (int index_y=0; index_y < ddsd.dwHeight; index_y++)
{
// copy next line of data to destination
memcpy(dest_ptr, source_ptr, ddsd.dwWidth);

// advance pointers
dest_ptr += (ddsd.dwWidth);
source_ptr += bitmap->bitmapinfoheader.biWidth;
} // end for index_y

// unlock the surface
lpdds->Unlock(NULL);

// return success
return(1);

} // end Scan_Image_Bitmap


LPDIRECTDRAWSURFACE4 createsurface(int width,int height, int memflags)
{
DDSURFACEDESC2 ddsd;
LPDIRECTDRAWSURFACE4 lpdds;
DDRAW_INIT_STRUCT(ddsd);

ddsd.dwFlags = DDSD_CAPS / DDSD_WIDTH / DDSD_HEIGHT;

ddsd.dwWidth = width;
ddsd.dwHeight = height;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN / memflags;
if (FAILED(lpdd4->CreateSurface(&ddsd,&lpdds,NULL)))
return (NULL);
DDCOLORKEY colorkey;
colorkey.dwColorSpaceLowValue =0;
colorkey.dwColorSpaceHighValue =0;
lpdds->SetColorKey(DDCKEY_SRCBLT, &colorkey);

return (lpdds);
}

LRESULT CALLBACK WindowProc(HWND hwnd,
UINT msg,
WPARAM wparam,
LPARAM lparam)
{
// this is the main message handler of the system
PAINTSTRUCT ps; // used in WM_PAINT
HDC hdc; // handle to a device context
// what is the message
switch(msg)
{
case WM_CREATE:
{
// do initialization stuff here
return(0);
} break;

case WM_PAINT:
{
// start painting
hdc = BeginPaint(hwnd,&ps);

// end painting
EndPaint(hwnd,&ps);
return(0);
} break;

case WM_DESTROY:
{
// kill the application
PostQuitMessage(0);
return(0);
} break;

default:break;

} // end switch

// process any messages that we didn''t take care of
return (DefWindowProc(hwnd, msg, wparam, lparam));

} // end WinProc

// WINMAIN ////////////////////////////////////////////////

int WINAPI WinMain( HINSTANCE hinstance,
HINSTANCE hprevinstance,
LPSTR lpcmdline,
int ncmdshow)
{

WNDCLASSEX winclass; // this will hold the class we create
HWND hwnd; // generic window handle
MSG msg; // generic message
HDC hdc; // generic dc
PAINTSTRUCT ps; // generic paintstruct

// first fill in the window class stucture
winclass.cbSize = sizeof(WNDCLASSEX);
winclass.style = CS_DBLCLKS / CS_OWNDC /
CS_HREDRAW / CS_VREDRAW;
winclass.lpfnWndProc = WindowProc;
winclass.cbClsExtra = 0;
winclass.cbWndExtra = 0;
winclass.hInstance = hinstance;
winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
winclass.hCursor = LoadCursor(NULL, IDC_ARROW);
winclass.hbrBackground = GetStockObject(BLACK_BRUSH);
winclass.lpszMenuName = NULL;
winclass.lpszClassName = WINDOW_CLASS_NAME;
winclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

// register the window class
if (!RegisterClassEx(&winclass))
return(0);

// create the window
if (!(hwnd = CreateWindowEx(NULL,WINDOW_CLASS_NAME, // class
"WinX Game Console", // title
WS_POPUP / WS_VISIBLE,
0,0, // x,y
WWIDTH, // width
WHEIGHT, // height
NULL, // handle to parent
NULL, // handle to menu
hinstance,// instance
NULL))) // creation parms
return(0);

// save the window handle and instance in a global
main_window_handle = hwnd;
main_instance = hinstance;

// perform all game console specific initialization
Game_Init();

// enter main event loop
while(1)
{
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
// test if this is a quit
if (msg.message == WM_QUIT)
break;

// translate any accelerator keys
TranslateMessage(&msg);

// send the message to the window proc
DispatchMessage(&msg);
} // end if

// main game processing goes here
Game_Main();

} // end while

// shutdown game and release all resources
Game_Shutdown();

// return to Windows like this
return(msg.wParam);

} // end WinMain

// WINX GAME PROGRAMMING CONSOLE FUNCTIONS ////////////////
int Game_Init(void *parms, int num_parms)
{


// first create base IDirectDraw interface
if (FAILED(DirectDrawCreate(NULL, &lpdd1, NULL)))
return(0);

// now query for IDirectDraw4
if (FAILED(lpdd1->QueryInterface(IID_IDirectDraw4,
(LPVOID *)&lpdd4)))
return(0);

// set cooperation to full screen
if (FAILED(lpdd4->SetCooperativeLevel(main_window_handle,
DDSCL_FULLSCREEN / DDSCL_ALLOWMODEX /
DDSCL_EXCLUSIVE / DDSCL_ALLOWREBOOT)))
return(0);

// set display mode
if (FAILED(lpdd4->SetDisplayMode(WWIDTH,WHEIGHT,BPP,0,0)))
return(0);

DDRAW_INIT_STRUCT(ddsd);

ddsd.dwFlags = DDSD_CAPS / DDSD_BACKBUFFERCOUNT;
ddsd.dwBackBufferCount=1;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE / DDSCAPS_COMPLEX / DDSCAPS_FLIP;
//create primary surface
if (FAILED(lpdd4->CreateSurface(&ddsd, &lpddsprimary, NULL)))
return 0;
ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;

if (FAILED(lpddsprimary->GetAttachedSurface(&ddsd.ddsCaps, &lpddsback)))
return 0;

if (!loadbitmap(&bitmap,"bground.bmp"))
return(0);

DDraw_Fill_Surface(lpddsprimary,0);
DDraw_Fill_Surface(lpddsback,0);

lpddsbackground = createsurface(640,480,DDSCAPS_VIDEOMEMORY);

//lock the primary surface
lpddsbackground->Lock(NULL,&ddsd, DDLOCK_SURFACEMEMORYPTR / DDLOCK_WAIT,NULL);

UCHAR *image_buffer = (UCHAR *)ddsd.lpSurface;

if (ddsd.lPitch == WWIDTH)
{
memcpy((void *)image_buffer,(void *)bitmap.buffer, WWIDTH*WHEIGHT);
}
else
{
UCHAR *destptr = image_buffer;
UCHAR *srcptr = bitmap.buffer;
for (int y=0; y {
memcpy((void *)destptr, (void *)srcptr, WWIDTH);
destptr += ddsd.lPitch;
srcptr += WWIDTH;
}
}

if (FAILED(lpddsbackground->Unlock(NULL)))
return(0);
unloadbitmap(&bitmap);

sprite.x = 200;
sprite.y = 100;

if (!loadbitmap(&bitmap,"ground.bmp"))
return 0;

sprite.image = createsurface(64,64,DDSCAPS_VIDEOMEMORY);
Scan_Image_Bitmap(&bitmap,sprite.image,1,0);

// unload the bitmap file, we no longer need it
unloadbitmap(&bitmap);

// return success or failure or your own return code here

return 1;
} // end Game_Init

///////////////////////////////////////////////////////////

int Game_Main(void *parms, int num_parms)
{

// make sure this isn''t executed again
if (window_closed)
return(0);

// for now test if user is hitting ESC and send WM_CLOSE
if (KEYDOWN(VK_ESCAPE))
{
PostMessage(main_window_handle,WM_CLOSE,0,0);
window_closed = 1;
} // end if
DDraw_Draw_Surface(lpddsbackground,0,0, WWIDTH,WHEIGHT, lpddsback,0);


DDraw_Draw_Surface(sprite.image,sprite.x,sprite.y,64,64,lpddsback);

while (FAILED(lpddsprimary->Flip(NULL, DDFLIP_WAIT)));


return 1;
} // end Game_Main

///////////////////////////////////////////////////////////


int Game_Shutdown(void *parms, int num_parms)
{

if (lpddsbackground)
{
lpddsbackground->Release();
lpddsbackground = NULL;
}



// now the primary surface
if (lpddsprimary)
{
lpddsprimary->Release();
lpddsprimary = NULL;
} // end if
// release the directdraw object
if (lpdd4!=NULL)
lpdd4->Release();
return 1;
} // end Game_Shutdown
Sorry if you wouldn´t use Direct-Draw I could help you....
Ok, in Scan_Image_Bitmap() you have this loop for copying your
image data.

// iterate thru each scanline and copy bitmap
for (int index_y=0; index_y < ddsd.dwHeight; index_y++)
{
// copy next line of data to destination
memcpy(dest_ptr, source_ptr, ddsd.dwWidth);

// advance pointers
dest_ptr += (ddsd.dwWidth);
source_ptr += bitmap->bitmapinfoheader.biWidth;
} // end for index_y

Now, if both your surface and your bitmap were 24 BPP, then
this approach would be fine. However, for each pixel that''s
copied, you have to skip a byte in your surface pointer. ie:

// iterate thru each scanline and copy bitmap
for (int index_y=0; index_y < ddsd.dwHeight; index_y++)
{
for (int index_x=0;index_x < bitmap->bitmapinfoheader.biWidth;
index_x++)
{
//Copy a single pixel
memcpy(dest_ptr, source_ptr, 3)

//advance pointers
dest_ptr = dest_ptr + 4;
source_ptr = source_ptr + 3;
}//end for index_x
} // end for index_y

Now if you have the direct-x sdk, you will probably find
mentioned in there somewhere a part of that ddsd structure
called lPitch [or something like that]. From memory, it''s the
*Actual* number of bytes per scanline in memory for the
surface. If your image comes up all distorted, then you will
probably have to add this in...

}//end for index_x
dest_ptr = dest_ptr + (ddsd.lPitch - ddsd.dwWidth);
} //end for index_y

also, <br>if you haven''t done this already, you need to compensate for the<br>fact that .BMP''s have each scanline end on a DWORD boundary. What this means is that the width of a scanline will always be<br>divisible by 4. If the image still distorts, you *could* try<br>something like this [not tested yet]…<br><br>}//end for index_x<br>dest_ptr = dest_ptr + (ddsd.lPitch - ddsd.dwWidth);<br>source_ptr = source_ptr + (bitmap->bitmapinfoheader.biWidth % 4)<br>} //end for index_y<br> <br><br>anyway, I hope some of this helps. I''m gonna go look for pornos<br>now… <br><br><br>———-<br>Disco Love For Everyone
----------"i think that all this talking and such is paining my head to astounding annoyance" - Erick"Quoting people in your tag is cool. Quoting yourself is even cooler" - SpazBoy_the_MiteyDisco Love For Everyone
well i tried those changes but the colors are still screwed up
i also added code in the loadbitmap function to convert the file to 32bpp but im not sure if that is correct
this is what it looks like
also does this function seem to long load in a bitmap file?

int loadbitmap(BITMAPFILEPTR bitmap, char *filename)
{
// this function opens a bitmap file and loads the data into bitmap

int file_handle, // the file handle
index; // looping index

UCHAR *temp_buffer = NULL; // used to convert 24 bit images to 16 bit
OFSTRUCT file_data; // the file data information

// open the file if it exists
if ((file_handle = OpenFile(filename,&file_data,OF_READ))==-1)
return(0);

// now load the bitmap file header
_lread(file_handle, &bitmap->bitmapfileheader,sizeof(BITMAPFILEHEADER));

// test if this is a bitmap file
if (bitmap->bitmapfileheader.bfType!=BITMAP_ID)
{
// close the file
_lclose(file_handle);

// return error
return(0);
} // end if

// now we know this is a bitmap, so read in all the sections

// first the bitmap infoheader

// now load the bitmap file header
_lread(file_handle, &bitmap->bitmapinfoheader,sizeof(BITMAPINFOHEADER));

// now load the color palette if there is one
if (bitmap->bitmapinfoheader.biBitCount == 8)
{
_lread(file_handle, &bitmap->palette,MAXCOLORS*sizeof(PALETTEENTRY));

// now set all the flags in the palette correctly and fix the reversed
// BGR RGBQUAD data format
for (index=0; index < MAXCOLORS; index++)
{
// reverse the red and green fields
int temp_color = bitmap->palette[index].peRed;
bitmap->palette[index].peRed = bitmap->palette[index].peBlue;
bitmap->palette[index].peBlue = temp_color;

// always set the flags word to this
bitmap->palette[index].peFlags = PC_NOCOLLAPSE;
} // end for index

} // end if

// finally the image data itself
_lseek(file_handle,-(int)(bitmap->bitmapinfoheader.biSizeImage),SEEK_END);

// now read in the image, if the image is 8 or 16 bit then simply read it
// but if its 24 bit then read it into a temporary area and then convert
// it to a 16 bit image

if (bitmap->bitmapinfoheader.biBitCount==8 // bitmap->bitmapinfoheader.biBitCount==16)
{
// delete the last image if there was one
if (bitmap->buffer)
free(bitmap->buffer);

// allocate the memory for the image
if (!(bitmap->buffer = (UCHAR *)malloc(bitmap->bitmapinfoheader.biSizeImage)))
{
// close the file
_lclose(file_handle);

// return error
return(0);
} // end if

// now read it in
_lread(file_handle,bitmap->buffer,bitmap->bitmapinfoheader.biSizeImage);

} // end if
else
{
if (!(temp_buffer = (UCHAR *)malloc(bitmap->bitmapinfoheader.biSizeImage)))
{
_lclose(file_handle);
// serious problem
return(0);

} // end else


// allocate final 16 bit storage buffer
if (!(bitmap->buffer=(UCHAR *)malloc(2*bitmap->bitmapinfoheader.biWidth*bitmap->bitmapinfoheader.biHeight)))
{
// close the file
_lclose(file_handle);

// release working buffer
free(temp_buffer);

// return error
return(0);
} // end if

// now read it in
_lread(file_handle,temp_buffer,bitmap->bitmapinfoheader.biSizeImage);

// now convert each 24 bit RGB value into a 16 bit value
for (index=0; indexbitmapinfoheader.biWidth*bitmap->bitmapinfoheader.biHeight; index++)
{
// extract RGB components (in BGR order), note the scaling
UCHAR blue = (temp_buffer[index*3 + 0]),
green = (temp_buffer[index*3 + 1]),
red = (temp_buffer[index*3 + 2]);

// build up 16 bit color word
DWORD color = RGB32BIT(0,red,green,blue);

// write color to buffer
((USHORT *)bitmap->buffer)[index] = color;

} // end for index

// finally write out the correct number of bits
bitmap->bitmapinfoheader.biBitCount=16;

} // end if
// close the file
_lclose(file_handle);

// flip the bitmap
flipbitmap(bitmap->buffer,
bitmap->bitmapinfoheader.biWidth*(bitmap->bitmapinfoheader.biBitCount/8),
bitmap->bitmapinfoheader.biHeight);

// return success
return(1);

} // end Load_Bitmap_File
It doesn''t seem long for a pixel conversion and loading
routine...

But isn''t it converting to 16 BPP there?

Hang on, It''s time I compiled this...

(minutes pass)

ok that complete program you posted back there compiled
(eventually) but crashed my pc. If you send your complete
source (workspace too) zipped to hing1@elite.net.au I''ll
get it working, but I''ll need to run it and see for myself.


----------
Disco Love For Everyone
----------"i think that all this talking and such is paining my head to astounding annoyance" - Erick"Quoting people in your tag is cool. Quoting yourself is even cooler" - SpazBoy_the_MiteyDisco Love For Everyone
Well now. I just realised that I''ve never coded a bitmap
loader under direct draw before. I''ve coded DOS loaders,
but I''ve always used API''s and stuff like that in windows.

So what the hell, I went away and repeatedly smashed my head
up against a brick wall, and when I finished the blood splatters
just happened to spell out a working bitmap loader and a
translater for a 32 bit direct draw surface. Here''s how it
goes...

/* You will of course have the following includes already
in your program

#include "stdio.h"
#include "stdlib.h" (or malloc.h)
#include "windows.h"
#include "ddraw.h" */



//This is the first batch of info you gain from the BMP file
typedef struct {
char ID[2]; //The identifier string
unsigned long FileSize; //The complete file size
char Reserved[4]; //Don''t care
unsigned long BitmapDataPos; //Where the image data is
unsigned long InfoLength; //Length of the InfoHeader
} BitMapFileHeader;

//This one contains more information on the image
typedef struct {
unsigned long Width; //How wide the scanline is (pixels)
unsigned long Height; //How many scanlines
WORD Planes; //Should be 1??
WORD BPP; //Bit Per Pixel
unsigned long Ctype; //0 - RGB, 1 & 2 = RLE
unsigned long PicSize; //Size of picture in bytes
unsigned long Hres; //Horizontal resolution
unsigned long Vres; //Vertical resolution
unsigned long Ncol; //Number of colors used
unsigned long Icol; //Number of important colors
unsigned char Palette[256][3];//The palette
} BitMapInfoHeader;


//This structure includes both headers and a buffer for the image
typedef struct {
BitMapFileHeader FileHeader;
BitMapInfoHeader InfoHeader;
unsigned char *Buffer; //The image goes in here
} BitMapStruct;


//LoadBitmap() Will load any 24 BPP bitmap into memory.
//It will ONLY load 24 BPP bitmaps, and it DOESN''T flip
//the image (the translator does this).
int LoadBitmap(char *FileName,BitMapStruct *Output)
{
FILE *fp;

//Attempt to open the file
fp = fopen(FileName,"rb");

//If we failed, we bail
if (fp == NULL)
return 0;

//Read the first header
//(For my paranoia''s sake, I did it seperate)
fread(&Output->FileHeader.ID[0],1,1,fp);
fread(&Output->FileHeader.ID[1],1,1,fp);
fread(&Output->FileHeader.FileSize,sizeof(long),1,fp);
fread(Output->FileHeader.Reserved,1,4,fp);
fread(&Output->FileHeader.BitmapDataPos,sizeof(long),1,fp);
fread(&Output->FileHeader.InfoLength,sizeof(long),1,fp);

//Check if it''s a valid bitmap file (valid for us anyway)
if (Output->FileHeader.ID[0] != ''B'' //
Output->FileHeader.ID[1] != ''M'')
return 0;

//get the info header
//(I feel safer if I keep ''em seperated
fread(&Output->InfoHeader.Width,sizeof(long),1,fp);
fread(&Output->InfoHeader.Height,sizeof(long),1,fp);
fread(&Output->InfoHeader.Planes,sizeof(WORD),1,fp);
fread(&Output->InfoHeader.BPP,sizeof(WORD),1,fp);
fread(&Output->InfoHeader.Ctype,sizeof(long),1,fp);
fread(&Output->InfoHeader.PicSize,sizeof(long),1,fp);
fread(&Output->InfoHeader.Hres,sizeof(long),1,fp);
fread(&Output->InfoHeader.Vres,sizeof(long),1,fp);
fread(&Output->InfoHeader.Ncol,sizeof(long),1,fp);
fread(&Output->InfoHeader.Icol,sizeof(long),1,fp);

//Check if it''s 24 bit
if (Output->InfoHeader.BPP != 24)
return 0;

//Check that it''s uncompressed (it will be if it''s 24 bpp)
if (Output->InfoHeader.Ctype != 0)
return 0;

//allocate the buffer memory
Output->Buffer = (char *) malloc(Output->InfoHeader.PicSize);

//Check that it worked
if (Output->Buffer == NULL)
return 0;

//Prepare to read the image
fseek(fp,Output->FileHeader.BitmapDataPos,0);

//Read in the image
fread(Output->Buffer,Output->InfoHeader.PicSize,1,fp);

//close the file
fclose(fp);

//return success
return 1;
}

//TransBmp() Takes the raw, unflipped Bitmap data
//and puts it in proper order onto a surface. The surface
//must already have been created and needs to be at least
//the same size as the bitmap.
//This function assumes that the surface is 32 bit.
//It could easily be converted to be BPP independant,
//but that can wait.
int TransBmp(BitMapStruct *Input, LPDIRECTDRAWSURFACE4 Output)
{
unsigned char R,G,B;
DDSURFACEDESC2 ddsd;
unsigned char *sptr, *dptr;
unsigned long y,x;
unsigned long BmpWidth, DestSkip;


//The width of the bitmap buffer in bytes, and ensuring a
//DWORD boundary.
BmpWidth = ((Input->InfoHeader.Width % 4) +
Input->InfoHeader.Width)*3;

//prepare the ddsd structure for use
ZeroMemory(&ddsd,sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);

//Step 1, Lock the Destination Surface
Output->Lock(NULL,&ddsd,DDLOCK_WAIT,NULL);


//DestSkip is the difference in bytes between the width of the
//Bitmap, and the width of the surface.
DestSkip = ddsd.lPitch - (4*Input->InfoHeader.Width);

//Step 2, get pointers to our buffers
sptr = Input->Buffer + Input->InfoHeader.PicSize - BmpWidth;
dptr = (unsigned char *) ddsd.lpSurface;

//Step 3. Loop thru the buffers, translating data
for (y = 0; y < ddsd.dwHeight; y++)
{
for (x = 0; x < ddsd.dwWidth; x++)
{
//Read the RGB data from the bitmap
R = *sptr;
sptr = sptr + 1;
G = *sptr;
sptr = sptr + 1;
B = *sptr;
sptr = sptr + 1;

//Chuck it into the surface
//Y''know, you should check the pixel format
//beforehand, I think it can be RGBA, OR ARGB.
*dptr = R;
dptr = dptr +1;
*dptr = G;
dptr = dptr +1;
*dptr = B;
dptr = dptr +1;
*dptr = 255;
dptr = dptr +1;
}
sptr = sptr - (2*BmpWidth);
dptr = dptr + DestSkip;
}

//Step 4. Unlock the surface and pray for surf.
Output->Unlock(NULL);

return 1;
}

This has been tested and it should work no problems.


----------
Disco Love For Everyone
----------"i think that all this talking and such is paining my head to astounding annoyance" - Erick"Quoting people in your tag is cool. Quoting yourself is even cooler" - SpazBoy_the_MiteyDisco Love For Everyone

This topic is closed to new replies.

Advertisement