Archived

This topic is now archived and is closed to further replies.

Swatter555

DDraw bmp loading issue, some advice plz

Recommended Posts

Swatter555    127
It seems this problem is a bit common. I have read a couple 16bit mode articles, but I am unable to get it to work exactly correctly. I am attempting to load a 24 bit bmp into an offscreen surface. I also attach a clipper to the offscreen surface before-hand. Then I blit it to the backbuffer, then flip the primary surface. The result is a some messed up colors. SCREEN_WIDTH 1024 SCREEN_HEIGHT 768 SCREEN_BPP 16 The LoadBitmapFile() is supposed to handle loading 24bit bmps and converting them to 16bit. oh well, heres a mess of code for you. Ill include the source for the library functions also.
//global

BITMAP_FILE          bitmap;

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

        } BITMAP_FILE, *BITMAP_FILE_PTR;

//game_init



	Load_Bitmap_File(&bitmap, "LOGO_FILLER.bmp");

	lpddsoff = DDraw_Create_Surface(SCREEN_WIDTH,   SCREEN_HEIGHT,DDSCAPS_VIDEOMEMORY, 
                                    _RGB16BIT565(255,255,255));

	
	//attach clipper to surface

	RECT clip_list[1] = {{0,0,SCREEN_WIDTH,SCREEN_HEIGHT}};
    DDraw_Attach_Clipper(lpddsoff, 1, clip_list);


//game main


// lock the off surface

lpddsoff->Lock(NULL,&ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,NULL);

// get video pointer to off surfce

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

// test if memory is linear

if (ddsd.lPitch == SCREEN_WIDTH)
   {
   // copy memory from double buffer to off buffer

   memcpy((void *)off_buffer, (void *)bitmap.buffer, SCREEN_WIDTH*SCREEN_HEIGHT);
   } // end if

else
   { // non-linear


   // make copy of source and destination addresses

   UCHAR *dest_ptr = off_buffer;
   UCHAR *src_ptr  = bitmap.buffer;

   // memory is non-linear, copy line by line

   for (int y=0; y < SCREEN_HEIGHT; y++)
       {
       // copy line

       memcpy((void *)dest_ptr, (void *)src_ptr, SCREEN_WIDTH);

       // advance pointers to next line

       dest_ptr+=ddsd.lPitch;
       src_ptr +=SCREEN_WIDTH;
       } // end for


   } // end else


// now unlock the off surface

if (FAILED(lpddsoff->Unlock(NULL)))
   return(0);


//blit


//dest_rect

RECT dest_rect;

dest_rect.left = 0;
dest_rect.top  = 0;
dest_rect.right = SCREEN_WIDTH -1;
dest_rect.bottom = SCREEN_HEIGHT -1;


//source rect

RECT source_rect;

source_rect.left = 0;
source_rect.top  = 0;
source_rect.right = SCREEN_WIDTH -1;
source_rect.bottom = SCREEN_HEIGHT -1;


lpddsback->Blt(&dest_rect, lpddsoff, &source_rect,
			   (DDBLT_WAIT | DDBLT_KEYSRC),
			   NULL);

lpddsprimary->Flip(NULL, DDFLIP_WAIT);


//function defs

//Create offscreen plain surface///////////////////////////

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



LPDIRECTDRAWSURFACE7 DDraw_Create_Surface(int width, 
                                          int height, 
                                          int mem_flags, 
                                          USHORT color_key_value)
{
// this function creates an offscreen plain surface


DDSURFACEDESC2 ddsd;         // working description

LPDIRECTDRAWSURFACE7 lpdds;  // temporary surface

    
// set to access caps, width, and height

memset(&ddsd,0,sizeof(ddsd));
ddsd.dwSize  = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;

// set dimensions of the new bitmap surface

ddsd.dwWidth  =  width;
ddsd.dwHeight =  height;

// set surface to offscreen plain

ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | mem_flags;

// create the surface

if (FAILED(lpdd->CreateSurface(&ddsd,&lpdds,NULL)))
   return(NULL);

// set color key to default color 000

// note that if this is a 8bit bob then palette index 0 will be 

// transparent by default

// note that if this is a 16bit bob then RGB value 000 will be 

// transparent

DDCOLORKEY color_key; // used to set color key

color_key.dwColorSpaceLowValue  = color_key_value;
color_key.dwColorSpaceHighValue = color_key_value;

// now set the color key for source blitting

lpdds->SetColorKey(DDCKEY_SRCBLT, &color_key);

// return surface

return(lpdds);
} // end DDraw_Create_Surface


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

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


//Load a bmp file and convert to 16bit//////////////////////////

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



