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

RawImage.cpp

Go to the documentation of this file.
00001 /*
00002  * RawImage.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/Utility.h"
00029 
00030 
00031 //
00032 // Define the following macro to have all RAW images flipped left-right
00033 //   when loaded.
00034 //
00035 // #define RAW_FLIP_LEFT_RIGHT
00036 // #define MASK_FLIP_LEFT_RIGHT
00037 
00038 
00039 /*
00040  * CMaskImage
00041  *
00042  * A mask image is a special type of RAW file used to represent a bitmask for
00043  *   overlaying one texture on top of another.  There is no need for either the
00044  *   ACT or OPA files; the RAW image data represents an 8-bit grayscale mask.
00045  *
00046  */
00047 
00048 //
00049 // Constructor for creating a "blank" mask image
00050 //
00051 CMaskImage::CMaskImage (int width, int height)
00052 {
00053   strcpy (this->name, "NoName");
00054   this->width = width;
00055   this->height = height;
00056   this->rawdata = new GLubyte[width * height];
00057   memset (this->rawdata, 0, width * height);
00058 }
00059 
00060 //
00061 // This constructor accepts a predefined buffer containing the mask data
00062 //
00063 CMaskImage::CMaskImage (int width, int height, const GLubyte *data)
00064 {
00065   strcpy (this->name, "NoName");
00066   this->width = width;
00067   this->height = height;
00068   this->rawdata = new GLubyte[width * height];
00069   memcpy (this->rawdata, data, width * height);
00070 }
00071 
00072 //
00073 // This constructor accepts a RAW filename from which the mask data is loaded
00074 //
00075 CMaskImage::CMaskImage (int width, int height, const char* rawFilename)
00076 {
00077   // Initialize data members
00078   strcpy (this->name, rawFilename);
00079   this->width = width;
00080   this->height = height;
00081 
00082   // Open RAW pod file
00083   PODFILE *pRaw = popen (&globals->pfs, rawFilename);
00084   if (!pRaw) {
00085     gtfo ("CMaskImage : Cannot open file %s", rawFilename);
00086     return;
00087   }
00088 
00089   // Load image data
00090   rawdata = new GLubyte[width * height];
00091   pread (rawdata, (width * height), 1, pRaw);
00092   pclose (pRaw);
00093 }
00094 
00095 CMaskImage::CMaskImage (const CMaskImage &src)
00096 {
00097   width = src.width;
00098   height = src.height;
00099 
00100   // Copy data
00101   rawdata = new GLubyte[width * height];
00102   memcpy (rawdata, src.rawdata, width * height);
00103 }
00104 
00105 CMaskImage::~CMaskImage (void)
00106 {
00107   delete rawdata;
00108 }
00109 
00110 int CMaskImage::GetWidth (void)
00111 {
00112   return width;
00113 }
00114 
00115 int CMaskImage::GetHeight (void)
00116 {
00117   return height;
00118 }
00119 
00120 
00121 /*
00122  * CRawImage
00123  */
00124 
00125 CRawImage::CRawImage (const char* rawFilename,
00126                       const char* actFilename,
00127                       const char* opaFilename)
00128 {
00129   Init ();
00130 
00131   // Open RAW file and get the file size
00132   PODFILE *pRaw = popen (&globals->pfs, rawFilename);
00133   if (!pRaw) {
00134     gtfo ("CRawImage : Cannot open file %s", rawFilename);
00135   }
00136   int rawSize = pRaw->size;
00137   pclose (pRaw);
00138 
00139   // Calculate side length and verify that the image is square
00140   int size = (int)(sqrt((double)rawSize));
00141   if ((size * size) != rawSize) {
00142     gtfo ("CRawImage : Image %s is not square; cannot auto-determine size", rawFilename);
00143     return;
00144   }
00145 
00146   // Initialize data members
00147   strcpy (name, rawFilename);
00148   width = height = size;
00149 
00150   // Load image data
00151   Load (rawFilename, actFilename, opaFilename);
00152 }
00153 
00154 
00155 CRawImage::CRawImage (int width,
00156                       int height,
00157                       const char* rawFilename,
00158                       const char* actFilename,
00159                       const char* opaFilename)
00160 {
00161   Init ();
00162 
00163   // Initialize data members
00164   strcpy (name, rawFilename);
00165   this->width = width;
00166   this->height = height;
00167   
00168   // Load image data
00169   Load (rawFilename, actFilename, opaFilename);
00170 }
00171 
00172 
00173 void CRawImage::Init (void)
00174 {
00175   actdata = rawdata = opadata = NULL;
00176   xferRed = xferGreen = xferBlue = xferAlpha = NULL;
00177   width = height = 0;
00178   texid = 0;
00179 }
00180 
00181 
00182 //
00183 // Load the image data from the specified pod files.  Class members 'width' and 'height'
00184 //   must already have been initialized
00185 //
00186 void CRawImage::Load (const char *rawFilename,
00187                       const char *actFilename,
00188                       const char *opaFilename)
00189 {
00190   // Initialize data buffer pointers
00191   actdata = NULL;
00192   rawdata = NULL;
00193   opadata = NULL;
00194 
00195   // Validate that width and height have been initialized
00196   if ((width == 0) || (height == 0)) {
00197     return;
00198   }
00199 
00200   // Open ACT pod file
00201   PODFILE *pAct = NULL;
00202   if (actFilename == NULL) {
00203     // Derive ACT filename from RAW file
00204     char actName[64];
00205     strcpy (actName, rawFilename);
00206     char *p = strrchr (actName, '.');
00207     if (p) {
00208       strcpy (p, ".ACT");
00209       pAct = popen (&globals->pfs, actName);
00210     } else {
00211       gtfo ("CRawImage : Could not derive ACT filename for %s", rawFilename);
00212     }
00213   } else {
00214     // ACT filename was supplied
00215     pAct = popen (&globals->pfs, actFilename);
00216   }
00217   if (!pAct) {
00218     gtfo ("CRawImage : Cannot open file %s", actFilename);
00219     return;
00220   }
00221 
00222   // Load colour map from ACT file
00223   actdata = new GLubyte[0x300];
00224   pread (actdata, 0x300, 1, pAct);
00225   pclose (pAct);
00226 
00227   // Open RAW pod file
00228   PODFILE *pRaw = popen (&globals->pfs, rawFilename);
00229   if (!pRaw) {
00230     gtfo ("CRawImage : Cannot open file %s", rawFilename);
00231     return;
00232   }
00233 
00234   // Load image data from RAW file
00235   rawdata = new GLubyte[width * height];
00236   pread (rawdata, (width * height), 1, pRaw);
00237   pclose (pRaw);
00238 
00239   // Open OPA data file if the filename has been specified
00240   PODFILE *pOpa = NULL;
00241   if (opaFilename != NULL) {
00242     pOpa = popen (&globals->pfs, opaFilename);
00243     if (!pOpa) {
00244       gtfo ("CRawImage : Cannot open file %s", opaFilename);
00245     }
00246 
00247     opadata = new GLubyte [width * height];
00248     pread (opadata, (width * height), 1, pOpa);
00249     pclose (pOpa);
00250   }
00251 }
00252 
00253 
00254 CRawImage::CRawImage (const CRawImage &src)
00255 {
00256   Init ();
00257   Copy (src);
00258 }
00259 
00260 CRawImage::~CRawImage (void)
00261 {
00262   delete actdata;
00263   delete rawdata;
00264   delete opadata;
00265   delete xferRed;
00266   delete xferGreen;
00267   delete xferBlue;
00268   delete xferAlpha;
00269 }
00270 
00271 int CRawImage::GetWidth (void)
00272 {
00273   return width;
00274 }
00275 
00276 int CRawImage::GetHeight (void)
00277 {
00278   return height;
00279 }
00280 
00281 void CRawImage::SetName (const char* name)
00282 {
00283   strcpy (this->name, name);
00284 }
00285 
00286 void CRawImage::Copy (const CRawImage &src)
00287 {
00288   width = src.width;
00289   height = src.height;
00290   strcpy (name, src.name);
00291   actdata = NULL;
00292   rawdata = NULL;
00293   opadata = NULL;
00294 
00295   // Copy all data
00296   if (src.actdata != NULL) {
00297     actdata = new GLubyte[0x300];
00298     memcpy (actdata, src.actdata, 0x300);
00299   }
00300 
00301   if (src.rawdata != NULL) {
00302     rawdata = new GLubyte[width * height];
00303     memcpy (rawdata, src.rawdata, (width * height));
00304   }
00305 
00306   if (src.opadata != NULL) {
00307     opadata = new GLubyte[width * height];
00308     memcpy (opadata, src.opadata, (width * height));
00309   }
00310 }
00311 
00312 
00313 //
00314 // Create pixel transfer maps to be used when texture is created
00315 //
00316 void CRawImage::CreateTransferMaps (void)
00317 {
00318   // Transfer ACT data into floating-point pixel transfer arrays
00319   xferRed = new GLfloat[0x100];
00320   xferGreen = new GLfloat[0x100];
00321   xferBlue = new GLfloat[0x100];
00322   GLubyte *p = actdata;
00323   for (int i=0; i<0x100; i++) {
00324     xferRed[i] = (float)(*p++) / 256.0f;
00325     xferGreen[i] = (float)(*p++) / 256.0f;
00326     xferBlue[i] = (float)(*p++) / 256.0f;
00327   }
00328 
00329   if (opadata != NULL) {
00330     // Transfer OPA data into floating-point alpha pixel transfer array
00331     xferAlpha = new GLfloat[0x100];
00332     GLubyte *p = opadata;
00333     for (int i=0; i<0x100; i++) {
00334       xferAlpha[i] = (float)(*p++) / 256.0f;
00335     }
00336   }
00337 }
00338 
00339 
00340 void CRawImage::Merge (const CRawImage *raw, const CMaskImage *mask, int actOffset)
00341 {
00342   if ((raw != NULL) && (mask != NULL)) {
00343     // Copy palette
00344     memcpy (&actdata[actOffset * 3], &raw->actdata[0], 0x40 * 3);
00345 
00346     // Overwrite current image data when corresponding mask bit is non-zero
00347     int offset = 0;
00348     for (int i=0; i<height; i++) {
00349       for (int j=0; j<width; j++, offset++) {
00350         if (mask->rawdata[offset] != 0) {
00351           this->rawdata[offset] = raw->rawdata[offset] + actOffset;
00352         }
00353       }
00354     }
00355   }
00356 }
00357 
00358 
00359 //
00360 // This function merges a total of four terrain detail tile textures ('this'
00361 //   image plus the three specified in the arguments) using the supplied masks.
00362 //   The current implementation relies on the fact that original Fly! II
00363 //   detail tile textures use only 0x40 palette indices each.
00364 //
00365 void CRawImage::MergeTransitions (const CRawImage *bRaw, const CMaskImage *bMask,
00366                                   const CRawImage *xRaw, const CMaskImage *xMask,
00367                                   const CRawImage *yRaw, const CMaskImage *yMask)
00368 {
00369   // Merge bottom transition
00370   Merge (bRaw, bMask, 0x40);
00371 
00372   // Merge right-side transition
00373   Merge (xRaw, xMask, 0x80);
00374 
00375   // Merge corner transition
00376   Merge (yRaw, yMask, 0xC0);
00377 }
00378 
00379 void CRawImage::CopyMasked (const CRawImage *src, const CMaskImage *mask)
00380 {
00382 /*
00383   for (int i=0; i<height; i++) {
00384     for (int j=0; j<width; j++) {
00385       // Calculate offsets
00386       int image_offset = ((i * width) + j) * depth;
00387       int mask_offset = (i * width) + j;
00388 
00389       float weight = (float)(mask->image[mask_offset] / 255);
00390       for (int k=0; k<3; k++) {
00391         char this_c = image[image_offset + k];
00392         char src_c = src->image[image_offset + k];
00393         char new_c = (char)((weight * (float)src_c) +
00394                           ((1.0 - weight) * (float)this_c));
00395         image[image_offset + k] = new_c;
00396       }
00397     }
00398   }
00399 */
00400 }
00401 
00402 
00403 GLubyte *CRawImage::GetRGBImageData (void)
00404 {
00405   int depth = 3;
00406   GLubyte *image = new GLubyte [width * height * depth];
00407 
00408   for (int i=0; i<height; i++) {
00409     for (int j=0; j<width; j++) {
00410 
00411 #ifdef RAW_FLIP_LEFT_RIGHT
00412       long iRaw = (i * width) + j;
00413       long iImg = ((i * width) + (width - j - 1)) * depth;
00414 #else
00415       long iSrc = (i * width) + j;
00416       long iImg = ((i * width) + j) * depth;
00417 #endif
00418       // Read colormap index from the raw image data
00419       GLubyte iCmap = rawdata[iSrc];
00420 
00421       image[iImg + 0] = actdata[iCmap * 3 + 0];
00422       image[iImg + 1] = actdata[iCmap * 3 + 1];
00423       image[iImg + 2] = actdata[iCmap * 3 + 2];
00424     }
00425   }
00426 
00427   return image;
00428 }
00429 
00430 GLubyte *CRawImage::GetRGBAImageData (void)
00431 {
00432   int depth = 4;
00433   GLubyte *image = new GLubyte [width * height * depth];
00434 
00435   for (int i=0; i<height; i++) {
00436     for (int j=0; j<width; j++) {
00437 
00438 #ifdef RAW_FLIP_LEFT_RIGHT
00439       long iRaw = (i * width) + j;
00440       long iImg = ((i * width) + (width - j - 1)) * depth;
00441 #else
00442       long iSrc = (i * width) + j;
00443       long iImg = ((i * width) + j) * depth;
00444 #endif
00445       // Read colormap index from the raw image data
00446       GLubyte iCmap = rawdata[iSrc];
00447 
00448       image[iImg + 0] = actdata[iCmap * 3 + 0];
00449       image[iImg + 1] = actdata[iCmap * 3 + 1];
00450       image[iImg + 2] = actdata[iCmap * 3 + 2];
00451 
00452       // Read opacity from OPA file, or default to 0xFF (opaque)
00453       GLubyte opa = (GLubyte)0xFF;
00454       if (opadata != NULL) {
00455         opa = opadata [(i * width) + j];
00456       }
00457       image[iImg + 3] = opa;
00458     }
00459   }
00460 
00461   return image;
00462 }
00463 
00464 /*
00465 GLuint CRawImage::GetTexture (bool mipmap)
00466 {
00467   // Create a GL texture
00468   glGenTextures (1, &texid);
00469   glBindTexture (GL_TEXTURE_2D, texid);
00470   glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
00471   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
00472   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
00473   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
00474 
00475   GLenum format = GL_RGB;
00476   int depth = 3;
00477   GLubyte *image = NULL;
00478   if (opadata == NULL) {
00479     // OPA data does not exist, texture is in RGB format
00480     format = GL_RGB;
00481     depth = 3;
00482     image = GetRGBImageData ();
00483   } else {
00484     // OPA data exists, get RGBA format data
00485     format = GL_RGBA;
00486     depth = 4;
00487     image = GetRGBAImageData ();
00488   }
00489 
00490   if (image != NULL) {
00491     if (mipmap) {
00492       // Generate mipmapped texture
00493       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00494       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
00495 
00496       gluBuild2DMipmaps (GL_TEXTURE_2D, depth, width, height, format,
00497         GL_UNSIGNED_BYTE, image);
00498     } else {
00499       // Generate non-mipmapped texture
00500       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00501       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00502 
00503       glTexImage2D (GL_TEXTURE_2D, 0, format, width, height, 0,
00504         format, GL_UNSIGNED_BYTE, image);
00505     }
00506 
00507     // Free image data
00508     free (image);
00509 
00510   } else {
00511     // Error, could not generate image data
00512     globals->logWarning->Write ("CRawImage : Could not generate image data");
00513   }   
00514 
00515   return texid;
00516 }
00517 */
00518 
00519 static int nTextures = 0;
00520 
00521 GLuint CRawImage::GetTexture (bool mipmap)
00522 {
00523   // Check that texture has not already been generated for this image
00524   if (texid != 0) {
00525     gtfo ("CRawImage::GetTexture : Multiple texture generation");
00526   }
00527 
00528   CreateTransferMaps ();
00529 
00530   glPushAttrib (GL_PIXEL_MODE_BIT);
00531 
00532   // Create a GL texture
00533   glGenTextures (1, &texid);
00534   glBindTexture (GL_TEXTURE_2D, texid);
00535   glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
00536   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
00537   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
00538   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
00539 
00540   GLenum format = GL_COLOR_INDEX;
00541   GLint depth = 3;
00542 
00543   // Set up pixel transfer functions for RGB colours
00544   glPixelMapfv (GL_PIXEL_MAP_I_TO_R, 0x100, xferRed);
00545   glPixelMapfv (GL_PIXEL_MAP_I_TO_G, 0x100, xferGreen);
00546   glPixelMapfv (GL_PIXEL_MAP_I_TO_B, 0x100, xferBlue);
00547   if (xferAlpha != NULL) {
00548     glPixelMapfv (GL_PIXEL_MAP_I_TO_A, 0x100, xferAlpha);
00549     depth = 4;
00550   }
00551   glPixelTransferi (GL_MAP_COLOR, true);
00552 
00553   if (mipmap) {
00554     // Generate mipmapped texture
00555     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00556     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
00557 
00558     gluBuild2DMipmaps (GL_TEXTURE_2D, depth, width, height, format, GL_UNSIGNED_BYTE, rawdata);
00559     GLenum e = glGetError();
00560     if (e != GL_NO_ERROR) {
00561       gtfo ("GL Error 0x%08X building 2D mipmaps for %s", e, name);
00562     }
00563   } else {
00564     // Generate non-mipmapped texture
00565     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00566     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00567 
00568     glTexImage2D (GL_TEXTURE_2D, 0, depth, width, height, 0, format, GL_UNSIGNED_BYTE, rawdata);
00569     GLenum e = glGetError();
00570     if (e != GL_NO_ERROR) {
00571       gtfo ("GL Error 0x%08X building 2D texture for %s", e, name);
00572     }
00573   }
00574 
00575   nTextures++;
00576 
00577   glPopAttrib ();
00578 
00579   return texid;
00580 }
00581 
00582 
00583 void CRawImage::FreeTexture (void)
00584 {
00585   glDeleteTextures (1, &texid);
00586 }
00587 
00588 
00589 //
00590 // CSunRawImage
00591 //
00592 // RAW textures used to display the sun are special in that the transparency
00593 //   is implied by the RAW image itself.  That is, there are no OPA files yet
00594 //   the texture is supposed to be transparent.
00595 //
00596 // Try using the pixel colour index as the transparency value
00597 //
00598 CSunRawImage::CSunRawImage (int width,
00599               int height,
00600               const char* rawFilename,
00601               const char* actFilename)
00602               : CRawImage (width, height, rawFilename, actFilename)
00603 {
00604 /*
00605   // Initialize data members
00606   strcpy (name, rawFilename);
00607   this->width = width;
00608   this->height = height;
00609   
00610   actdata = NULL;
00611   rawdata = NULL;
00612   opadata = NULL;
00613 
00614   // Open ACT pod file
00615   PODFILE *pAct = popen (&globals->pfs, actFilename);
00616   if (!pAct) {
00617     gtfo ("CSunRawImage : Cannot open file %s", actFilename);
00618     return;
00619   }
00620 
00621   // Load colour map from ACT file
00622   actdata = new GLubyte[0x300];
00623   pread (actdata, 0x300, 1, pAct);
00624   pclose (pAct);
00625 
00626   // Open RAW pod file
00627   PODFILE *pRaw = popen (&globals->pfs, rawFilename);
00628   if (!pRaw) {
00629     globals->logWarning->Write ("CRawImage : Cannot open file %s", rawFilename);
00630     return;
00631   }
00632 
00633   // Load image data
00634   rawdata = new GLubyte[width * height];
00635   pread (rawdata, (width * height), 1, pRaw);
00636   pclose (pRaw);
00637 */
00638   opadata = new GLubyte [width * height];
00639   memcpy (opadata, rawdata, (width * height));
00640 }
00641 
SourceForge.net Logo Documentation generated by doxygen