Archived

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

DDraw bmp loading issue, some advice plz

This topic is 5245 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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
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