int Load_Bitmap_File(BITMAP_FILE_PTR 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,MAX_COLORS_PALETTE*sizeof(PALETTEENTRY));

   // now set all the flags in the palette correctly and fix the reversed 

   // BGR RGBQUAD data format

   for (index=0; index < MAX_COLORS_PALETTE; 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 (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 (bitmap->bitmapinfoheader.biBitCount==24)
   {
   // allocate temporary buffer to load 24 bit image

   if (!(temp_buffer = (UCHAR *)malloc(bitmap->bitmapinfoheader.biSizeImage)))
      {
      // close the file

      _lclose(file_handle);

      // return error

      return(0);
      } // end if

   
   // 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 the file in

   _lread(file_handle,temp_buffer,bitmap->bitmapinfoheader.biSizeImage);

   // now convert each 24 bit RGB value into a 16 bit value

   for (index=0; index < bitmap->bitmapinfoheader.biWidth*bitmap->bitmapinfoheader.biHeight; index++)
       {
       // build up 16 bit color word

       USHORT color;
       
       // build pixel based on format of directdraw surface

       if (dd_pixel_format==DD_PIXEL_FORMAT555)
           {
           // extract RGB components (in BGR order), note the scaling

           UCHAR blue  = (temp_buffer[index*3 + 0] >> 3),
                 green = (temp_buffer[index*3 + 1] >> 3),
                 red   = (temp_buffer[index*3 + 2] >> 3); 
           // use the 555 macro

           color = _RGB16BIT555(red,green,blue);
           } // end if 555

       else
       if (dd_pixel_format==DD_PIXEL_FORMAT565) 
          {
          // extract RGB components (in BGR order), note the scaling

           UCHAR blue  = (temp_buffer[index*3 + 0] >> 3),
                 green = (temp_buffer[index*3 + 1] >> 2),
                 red   = (temp_buffer[index*3 + 2] >> 3);

           // use the 565 macro

           color = _RGB16BIT565(red,green,blue);

          } // end if 565


       // write color to buffer

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

       } // end for index


   // finally write out the correct number of bits

   bitmap->bitmapinfoheader.biBitCount=16;

   // release working buffer

   free(temp_buffer);

   } // end if 24 bit

else
   {
   // serious problem

   return(0);

   } // end else


#if 0
// write the file info out 

printf("\nfilename:%s \nsize=%d \nwidth=%d \nheight=%d \nbitsperpixel=%d \ncolors=%d \nimpcolors=%d",
        filename,
        bitmap->bitmapinfoheader.biSizeImage,
        bitmap->bitmapinfoheader.biWidth,
        bitmap->bitmapinfoheader.biHeight,
		bitmap->bitmapinfoheader.biBitCount,
        bitmap->bitmapinfoheader.biClrUsed,
        bitmap->bitmapinfoheader.biClrImportant);
#endif

// close the file

_lclose(file_handle);

// flip the bitmap

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

// return success

return(1);

} // end Load_Bitmap_File

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

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



[edited by - swatter555 on August 5, 2003 12:26:05 AM]

Share this post


Link to post
Share on other sites
Swatter555    127
Well,with the help of some source I found on the internet I created this function that seems to work fine. This whole affair seemed very hit and miss. Its probably not too pretty, but it works





//Load 24bit bmp onto a 16 bit surface/////////////////////////////

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



LPDIRECTDRAWSURFACE7 LoadBmpOffSurface16(LPDIRECTDRAWSURFACE7 lpddsoff,
int lred, int lgreen,int lblue,
int hred, int hgreen,int hblue,
const char* bmp_file_name)

{
//This function loads a 24bit bmp and make appropriate

//changes for 16bit surface. It then creates an offscreen

//surface to store bmp on. The surface is returned


//Local Vars////////////////////////

BITMAP bitmap24;
HBITMAP hbitmap24;
DDSURFACEDESC2 ddsd;


//clear out ddsd////////////////////

DDRAW_INIT_STRUCT(ddsd);


// load the interface bitmap

hbitmap24 = (HBITMAP)LoadImage(NULL,bmp_file_name,IMAGE_BITMAP,
0,0,LR_DEFAULTSIZE|LR_LOADFROMFILE);

// return if we failed to load the bitmap

if (FAILED(hbitmap24))
{
//If failure, Show MB

MessageBox(main_window_handle,
"FATAL ERROR:UNABLE TO LOAD BITMAP",
"DirectX Error Message",
MB_OK);
return(0);
} //endif




// get bitmap dimensions

GetObject(hbitmap24,sizeof(BITMAP),&bitmap24);
int surf_width=bitmap24.bmWidth;
int surf_height=bitmap24.bmHeight;



// create surface//////////////////////////

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

HRESULT ddrval;

ZeroMemory(&ddsd,sizeof(ddsd));
ddsd.dwSize = sizeof(DDSURFACEDESC2);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT ;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
ddsd.dwWidth = surf_width;
ddsd.dwHeight = surf_height;



// attempt to create surface

ddrval=lpdd->CreateSurface(&ddsd,&lpddsoff,NULL);


// created ok?//////////////////////////////

if (ddrval!=DD_OK)
{
//If failure, Show MB

MessageBox(main_window_handle,
"FATAL ERROR:UNABLE TO CREATE OFFSCREEN SURFACE",
"DirectX Error Message",
MB_OK);
lpddsoff= NULL;
} //end if



else {

//blacks out surface before bmp transfer

DDraw_Fill_Surface(lpddsoff,_RGB32BIT(0,0,0,0) , NULL);



//get a DC for the surface

HDC hdc;
lpddsoff->GetDC(&hdc);


// generate a compatible DC

HDC bit_dc=CreateCompatibleDC(hdc);


// blit the interface to the surface

SelectObject(bit_dc,hbitmap24);
BitBlt(hdc,0,0,surf_width,surf_height,bit_dc,0,0,SRCCOPY);


// release the DCs

lpddsoff->ReleaseDC(hdc);
DeleteDC(bit_dc);



// set up the color key

DDCOLORKEY key;
key.dwColorSpaceLowValue = _RGB24BIT(0,lred,lgreen,lblue);
key.dwColorSpaceHighValue= _RGB24BIT(0,hred,hgreen,hblue);
lpddsoff->SetColorKey(DDCKEY_SRCBLT,&key);



} //end else



// unload bitmap

DeleteObject(hbitmap24);


return(lpddsoff); //return the surface


} //End LoadBmpOffSurface32

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

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


Share this post


Link to post
Share on other sites