Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

Bitmaps.cpp

Go to the documentation of this file.
00001 /*
00002  * Bitmaps.cpp
00003  *
00004  * Part of Fly! Legacy project
00005  *
00006  * Copyright 2003 Chris Wallace
00007  *
00008  * Fly! Legacy is free software; you can redistribute it and/or modify
00009  *   it under the terms of the GNU General Public License as published by
00010  *   the Free Software Foundation; either version 2 of the License, or
00011  *   (at your option) any later version.
00012  *
00013  * Fly! Legacy is distributed in the hope that it will be useful,
00014  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  *   GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  *   along with Fly! Legacy; if not, write to the Free Software
00020  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  */
00022 
00027 #include "../Include/Globals.h"
00028 #include "../Include/FlyLegacy.h"
00029 #include <vector>
00030 using namespace std;
00031 
00032 
00033 /*
00034  * Drawing Primitives
00035  *
00036  */
00037 
00038 //
00039 // Create a new drawing surface.  In Fly! II, drawing surfaces were RGB
00040 //   arrays where one specific pixel colour value represented transparency,
00041 //   usually <0, 0, 0>.  The xSpan field ensured that the first pixel
00042 //   of each row was longword aligned, by padding each row of RGB values
00043 //   to the next longword boundary.
00044 //
00045 // Legacy surfaces are RGBA arrays, so each pixel is assigned 
00046 //   its transparency level.  This provides more flexibility for
00047 //   implementing alpha-blended surfaces.  The xSpan field is not
00048 //   really needed, but is kept for backwards compatibility with
00049 //   Fly! II DLLs.
00050 //
00051 // Surface image data is oriented starting at the lower-left corner,
00052 //   with pixels increasing towards the right, then row-wise towards
00053 //   the top.
00054 //
00055 SSurface* CreateSurface(int width, int height)
00056 {
00057   SSurface *surf = new SSurface;
00058 
00059   surf->xScreen = 0;
00060   surf->yScreen = 0;
00061   surf->xSize = width;
00062   surf->ySize = height;
00063   surf->xSpan = width;
00064   surf->drawBuffer = new unsigned int[width * height];
00065 
00066   return surf;
00067 }
00068 
00069 void  FreeSurface(SSurface *surface)
00070 {
00071   if (surface != NULL) {
00072     if (surface->drawBuffer != NULL) delete surface->drawBuffer;
00073     delete surface;
00074   }
00075 }
00076 
00077 void  EraseSurface(SSurface *surface)
00078 {
00079   EraseSurfaceRGBA (surface, 0);
00080 }
00081 
00082 void  EraseSurfaceRGB(SSurface *surface, unsigned int rgb)
00083 {
00084   EraseSurfaceRGBA (surface, rgb | (0xff << 24));
00085 }
00086 
00087 void  EraseSurfaceRGBA(SSurface *surface, unsigned int rgba)
00088 {
00089   if (surface != NULL) {
00090     int nPixels = (surface->xSpan * surface->ySize);
00091     for (int i=0; i<nPixels; i++) {
00092       surface->drawBuffer[i] = rgba;
00093     }
00094   }
00095 }
00096 
00097 GLuint TextureFromSurface (SSurface *s, bool mipmap)
00098 {
00099   GLuint texid = 0;
00100 
00101   // Check that surface is square and a power of two in size
00102   if ((s->xSize) == (s->ySize)) {
00103     // Create a GL texture
00104     glGenTextures (1, &texid);
00105     glBindTexture (GL_TEXTURE_2D, texid);
00106     glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
00107     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
00108     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
00109     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
00110 
00111     GLenum format = GL_RGBA;
00112     int depth = 4;
00113     GLubyte *image = (unsigned char*)(s->drawBuffer);
00114 
00115     if (mipmap) {
00116       // Generate mipmapped texture
00117       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00118       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
00119 
00120       gluBuild2DMipmaps (GL_TEXTURE_2D, depth, s->xSize, s->ySize, format,
00121         GL_UNSIGNED_BYTE, image);
00122     } else {
00123       // Generate non-mipmapped texture
00124       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00125       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00126 
00127       glTexImage2D (GL_TEXTURE_2D, 0, format, s->xSize, s->ySize, 0,
00128         format, GL_UNSIGNED_BYTE, image);
00129     }
00130   }
00131 
00132   return texid;
00133 }
00134 
00135 //
00136 // Draw a single pixel in the drawing surface to the specified colour
00137 //   (x,y) are relative to the top-left corner of the surface, increasing
00138 //   to the right and down
00139 //
00140 void  DrawDot(SSurface *surface, int x, int y, unsigned int rgba)
00141 {
00142   if (surface != NULL) {
00143     // Clip to surface boundaries
00144     if ((x >= 0) &&
00145         (y >= 0) &&
00146         (x < (int)surface->xSize) &&
00147         (y < (int)surface->ySize))
00148     {
00149       y = surface->ySize - y - 1;
00150       int offset = ((y * surface->xSpan) + x);
00151       surface->drawBuffer[offset] = rgba;
00152     }
00153   }
00154 }
00155 
00156 //
00157 // Draw a continuous line segment starting at (and including) (x1, y1) and
00158 //   ending at (and including) (x2, y2).  This is an implementation of
00159 //   Bresenham's algorithm.
00160 //
00161 void  DrawLine(SSurface *surface, int x1, int y1, int x2, int y2, unsigned int rgba)
00162 {
00163   // First calculate delta in x and y endpoints
00164   int dx = x2 - x1;
00165   int dy = y2 - y1;
00166 
00167   // Check for special cases
00168   if ((dx == 0) && (dy == 0)) {
00169     // Coincident endpoints
00170     DrawDot (surface, x1, y1, rgba);
00171   } else if (dx == 0) {
00172     // Vertical line, draw from top to bottom
00173     int yStart, yEnd;
00174     if (dy > 0) {
00175       yStart = y1;
00176       yEnd = y2;
00177     } else {
00178       yStart = y2;
00179       yEnd = y1;
00180     }
00181     for (int y=yStart; y<=yEnd; y++) {
00182       DrawDot (surface, x1, y, rgba);
00183     }
00184   } else if (dy == 0) {
00185     // Horizontal line, draw left to right
00186     int xStart, xEnd;
00187     if (dx > 0) {
00188       xStart = x1;
00189       xEnd = x2;
00190     } else {
00191       xStart = x2;
00192       xEnd = x1;
00193     }
00194     for (int x=xStart; x<=xEnd; x++) {
00195       DrawDot (surface, x, y1, rgba);
00196     }
00197   } else {
00198     // Determine whether to step in x-direction or y-direction
00199     if (abs(dx) >= abs(dy)) {
00200       // Step in x direction
00201       // First endpoint must be the leftmost
00202       if (x1 > x2) {
00203         DrawLine (surface, x2, y2, x1, y1, rgba);
00204         return;
00205       }
00206 
00207       // Adjust y-increment for negatively sloped lines
00208       int slope;
00209       if (dy < 0) {
00210         slope = -1;
00211         dy = -dy;
00212       } else {
00213         slope = 1;
00214       }
00215 
00216       // Calculate constants for Bresenham's algorithm
00217       int incE = 2 * dy;
00218       int incNE = (2 * dy) - (2 * dx);
00219       int d = (2 * dy) - dx;
00220       int y = y1;
00221   
00222       // Step through each x-coordinate, drawing the appropriate pixels
00223       for (int x=x1; x<=x2; x++) {
00224         DrawDot (surface, x, y, rgba);
00225         if (d <= 0) {
00226           d += incE;
00227         } else {
00228           d += incNE;
00229           y += slope;
00230         }
00231       }
00232     } else {
00233       // Step in y direction
00234       // First endpoint must be the topmost
00235       if (y1 > y2) {
00236         DrawLine (surface, x2, y2, x1, y1, rgba);
00237         return;
00238       }
00239 
00240       // Adjust x-increment for negatively sloped lines
00241       int slope;
00242       if (dx < 0) {
00243         slope = -1;
00244         dx = -dx;
00245       } else {
00246         slope = 1;
00247       }
00248 
00249       // Calculate constants for Bresenham's algorithm
00250       int incE = 2 * dx;
00251       int incNE = (2 * dx) - (2 * dy);
00252       int d = (2 * dx) - dy;
00253       int x = x1;
00254   
00255       // Step through each y-coordinate, drawing the appropriate pixels
00256       for (int y=y1; y<=y2; y++) {
00257         DrawDot (surface, x, y, rgba);
00258         if (d <= 0) {
00259           d += incE;
00260         } else {
00261           d += incNE;
00262           x += slope;
00263         }
00264       }
00265     }
00266   }
00267 }
00268 
00269 
00270 //
00271 // Draw an unfilled rectangle with corners (x1, y1) and (x2, y2).
00272 //
00273 void  DrawRect(SSurface *surface, int x1, int y1, int x2, int y2, unsigned int rgba)
00274 {
00275   DrawLine (surface, x1, y1, x2, y1, rgba);     // Top
00276   DrawLine (surface, x2, y1, x2, y2, rgba);     // Right
00277   DrawLine (surface, x2, y2, x1, y2, rgba);     // Bottom
00278   DrawLine (surface, x1, y2, x1, y1, rgba);     // Left
00279 }
00280 
00281 //
00282 // Draw a filled rectangle with corners (x1, y1) and (x2, y2).  The sides of
00283 //   the rectangle must be parallel to the axes (sides) of the surface
00284 //
00285 void  FillRect(SSurface *surface, int x1, int y1, int x2, int y2, unsigned int rgba)
00286 {
00287   // x1, y1 must be the top coordinate
00288   int height = (y2 - y1);
00289   if (height < 0) {
00290     FillRect (surface, x2, y2, x1, y1, rgba);
00291   } else {
00292     for (int row=0; row<height; row++) {
00293       DrawLine (surface, x1, y1 + row, x2, y1 + row, rgba);
00294     }
00295   }
00296 }
00297 
00298 void  DrawCircle(SSurface *surface, int xCenter, int yCenter, int radius, unsigned int rgba)
00299 {
00300 }
00301 
00302 unsigned int  MakeRGB(unsigned int r, unsigned int g, unsigned int b)
00303 {
00304   return (r << 0) + (g << 8) + (b << 16) + (0xff << 24);
00305 }
00306 
00307 unsigned int  MakeRGBA(unsigned int r, unsigned int g, unsigned int b, unsigned int a)
00308 {
00309   return (r << 0) + (g << 8) + (b << 16) + (a << 24);
00310 }
00311 
00312 void UnmakeRGB (unsigned int rgb, unsigned int *r, unsigned int *g, unsigned int *b)
00313 {
00314   *r =  rgb & 0x000000FF;
00315   *g = (rgb & 0x0000FF00) >> 8;
00316   *b = (rgb & 0x00FF0000) >> 16;
00317 }
00318 
00319 
00320 void  Blit(SSurface *surface)
00321 {
00322   // Save alpha state and enable it
00323   glPushAttrib (GL_ENABLE_BIT);
00324   glDisable (GL_ALPHA_TEST);
00325   glDisable (GL_LIGHTING);
00326 
00327   glDrawBuffer (GL_BACK);
00328   glDrawPixels (surface->xSize, surface->ySize,
00329     GL_RGBA,
00330     GL_UNSIGNED_BYTE,
00331     surface->drawBuffer);
00332 
00333   // Restore alpha state
00334   glPopAttrib ();
00335 }
00336 
00337 void  BlitTransparent(SSurface *surface, unsigned int rgbTransparentColor)
00338 {
00339   // Save alpha state and enable it
00340   glPushAttrib (GL_ENABLE_BIT);
00341   glEnable (GL_ALPHA_TEST);
00342   glDisable (GL_LIGHTING);
00343 
00344   glDrawBuffer (GL_BACK);
00345   glDrawPixels (surface->xSize, surface->ySize,
00346     GL_RGBA,
00347     GL_UNSIGNED_BYTE,
00348     surface->drawBuffer);
00349 
00350   // Restore alpha state
00351   glPopAttrib ();
00352 }
00353 
00354 
00355 /*
00356  * Font Primitives
00357  *
00358 
00359   int APILoadFont(SFont *font);
00360   void  APIFreeFont(SFont *font);
00361   void  APIDrawText(SSurface *surface, SFont *font, int x, int y, unsigned int rgbColor, const char *text);
00362   void  APIDrawTextC(SSurface *surface, SFont *font, int x, int y, unsigned int rgbColor, const char *text);
00363   void  APIDrawTextR(SSurface *surface, SFont *font, int x, int y, unsigned int rgbColor, const char *text);
00364   int APITextHeight(SFont *font, const char *text);
00365   int APITextWidth(SFont *font, const char *text);
00366   int APICharHeight(SFont *font, char c);
00367   int APICharWidth(SFont *font, char c);
00368   int APIMaxCharHeight(SFont *font);
00369   int APIMaxCharWidth(SFont *font);
00370 
00371  *
00372  */
00373 
00374 
00375 
00376 //
00377 // PBM (Single-frame) Bitmap
00378 //
00379 
00380 class CBitmapPBM {
00381 public:
00382   // Constructors
00383   CBitmapPBM (const char* pbmFilename = NULL);
00384   ~CBitmapPBM (void);
00385 
00386   void Load (PODFILE *pbm, PODFILE *act);
00387   void GetSize (int *x_size, int *y_size);
00388   void Draw (SSurface *surface, int x, int y);
00389   void DrawPartial (SSurface *surface, int x, int y, int x1, int y1, int x2, int y2);
00390 
00391 protected:
00392   char     pbmFilename[64];
00393   RGB      *palette;
00394   GLubyte  *image;
00395   int      width, height;
00396 };
00397 
00398 
00399 CBitmapPBM::CBitmapPBM (const char *pbmName)
00400 {
00401   // Initialize
00402   image = NULL;
00403   width = height = 0;
00404 
00405   if (pbmName != NULL) {
00406     strcpy (pbmFilename, pbmName);
00407 
00408     // Construct full names for PBM and ACT files
00409     char pbmFilename[256];
00410     char actFilename[256];
00411     strcpy (pbmFilename, pbmName);
00412 
00413     strcpy (actFilename, pbmFilename);
00414     char *pExt = strrchr (actFilename, '.');
00415     if (pExt != NULL) {
00416       pExt++;
00417       strcpy (pExt, "ACT");
00418     } else {
00419       gtfo ("CBitmapPBM : Invalid PBM filename %s", pbmFilename);
00420     }
00421 
00422     // Open PBM and ACT files in default pod filesystem
00423     PODFILE* pbm = popen (&globals->pfs, pbmFilename);
00424     PODFILE* act = popen (&globals->pfs, actFilename);
00425     if ((pbm != NULL) && (act != NULL)) {
00426       Load (pbm, act);
00427       pclose (pbm);
00428       pclose (act);
00429     } else {
00430       gtfo ("CBitmapPBM : Could not open PBM or ACT file for %s", pbmName);
00431     }
00432   }
00433 }
00434 
00435 CBitmapPBM::~CBitmapPBM (void)
00436 {
00437   delete palette;
00438   delete image;
00439 }
00440 
00441 void CBitmapPBM::GetSize (int *x_size, int *y_size)
00442 {
00443   *x_size = width;
00444   *y_size = height;
00445 }
00446 
00447 void CBitmapPBM::Load (PODFILE *pbm, PODFILE *act)
00448 {
00449   int i;
00450 
00451   if ((pbm == NULL) || (act == NULL)) {
00452     return;
00453   }
00454 
00455   // Load colormap from the ACT file
00456   palette = new RGB[0x100];
00457   pread (palette, 3, 0x100, act);
00458 
00459   // Read PBM header
00460   SPBMHeader h;
00461   pread (&h, sizeof(SPBMHeader), 1, pbm);
00462   if (h.magic != 0x1A4D4250) {    // 'PBM<Esc>' in Little-Endian format
00463     gtfo ("CBitmapPBM : Invalid magic value, %s", pbm->filename);
00464   }
00465   width = h.width;
00466   height = h.height;
00467 
00468   // Read PBM row offset table. This is a list of (height+1) offsets to the
00469   //   start of each row's data.  The last element is the size of the entire
00470   //   data area, which allows for simple calculation of the last row's size
00471   unsigned long *rowOffset = new unsigned long[height+1];
00472   pread (rowOffset, sizeof(unsigned long), height+1, pbm);
00473 
00474   unsigned long *rowLength = new unsigned long[height];
00475   for (i=0; i<height; i++) {
00476     // Calculate data length for this row
00477     rowLength[i] = rowOffset[i+1] - rowOffset[i];
00478   }
00479 
00480   // Pre-load all image data into memory for faster processing
00481   int rowDataSize = rowOffset[height];
00482   unsigned char *rowData = new unsigned char[rowDataSize];
00483   pread (rowData, 1, rowDataSize, pbm);
00484 
00485   // Allocate storage for the 32bpp image
00486   image = new GLubyte[width*height];
00487 
00488   // Initialize entire image to palette index 0 (transparent)
00489   memset (image, 0, width*height);
00490 
00491   for (i=0; i<height; i++) {
00492 
00493     unsigned char *p = &rowData[rowOffset[i]];
00494 
00495     // Each row consists of a series of data chunks, each chunk representing
00496     //   a non-transparent series of pixels.
00497 
00498     // Continue reading data chunks until finished this row
00499     unsigned long iRow = 0;
00500     while (iRow < rowLength[i]) {
00501       // Read pixel colum
00502       short column;
00503       column = *((short*)p);
00504       p += sizeof(short);
00505       iRow += sizeof(short);
00506 
00507       // Read pixel count
00508       short count;
00509       count = *((short*)p);
00510       p += sizeof(short);
00511       iRow += sizeof(short);
00512 
00513       // Read data (palette index) for each pixel in the chunk
00514       for (short j=0; j<count; j++) {
00515         unsigned char iCmap;
00516         iCmap = *p;
00517         p++;
00518         iRow++;
00519 
00520         // Flip image vertically
00521         unsigned int offset = (((height - i - 1) * width) + column + j);
00522 
00523         // Set pixel colour, and transparency to fully opaque
00524         image[offset] = iCmap;
00525       }
00526 
00527       // Pad to next long boundary
00528       while ((iRow % 4) != 0) {
00529         p++;
00530         iRow++;
00531       }
00532     }
00533   }
00534 
00535   // Clean up allocated data
00536   delete rowOffset;
00537   delete rowLength;
00538   delete rowData;
00539 }
00540 
00541 
00542 void CBitmapPBM::Draw (SSurface *surface, int x, int y)
00543 {
00544   if (image == NULL) {
00545     WARNINGLOG ("CBitmapPBM::Draw : Drawing NULL bitmap image for %s", pbmFilename);
00546     return;
00547   }
00548 
00549   // Check that rendered bitmap will fit in the surface
00551   if ((x < 0) || ((unsigned int)(x + width) > surface->xSize)) {
00552 //    gtfo ("CBitmapPBM::Draw outside surface x bounds");
00553   }
00554 
00555   if ((y < 0) || ((unsigned int)(y + height) > surface->ySize)) {
00556 //    gtfo ("CBitmapPBM::Draw outside surface y bounds");
00557   }
00558 
00559   // Copy bitmap pixels to surface image buffer
00560 //  int sybase = surface->ySize - y;
00561   int sybase = surface->ySize - y - height;
00562   for (int i=0; i<height; i++) {
00563     for (int j=0; j<width; j++) {
00564       long bmOffset = ((i * width) + j);
00565       int iCmap = image[bmOffset];
00566 
00567       // Copy only non-transparent pixels to the surface
00568       if (iCmap != 0) {
00569         GLubyte r = palette[iCmap].r;
00570         GLubyte g = palette[iCmap].g;
00571         GLubyte b = palette[iCmap].b;
00572         GLubyte a = 0xFF;
00573         unsigned int rgba = MakeRGBA (r, g, b, a);
00574 
00575         // Copy pixel value to surface buffer, clipping against edges
00576         int sx = x+j;
00577         int sy = sybase+i;
00578         if ((sx >= 0) && (sx <= (int)surface->xSize) &&
00579             (sy >= 0) && (sy <= (int)surface->ySize))
00580         {
00581           int surfOffset = (sy * surface->xSpan) + sx;
00582           surface->drawBuffer[surfOffset] = rgba;
00583         }
00584       }
00585     }
00586   }
00587 }
00588 
00589 void CBitmapPBM::DrawPartial (SSurface *surface, int x, int y,
00590                               int x1, int y1, int x2, int y2)
00591 {
00592   // Check that rendered bitmap will fit in the surface
00593   int wDraw = x2 - x1;
00594   int hDraw = y2 - y1;
00595 
00597   if ((x < 0) || ((unsigned int)(x + wDraw) > surface->xSize)) {
00598 //    gtfo ("CBitmapPBM::Draw outside surface x bounds");
00599   }
00600 
00601   if ((y < 0) || ((unsigned int)(y + hDraw) > surface->ySize)) {
00602 //    gtfo ("CBitmapPBM::Draw outside surface y bounds");
00603   }
00604 
00605   // Copy bitmap pixels to surface image buffer
00606   int sybase = surface->ySize - y - hDraw;
00607   for (int i=0; i<hDraw; i++) {
00608     for (int j=0; j<wDraw; j++) {
00609       long bmOffset = (((y1 + i) * width) + (x1 + j));
00610       int iCmap = image[bmOffset];
00611 
00612       // Copy only non-transparent pixels to the surface
00613       if (iCmap != 0) {
00614         GLubyte r = palette[iCmap].r;
00615         GLubyte g = palette[iCmap].g;
00616         GLubyte b = palette[iCmap].b;
00617         GLubyte a = 0xFF;
00618         unsigned int rgba = MakeRGBA (r, g, b, a);
00619 
00620         // Copy pixel value to surface buffer, clipping against edges
00621         int sx = x+j;
00622         int sy = sybase+i;
00623         if ((sx >= 0) && (sx < (int)surface->xSize) &&
00624             (sy >= 0) && (sy < (int)surface->ySize))
00625         {
00626           int surfOffset = (sy * surface->xSpan) + sx;
00627           surface->drawBuffer[surfOffset] = rgba;
00628         }
00629       }
00630     }
00631   }
00632 }
00633 
00634 
00635 //
00636 // PBG (Multi-frame) Bitmap
00637 //
00638 
00639 class CBitmapPBG {
00640 public:
00641   // Constructor
00642   CBitmapPBG (const char* pbgFilename);
00643   ~CBitmapPBG (void);
00644 
00645   // CBitmapPBG methods
00646   void  Load (PODFILE *pbm, PODFILE *act);
00647   void  GetSize (int *x_size, int *y_size);
00648   int   GetNumFrames (void);
00649   void  Draw (SSurface *surface, int x, int y, int frame);
00650   void  DrawPartial (SSurface *surface, int x, int y,
00651                      int x1, int y1, int x2, int y2, int frame);
00652 
00653 protected:
00654   int                 nFrames;  
00655   vector<CBitmapPBM*> pbm;      
00656 };
00657 
00658 CBitmapPBG::CBitmapPBG (const char *pbgName)
00659 {
00660   // Initialize
00661   nFrames = 0;
00662 
00663   if (pbgName != NULL) {
00664     // Construct full names for PBG and ACT files
00665     char pbgFilename[256];
00666     char actFilename[256];
00667     strcpy (pbgFilename, pbgName);
00668 
00669     strcpy (actFilename, pbgFilename);
00670     char *pExt = strrchr (actFilename, '.');
00671     if (pExt != NULL) {
00672       pExt++;
00673       strcpy (pExt, "ACT");
00674     } else {
00675       gtfo ("CBitmapPBG : Invalid PBG filename %s", pbgFilename);
00676     }
00677 
00678     // Open PBM and ACT files in default pod filesystem
00679     PODFILE* pbg = popen (&globals->pfs, pbgFilename);
00680     PODFILE* act = popen (&globals->pfs, actFilename);
00681     Load (pbg, act);
00682     pclose (pbg);
00683     pclose (act);
00684   }   
00685 }
00686 
00687 CBitmapPBG::~CBitmapPBG (void)
00688 {
00689   vector<CBitmapPBM*>::iterator i;
00690   for (i=pbm.begin(); i!=pbm.end(); i++) {
00691     CBitmapPBM *bm = *i;
00692     delete bm;
00693   }
00694 }
00695 
00696 int CBitmapPBG::GetNumFrames (void)
00697 {
00698   return nFrames;
00699 }
00700 
00701 typedef struct {
00702   unsigned long magic;
00703   unsigned long nFrames;
00704 } SPBGHeader;
00705 
00706 void CBitmapPBG::Load (PODFILE *pbg, PODFILE *act)
00707 {
00708   if ((pbg == NULL) || (act == NULL)) {
00709     return;
00710   }
00711 
00712   // Read PBG header
00713   SPBGHeader h;
00714   pread (&h, sizeof(SPBGHeader), 1, pbg);
00715   if (h.magic != 0x1A474250) {    // 'PBG<Esc>' in Little-Endian format
00716     gtfo ("CBitmapPBG : Invalid magic value, %s", pbg->filename);
00717   }
00718   nFrames = h.nFrames;
00719 
00720   for (int i=0; i<nFrames; i++) {
00721     CBitmapPBM *bm = new CBitmapPBM;
00722     prewind (act);
00723     bm->Load (pbg, act);
00724     pbm.push_back (bm);
00725   }
00726 }
00727 
00728 
00729 void CBitmapPBG::GetSize (int *x, int *y)
00730 {
00731   if (pbm.size() > 0) {
00732     // Get size of first PBM entry (assume they are all the same size!)
00733     pbm[0]->GetSize (x, y);
00734   } else {
00735     // Zero frames ?
00736     *x = 0;
00737     *y = 0;
00738   }
00739 }
00740 
00741 
00742 void CBitmapPBG::Draw (SSurface *surface, int x, int y, int frame)
00743 {
00744   if (frame < nFrames) {
00745     CBitmapPBM *bm = pbm[frame];
00746     bm->Draw (surface, x, y);
00747   }
00748 }
00749 
00750 void CBitmapPBG::DrawPartial (SSurface *surface, int x, int y,
00751                               int x1, int y1, int x2, int y2, int frame)
00752 {
00753   if (frame < nFrames) {
00754     CBitmapPBM *bm = pbm[frame];
00755     bm->DrawPartial (surface, x, y, x1, y1, x2, y2);
00756   }
00757 }
00758 
00759 
00760 /*
00761  * Bitmap primitives
00762  */
00763 
00764 int   LoadBitmap(SBitmap *bm)
00765 {
00766   int rc = false;
00767 
00768   bm->type = TYPE_INVALID;
00769   bm->bitmap = NULL;
00770 
00771   char *p = strrchr (bm->bitmapName, '.');
00772   if (p) {
00773     // File has an extension, now check for valid bitmaps
00774     if (stricmp (p, ".PBM") == 0) {
00775       bm->type = TYPE_SINGLE;
00776       bm->bitmap = new CBitmapPBM (bm->bitmapName);
00777       rc = true;
00778     } else if (stricmp (p, ".PBG") == 0) {
00779       bm->type = TYPE_FRAMES;
00780       bm->bitmap = new CBitmapPBG (bm->bitmapName);
00781       rc = true;
00782     } else {
00783       gtfo ("LoadBitmap : Invalid bitmap name %s", bm->bitmapName);
00784     }
00785   }
00786 
00787   return rc;
00788 }
00789 
00790 
00791 //
00792 // Draw a PBM/PBG bitmap onto the specified surface.  The 'frame' parameter is
00793 //  only relevant for multi-frame PBG bitmaps.  The 'x' and 'y' parameters
00794 //  indicate the location of the top-left corner of the bitmap relative to
00795 //  the top-left corner of the surface
00796 //
00797 void  DrawBitmap (SSurface *surface, SBitmap *bm, int x, int y, int frame)
00798 {
00799   // PBM/PBG draw methods copy pixels from bottom-up to match the orientation
00800   //   of the SSurface.  Adjust the supplied x,y coordinates from top-left to
00801   //   bottom-left of the bitmap relative to bottom-left of the surface
00802   switch (bm->type) {
00803   case TYPE_SINGLE:
00804     ((CBitmapPBM*)(bm->bitmap))->Draw (surface, x, y);
00805     break;
00806 
00807   case TYPE_FRAMES:
00808     ((CBitmapPBG*)(bm->bitmap))->Draw (surface, x, y, frame);
00809     break;
00810     
00811   default:
00812     // Invalid bitmap type
00813     gtfo ("DrawBitmap : Invalid bitmap type %d", bm->type);
00814   }
00815 }
00816 
00817 
00818 void  DrawBitmapPartial (SSurface *surf, SBitmap *bm, int x, int y,
00819                          int x1, int y1, int x2, int y2, int frame)
00820 {
00821   // PBM/PBG draw methods copy pixels from bottom-up to match the orientation
00822   //   of the SSurface.  Adjust the supplied x,y coordinates from top-left to
00823   //   bottom-left of the bitmap relative to bottom-left of the surface
00824   switch (bm->type) {
00825   case TYPE_SINGLE:
00826     ((CBitmapPBM*)(bm->bitmap))->DrawPartial (surf, x, y, x1, y1, x2, y2);
00827     break;
00828 
00829   case TYPE_FRAMES:
00830     ((CBitmapPBG*)(bm->bitmap))->DrawPartial (surf, x, y, x1, y1, x2, y2, frame);
00831     break;
00832 
00833   default:
00834     // Invalid bitmap type
00835     gtfo ("DrawBitmapPartial : Invalid bitmap type %d", bm->type);
00836   }
00837 }
00838 
00839 
00840 void  GetBitmapSize(SBitmap *bm, int *xSize, int *ySize)
00841 {
00842   switch (bm->type) {
00843   case TYPE_SINGLE:
00844     ((CBitmapPBM*)(bm->bitmap))->GetSize (xSize, ySize);
00845     break;
00846 
00847   case TYPE_FRAMES:
00848     ((CBitmapPBG*)(bm->bitmap))->GetSize (xSize, ySize);
00849     break;
00850 
00851   default:
00852     // Invalid bitmap type
00853     gtfo ("GetBitmapSize : Invalid bitmap type %d", bm->type);
00854   }
00855 }
00856 
00857 
00858 int NumBitmapFrames(SBitmap *bm)
00859 {
00860   int rc = 0;
00861 
00862   switch (bm->type) {
00863   case TYPE_SINGLE:
00864     rc = 1;
00865     break;
00866 
00867   case TYPE_FRAMES:
00868     rc = ((CBitmapPBG*)(bm->bitmap))->GetNumFrames ();
00869     break;
00870 
00871   default:
00872     rc = 0;
00873   }
00874 
00875   return rc;
00876 }
00877 
00878 void FreeBitmap(SBitmap *bm)
00879 {
00880   switch (bm->type) {
00881   case TYPE_SINGLE:
00882     delete (CBitmapPBM *)(bm->bitmap);
00883     break;
00884 
00885   case TYPE_FRAMES:
00886     delete (CBitmapPBG *)(bm->bitmap);
00887     break;
00888 
00889   default:
00890     // Invalid bitmap type
00891     gtfo ("FreeBitmap : Invalid bitmap type %d", bm->type);
00892   }
00893   bm->bitmap = NULL;
00894   bm->type = TYPE_INVALID;
00895 }
00896 
SourceForge.net Logo Documentation generated by doxygen