vgafile.cc

Go to the documentation of this file.
00001 /*
00002  *  vgafile.cc - Handle access to one of the xxx.vga files.
00003  *
00004  *  Copyright (C) 1999  Jeffrey S. Freedman
00005  *  Copyright (C) 2000-2001  The Exult Team
00006  *
00007  *  This program is free software; you can redistribute it and/or modify
00008  *  it under the terms of the GNU General Public License as published by
00009  *  the Free Software Foundation; either version 2 of the License, or
00010  *  (at your option) any later version.
00011  *
00012  *  This program is distributed in the hope that it will be useful,
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *  GNU General Public License for more details.
00016  *
00017  *  You should have received a copy of the GNU General Public License
00018  *  along with this program; if not, write to the Free Software
00019  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00020  */
00021 
00022 #ifdef HAVE_CONFIG_H
00023 #  include <config.h>
00024 #endif
00025 
00026 #ifndef ALPHA_LINUX_CXX
00027 #  include <cstring>
00028 #endif
00029 #include "utils.h"
00030 #include "rect.h"
00031 #include "ibuf8.h"
00032 #include "vgafile.h"
00033 #include "databuf.h"
00034 #include "Flex.h"
00035 #include "exceptions.h"
00036 
00037 #include <cassert>
00038 
00039 #ifndef UNDER_CE
00040 using std::cerr;
00041 using std::cout;
00042 using std::endl;
00043 using std::ifstream;
00044 using std::ios;
00045 using std::memcpy;
00046 using std::memset;
00047 using std::ostream;
00048 #endif
00049 
00050 GL_manager *Shape_frame::glman = 0;
00051 Image_buffer8 *Shape_frame::scrwin = 0;
00052 
00053 #if 1 /* For debugging. */
00054 #include <iomanip>
00055 #include "items.h"
00056 #endif
00057 
00058 /*
00059  *  +++++Debugging
00060  */
00061 inline void Check_file
00062   (
00063   ifstream& shapes
00064   )
00065   {
00066   if (!shapes.good())
00067     {
00068     cout << "VGA file is bad!" << endl;
00069     shapes.clear();
00070     }
00071   }
00072 
00073 /*
00074  *  Create a new frame by reflecting across a line running NW to SE.
00075  *
00076  *  May return 0.
00077  */
00078 
00079 Shape_frame *Shape_frame::reflect
00080   (
00081   )
00082   {
00083   if (!data)
00084     return 0;
00085   int w = get_width(), h = get_height();
00086   if (w < h)
00087     w = h;
00088   else
00089     h = w;      // Use max. dim.
00090   Shape_frame *reflected = new Shape_frame();
00091   reflected->rle = true;    // Set data.
00092   reflected->xleft = yabove;
00093   reflected->yabove = xleft;
00094   reflected->xright = ybelow;
00095   reflected->ybelow = xright;
00096           // Create drawing area.
00097   Image_buffer8 *ibuf = new Image_buffer8(h, w);
00098   ibuf->fill8(255);   // Fill with 'transparent' pixel.
00099           // Figure origin.
00100   int xoff = reflected->xleft, yoff = reflected->yabove;
00101   uint8 *in = data;   // Point to data, and draw.
00102   int scanlen;
00103   while ((scanlen = Read2(in)) != 0)
00104     {
00105           // Get length of scan line.
00106     int encoded = scanlen&1;// Is it encoded?
00107     scanlen = scanlen>>1;
00108     short scanx = Read2(in);
00109     short scany = Read2(in);
00110     if (!encoded)   // Raw data?
00111       {
00112       ibuf->copy8(in, 1, scanlen,
00113           xoff + scany, yoff + scanx);
00114       in += scanlen;
00115       continue;
00116       }
00117     for (int b = 0; b < scanlen; )
00118       {
00119       unsigned char bcnt = *in++;
00120           // Repeat next char. if odd.
00121       int repeat = bcnt&1;
00122       bcnt = bcnt>>1; // Get count.
00123       if (repeat)
00124         {
00125         unsigned char pix = *in++;
00126         ibuf->fill8(pix, 1, bcnt,
00127           xoff + scany, yoff + scanx + b);
00128         }
00129       else    // Get that # of bytes.
00130         {
00131         ibuf->copy8(in, 1, bcnt,
00132           xoff + scany, yoff + scanx + b);
00133         in += bcnt;
00134         }
00135       b += bcnt;
00136       }
00137     }
00138   reflected->create_rle(ibuf->get_bits(), w, h);
00139   delete ibuf;      // Done with this.
00140   return (reflected);
00141   }
00142   
00143 /*
00144  *  Skip transparent pixels.
00145  *
00146  *  Output: Index of first non-transparent pixel (w if no more).
00147  *    Pixels is incremented by (delta x).
00148  */
00149 
00150 static int Skip_transparent
00151   (
00152   unsigned char *& pixels,  // 8-bit pixel scan line.
00153   int x,        // X-coord. of pixel to start with.
00154   int w       // Remaining width of pixels.
00155   )
00156   {
00157   while (x < w && *pixels == 255)
00158     {
00159     x++;
00160     pixels++;
00161     }
00162   return (x);
00163   }
00164 
00165 /*
00166  *  Split a line of pixels into runs, where a run
00167  *  consists of different pixels, or a repeated pixel.
00168  *
00169  *  Output: Index of end of scan line.
00170  */
00171 
00172 static int Find_runs
00173   (
00174   short *runs,      // Each run's length is returned.
00175           // For each byte, bit0==repeat.
00176           // List ends with a 0.
00177   unsigned char *pixels,    // Scan line (8-bit color).
00178   int x,        // X-coord. of pixel to start with.
00179   int w       // Remaining width of pixels.
00180   )
00181   {
00182   int runcnt = 0;     // Counts runs.
00183   while (x < w && *pixels != 255) // Stop at first transparent pixel.
00184     {
00185     int run = 0;    // Look for repeat.
00186     while (x < w - 1 && pixels[0] == pixels[1])
00187       {
00188       x++;
00189       pixels++;
00190       run++;
00191       }
00192     if (run)    // Repeated?  Count 1st, shift, flag.
00193       {
00194       run = ((run + 1)<<1)|1;
00195       x++;    // Also pass the last one.
00196       pixels++;
00197       }
00198     else do     // Pass non-repeated run of
00199       {   //   andy length.
00200       x++;
00201       pixels++;
00202       run += 2; // So we don't have to shift.
00203       }
00204     while (x < w && *pixels != 255 &&
00205       (x == w - 1 || pixels[0] != pixels[1]));
00206           // Store run length.
00207     runs[runcnt++] = run;
00208     }
00209   runs[runcnt] = 0;   // 0-delimit list.
00210   return (x);
00211   }
00212 
00213 /*
00214  *  Encode an 8-bit image into an RLE frame.
00215  *
00216  *  Output: Data is set to compressed image.
00217  */
00218 
00219 void Shape_frame::create_rle
00220   (
00221   unsigned char *pixels,    // 8-bit uncompressed data.
00222   int w, int h      // Width, height.
00223   )
00224   {
00225   delete [] data;     // Delete old data if there.
00226   data = encode_rle(pixels, w, h, xleft, yabove, datalen);
00227   }
00228 
00229 /*
00230  *  Encode an 8-bit image into an RLE frame.
00231  *
00232  *  Output: ->allocated RLE data.
00233  */
00234 
00235 unsigned char *Shape_frame::encode_rle
00236   (
00237   unsigned char *pixels,    // 8-bit uncompressed data.
00238   int w, int h,     // Width, height.
00239   int xoff, int yoff,   // Origin (xleft, yabove).
00240   int& datalen      // Length of RLE data returned.
00241   )
00242   {
00243           // Create an oversized buffer.
00244   uint8 *buf = new uint8[w*h*2 + 16*h];
00245   uint8 *out = buf;
00246   int newx;     // Gets new x at end of a scan line.
00247   for (int y = 0; y < h; y++) // Go through rows.
00248     for (int x = 0; (x = Skip_transparent(pixels, x, w)) < w; 
00249                 x = newx)
00250       {
00251       short runs[100];// Get runs.
00252       newx = Find_runs(runs, pixels, x, w);
00253           // Just 1 non-repeated run?
00254       if (!runs[1] && !(runs[0]&1))
00255         {
00256         int len = runs[0] >> 1;
00257         Write2(out, runs[0]);
00258           // Write position.
00259         Write2(out, x - xoff);
00260         Write2(out, y - yoff);
00261         memcpy(out, pixels, len);
00262         pixels += len;
00263         out += len;
00264         continue;
00265         }
00266           // Encoded, so write it with bit0==1.
00267       Write2(out, ((newx - x)<<1)|1);
00268           // Write position.
00269       Write2(out, x - xoff);
00270       Write2(out, y - yoff);
00271           // Go through runs.
00272       for (int i = 0; runs[i]; i++)
00273         {
00274         int len = runs[i]>>1;
00275           // Check for repeated run.
00276         if (runs[i]&1)
00277           {
00278           while (len)
00279             {
00280             int c = len > 127
00281               ? 127 : len;
00282             *out++ = (c<<1)|1;
00283             *out++ = *pixels;
00284             pixels += c;
00285             len -= c;
00286             }
00287           }
00288         else while (len > 0)
00289           {
00290           int c = len > 127 ? 127 : len;
00291           *out++ = c<<1;
00292           memcpy(out, pixels, c);
00293           out += c;
00294           pixels += c;
00295           len -= c;
00296           }
00297         }
00298       }
00299   Write2(out, 0);     // End with 0 length.
00300   datalen = out - buf;    // Create buffer of correct size.
00301 #ifdef DEBUG
00302   if(datalen > w*h*2 + 16*h)
00303     cout << "create_rle: datalen: " << datalen << " w: " << w
00304       << " h: " << h << endl;
00305 #endif
00306   unsigned char *data = new unsigned char[datalen];
00307   memcpy(data, buf, datalen);
00308   delete [] buf;
00309   return data;
00310   }
00311 
00312 /*
00313  *  Create from data.
00314  */
00315 
00316 Shape_frame::Shape_frame
00317   (
00318   unsigned char *pixels,    // (A copy is made.)
00319   int w, int h,     // Dimensions.
00320   int xoff, int yoff,   // Xleft, yabove.
00321   bool setrle     // Run-length-encode.
00322   ) : xleft(xoff), yabove(yoff), xright(w - xoff - 1),
00323       ybelow(h - yoff - 1), rle(setrle)
00324 #ifdef HAVE_OPENGL
00325     , glshape(0)
00326 #endif
00327   {
00328   if (!rle)
00329     {
00330     assert(w == 8 && h == 8);
00331     datalen = 64;
00332     data = new unsigned char[64];
00333     memcpy(data, pixels, 64);
00334     }
00335   else
00336     data = encode_rle(pixels, w, h, xleft, yabove, datalen);
00337   }
00338 
00339 /*
00340  *  Read in a desired shape.
00341  *
00342  *  Output: # of frames.
00343  */
00344 
00345 unsigned char Shape_frame::read
00346   (
00347   DataSource* shapes,   // Shapes data source to read.
00348   uint32 shapeoff,    // Offset of shape in file.
00349   uint32 shapelen,    // Length expected for detecting RLE.
00350   int frnum     // Frame #.
00351   )
00352   {
00353   int framenum = frnum;
00354   rle = false;
00355   if (!shapelen && !shapeoff) return 0;
00356           // Get to actual shape.
00357   shapes->seek(shapeoff);
00358   uint32 dlen = shapes->read4();
00359   uint32 hdrlen = shapes->read4();
00360   if (dlen == shapelen)
00361     {
00362     rle = true;   // It's run-length-encoded.
00363           // Figure # frames.
00364     int nframes = (hdrlen - 4)/4;
00365     if (framenum >= nframes)// Bug out if bad frame #.
00366       return (nframes);
00367           // Get frame offset, lengeth.
00368     uint32 frameoff, framelen;
00369     if (framenum == 0)
00370       {
00371       frameoff = hdrlen;
00372       framelen = nframes > 1 ? shapes->read4() - frameoff :
00373             dlen - frameoff;
00374       }
00375     else
00376       {
00377       shapes->skip((framenum - 1) * 4);
00378       frameoff = shapes->read4();
00379           // Last frame?
00380       if (framenum == nframes - 1)
00381         framelen = dlen - frameoff;
00382       else
00383         framelen = shapes->read4() - frameoff;
00384       }
00385           // Get compressed data.
00386     get_rle_shape(shapes, shapeoff + frameoff, framelen);
00387           // Return # frames.
00388     return (nframes);
00389     }
00390   framenum &= 31;     // !!!Guessing here.
00391   xleft = yabove = 8;   // Just an 8x8 bitmap.
00392   xright= ybelow = -1;
00393   shapes->seek(shapeoff + framenum*64);
00394   data = new unsigned char[64]; // Read in 8x8 pixels.
00395   datalen = 64;
00396   shapes->read((char *) data, 64);
00397   return (shapelen/64);   // That's how many frames.
00398   }
00399   
00400 /*
00401  *  Read in a Run-Length_Encoded shape.
00402  */
00403 
00404 void Shape_frame::get_rle_shape
00405   (
00406   DataSource* shapes,   // Shapes data source to read.
00407   long filepos,     // Position in file.
00408   long len      // Length of entire frame data.
00409   )
00410   {
00411   shapes->seek(filepos);    // Get to extents.
00412   xright = shapes->read2();
00413   xleft = shapes->read2();
00414   yabove = shapes->read2();
00415   ybelow = shapes->read2();
00416   len -= 8;     // Subtract what we just read.
00417   data = new unsigned char[len + 2];  // Allocate and read data.
00418   datalen = len+2;
00419   shapes->read((char*)data, len);
00420   data[len] = 0;      // 0-delimit.
00421   data[len + 1] = 0;
00422   rle = true;
00423   }
00424   
00425 /*
00426  *  Show a Run-Length_Encoded shape.
00427  */
00428 
00429 void Shape_frame::paint_rle
00430   (
00431   Image_buffer8 *win,   // Buffer to paint in.
00432   int xoff, int yoff    // Where to show in iwin.
00433   )
00434   {
00435   assert(rle);
00436 
00437   int w = get_width(), h = get_height();
00438   if (w >= 8 || h >= 8)   // Big enough to check?  Off screen?
00439     if (!win->is_visible(xoff - xleft, yoff - yabove, w, h))
00440       return;
00441 
00442   win->paint_rle (xoff, yoff, data);
00443   return;
00444   }
00445 
00446 /*
00447  *  Paint either type of shape.
00448  */
00449 
00450 void Shape_frame::paint
00451   (
00452   Image_buffer8 *win,   // Buffer to paint in.
00453   int xoff, int yoff    // Where to show in iwin.
00454   )
00455   {
00456   if (rle)
00457     paint_rle(win, xoff, yoff);
00458   else
00459     win->copy8(data, 8, 8, xoff - 8, yoff - 8);
00460   }
00461 
00462 /*
00463  *  Show a Run-Length_Encoded shape with translucency.
00464  */
00465 
00466 void Shape_frame::paint_rle_translucent
00467   (
00468   Image_buffer8 *win,   // Buffer to paint in.
00469   int xoff, int yoff,   // Where to show in iwin.
00470   Xform_palette *xforms,    // Transforms translucent colors
00471   int xfcnt     // Number of xforms.
00472   )
00473   {
00474   assert(rle);
00475 
00476   int w = get_width(), h = get_height();
00477   if (w >= 8 || h >= 8)   // Big enough to check?  Off screen?
00478     if (!win->is_visible(xoff - xleft, 
00479             yoff - yabove, w, h))
00480       return;
00481           // First pix. value to transform.
00482   const int xfstart = 0xff - xfcnt;
00483   uint8 *in = data;
00484   int scanlen;
00485   while ((scanlen = Read2(in)) != 0)
00486     {
00487           // Get length of scan line.
00488     int encoded = scanlen&1;// Is it encoded?
00489     scanlen = scanlen>>1;
00490     short scanx = Read2(in);
00491     short scany = Read2(in);
00492     if (!encoded)   // Raw data?
00493       {
00494       win->copy_line_translucent8(in, scanlen,
00495           xoff + scanx, yoff + scany,
00496           xfstart, 0xfe, xforms);
00497       in += scanlen;
00498       continue;
00499       }
00500     for (int b = 0; b < scanlen; )
00501       {
00502       unsigned char bcnt = *in++;
00503           // Repeat next char. if odd.
00504       int repeat = bcnt&1;
00505       bcnt = bcnt>>1; // Get count.
00506       if (repeat)
00507         {
00508         unsigned char pix = *in++;
00509         if (pix >= xfstart && pix <= 0xfe)
00510           win->fill_line_translucent8(pix, bcnt,
00511             xoff + scanx + b, yoff + scany,
00512             xforms[pix - xfstart]);
00513         else
00514           win->fill_line8(pix, bcnt,
00515                 xoff + scanx + b, yoff + scany);
00516         }
00517       else    // Get that # of bytes.
00518         {
00519         win->copy_line_translucent8(in, bcnt,
00520           xoff + scanx + b, yoff + scany,
00521           xfstart, 0xfe, xforms);
00522         in += bcnt;
00523         }
00524       b += bcnt;
00525       }
00526     }
00527   }
00528 
00529 /*
00530  *  Paint a shape purely by translating the pixels it occupies.  This is
00531  *  used for invisible NPC's.
00532  */
00533 
00534 void Shape_frame::paint_rle_transformed
00535   (
00536   Image_buffer8 *win,   // Buffer to paint in.
00537   int xoff, int yoff,   // Where to show in iwin.
00538   Xform_palette& xform    // Use to transform pixels.
00539   )
00540   {
00541   assert(rle);
00542 
00543   int w = get_width(), h = get_height();
00544   if (w >= 8 || h >= 8)   // Big enough to check?  Off screen?
00545     if (!win->is_visible(xoff - xleft, 
00546             yoff - yabove, w, h))
00547       return;
00548   uint8 * in = data;
00549   int scanlen;
00550   while ((scanlen = Read2(in)) != 0)
00551     {
00552           // Get length of scan line.
00553     int encoded = scanlen&1;// Is it encoded?
00554     scanlen = scanlen>>1;
00555     short scanx = Read2(in);
00556     short scany = Read2(in);
00557     if (!encoded)   // Raw data?
00558       {   // (Note: 1st parm is ignored).
00559       win->fill_line_translucent8(0, scanlen,
00560           xoff + scanx, yoff + scany, xform);
00561       in += scanlen;
00562       continue;
00563       }
00564     for (int b = 0; b < scanlen; )
00565       {
00566       unsigned char bcnt = *in++;
00567           // Repeat next char. if odd.
00568       int repeat = bcnt&1;
00569       bcnt = bcnt>>1; // Get count.
00570       in += repeat ? 1 : bcnt;
00571       win->fill_line_translucent8(0, bcnt,
00572         xoff + scanx + b, yoff + scany, xform);
00573       b += bcnt;
00574       }
00575     }
00576   }
00577 
00578 /*
00579  *  Paint outline around a shape.
00580  */
00581 
00582 void Shape_frame::paint_rle_outline
00583   (
00584   Image_buffer8 *win,   // Buffer to paint in.
00585   int xoff, int yoff,   // Where to show in win.
00586   unsigned char color   // Color to use.
00587   )
00588   {
00589   assert(rle);
00590 
00591   int w = get_width(), h = get_height();
00592   if (w >= 8 || h >= 8)   // Big enough to check?  Off screen?
00593     if (!win->is_visible(xoff - xleft, 
00594             yoff - yabove, w, h))
00595       return;
00596   int firsty = -10000;    // Finds first line.
00597   int lasty;
00598   uint8 * in = data;
00599   int scanlen;
00600   while ((scanlen = Read2(in)) != 0)
00601     {
00602           // Get length of scan line.
00603     int encoded = scanlen&1;// Is it encoded?
00604     scanlen = scanlen>>1;
00605     short scanx = Read2(in);
00606     short scany = Read2(in);
00607     int x = xoff + scanx;
00608     int y = yoff + scany;
00609     if (firsty == -10000)
00610       {
00611       firsty = y;
00612       lasty = y + h - 1;
00613       }
00614           // Put pixel at both ends.
00615     win->put_pixel8(color, x, y);
00616     win->put_pixel8(color, x + scanlen - 1, y);
00617 
00618     if (!encoded)   // Raw data?
00619       {
00620       if (y == firsty ||  // First line?
00621           y == lasty)   // Last line?
00622         win->fill_line8(color, scanlen, x, y);
00623       in += scanlen;
00624       continue;
00625       }
00626     for (int b = 0; b < scanlen; )
00627       {
00628       unsigned char bcnt = *in++;
00629           // Repeat next char. if odd.
00630       int repeat = bcnt&1;
00631       bcnt = bcnt>>1; // Get count.
00632       if (repeat) // Pass repetition byte.
00633         in++;
00634       else    // Skip that # of bytes.
00635         in += bcnt;
00636       if (y == firsty ||  // First line?
00637           y == lasty)   // Last line?
00638         win->fill_line8(color, bcnt, x + b, y);
00639       b += bcnt;
00640       }
00641     }
00642   }
00643 
00644 /*
00645  *  See if a point, relative to the shape's 'origin', actually within the
00646  *  shape.
00647  */
00648 
00649 int Shape_frame::has_point
00650   (
00651   int x, int y      // Relative to origin of shape.
00652   )
00653   {
00654   if (!rle)     // 8x8 flat?
00655     {
00656     return x >= -xleft && x < xright &&
00657            y >= -yabove && y < ybelow;
00658     }
00659   uint8 *in = data;     // Point to data.
00660   int scanlen;
00661   while ((scanlen = Read2(in)) != 0)
00662     {
00663           // Get length of scan line.
00664     int encoded = scanlen&1;// Is it encoded?
00665     scanlen = scanlen>>1;
00666     short scanx = Read2(in);
00667     short scany = Read2(in);
00668           // Be liberal by 1 pixel.
00669     if (y == scany && x >= scanx - 1 && x <= scanx + scanlen)
00670       return (1);
00671     if (!encoded)   // Raw data?
00672       {
00673       in += scanlen;
00674       continue;
00675       }
00676     for (int b = 0; b < scanlen; )
00677       {
00678       unsigned char bcnt = *in++;
00679           // Repeat next char. if odd.
00680       int repeat = bcnt&1;
00681       bcnt = bcnt>>1; // Get count.
00682       if (repeat)
00683         in++; // Skip pixel to repeat.
00684       else    // Skip that # of bytes.
00685         in += bcnt;
00686       b += bcnt;
00687       }
00688     }
00689   return (0);     // Never found it.
00690   }
00691 
00692 /*
00693  *  Set new offset, assuming dimensions are unchanged.
00694  */
00695 
00696 void Shape_frame::set_offset
00697   (
00698   int new_xright, int new_ybelow
00699   )
00700   {
00701   if (!rle)
00702     return;     // Can do it for 8x8 tiles.
00703   int w = get_width(), h = get_height();
00704   if (new_xright > w)   // Limit to left edge.
00705     new_xright = w;
00706   if (new_ybelow > h)
00707     new_ybelow = h;
00708   int deltax = new_xright - xright; // Get changes.
00709   int deltay = new_ybelow - ybelow;
00710   xright = new_xright;
00711   ybelow = new_ybelow;
00712   xleft = w - xright - 1;   // Update other dims.
00713   yabove = h - ybelow - 1;
00714   uint8 *in = data;   // Got to update all scan lines!
00715   int scanlen;
00716   while ((scanlen = Read2(in)) != 0)
00717     {
00718           // Get length of scan line.
00719     int encoded = scanlen&1;// Is it encoded?
00720     scanlen = scanlen>>1;
00721     short scanx = Read2(in);
00722     in -= 2;
00723     Write2(in, scanx + deltax);
00724     short scany = Read2(in);
00725     in -= 2;
00726     Write2(in, scany + deltay);
00727           // Just need to scan past EOL.
00728     if (!encoded)   // Raw data?
00729       in += scanlen;
00730     else for (int b = 0; b < scanlen; )
00731       {
00732       unsigned char bcnt = *in++;
00733           // Repeat next char. if odd.
00734       int repeat = bcnt&1;
00735       bcnt = bcnt>>1; // Get count.
00736       if (repeat)
00737         in++; // Skip pixel to repeat.
00738       else    // Skip that # of bytes.
00739         in += bcnt;
00740       b += bcnt;
00741       }
00742     }
00743   }
00744 
00745 /*
00746  *  Create the reflection of a shape.
00747  */
00748 
00749 Shape_frame *Shape::reflect
00750   (
00751   DataSource* shapes,   // shapes data source to read.
00752   int shapenum,     // Shape #.
00753   int framenum      // Frame # without the 'reflect' bit.
00754   )
00755   {
00756           // Get normal frame.
00757   Shape_frame *normal = get(shapes, shapenum, framenum);
00758   if (!normal)
00759     return (0);
00760           // Reflect it.
00761   Shape_frame *reflected = normal->reflect();
00762   if (!reflected)
00763     return (0);
00764   framenum |= 32;     // Put back 'reflect' flag.
00765   if (framenum >= frames_size - 1)// Expand list if necessary.
00766     enlarge(framenum + 1);
00767   frames[framenum] = reflected; // Store new frame.
00768   return reflected;
00769   }
00770 
00771 /*
00772  *  Resize list upwards.
00773  */
00774 
00775 void Shape::enlarge
00776   (
00777   int newsize
00778   )
00779   {
00780   Shape_frame **newframes = new Shape_frame *[newsize];
00781   int i;
00782   for (i = 0; i < frames_size; i++)
00783     newframes[i] = frames[i];
00784   frames_size = newsize;
00785   for ( ; i < frames_size; i++)
00786     newframes[i] = 0;
00787   delete [] frames;
00788   frames = newframes;
00789   }
00790 
00791 /*
00792  *  Resize list.  This is for outside clients, and it sets num_frames.
00793  */
00794 
00795 void Shape::resize
00796   (
00797   int newsize
00798   )
00799   {
00800   if (newsize == frames_size)
00801     return;
00802   if (newsize > frames_size)
00803     enlarge(newsize); // Growing.
00804   else
00805     {     // Shrinking.
00806     Shape_frame **newframes = new Shape_frame *[newsize];
00807     int i;
00808     for (i = 0; i < newsize; i++)
00809       newframes[i] = frames[i];
00810           // Delete past new end.
00811     for ( ; i < frames_size; i++)
00812       delete frames[i];
00813     frames_size = newsize;
00814     delete [] frames;
00815     frames = newframes;
00816     }
00817   num_frames = newsize;
00818   }
00819 
00820 /*
00821  *  Call this to set num_frames, frames_size and create 'frames' list.
00822  */
00823 
00824 inline void Shape::create_frames_list
00825   (
00826   int nframes
00827   )
00828   {
00829   num_frames = frames_size = nframes;
00830   frames = new Shape_frame *[frames_size];
00831   memset((char *) frames, 0, frames_size * sizeof(Shape_frame *));
00832   }
00833 
00834 /*
00835  *  Read in a frame, or convert an existing one if reflection is
00836  *  desired.
00837  *
00838  *  Output: ->frame, or 0 if failed.
00839  */
00840 
00841 Shape_frame *Shape::read
00842   (
00843   DataSource *shapes1,    // Shapes data source to read.
00844   int shapenum,     // Shape #.
00845   int framenum,     // Frame # within shape.
00846   DataSource *shapes2,    // Shapes data source to read (alternative).
00847   int count1,     // Number of shapes in shapes
00848   int count2      // Number of shapes in shapes2
00849   )
00850   {
00851   DataSource *shapes = 0;
00852   Shape_frame *frame = new Shape_frame();
00853           // Figure offset in "shapes.vga".
00854   uint32 shapeoff = 0x80 + shapenum*8;
00855   uint32 shapelen = 0;
00856 
00857   // If shapes2 exists and shapenum is valid for shapes2
00858   if (shapes2 && (count2 == -1 || shapenum < count2))
00859   {
00860     shapes2->seek(shapeoff);
00861             // Get location, length.
00862     int s = shapes2->read4();
00863     shapelen = shapes2->read4();
00864 
00865     if (s && shapelen)
00866     {
00867       shapeoff = s;
00868       shapes = shapes2;
00869     }
00870   }
00871   if (shapes == 0)
00872   {
00873     shapes = shapes1;
00874     if (count1 != -1 && shapenum >= count1)
00875     {
00876       std::cerr << "Shape num out of range: " << shapenum << std::endl;
00877       return 0;
00878     }
00879 
00880     shapes->seek(shapeoff);
00881             // Get location, length.
00882     shapeoff = shapes->read4();
00883     shapelen = shapes->read4();
00884   }
00885   if (!shapelen)
00886     return 0;   // Empty shape.
00887           // Read it in and get frame count.
00888   int nframes = frame->read(shapes, shapeoff, shapelen, framenum);
00889   if (!num_frames)    // 1st time?
00890     create_frames_list(nframes);
00891   if (!frame->rle)
00892     framenum &= 31;   // !!Guessing.
00893   if (framenum >= nframes &&  // Compare against #frames in file.
00894       (framenum&32))    // Reflection desired?
00895     {
00896     delete frame;
00897     return (reflect(shapes, shapenum, framenum&0x1f));
00898     }
00899   return store_frame(frame, framenum);
00900   }
00901 
00902 /*
00903  *  Write a shape's frames as an entry in an Exult .vga file.  Note that
00904  *  a .vga file is a .FLX file with one shape/entry.
00905  *
00906  *  NOTE:  This should only be called if all frames have been read.
00907  */
00908 
00909 void Shape::write
00910   (
00911   ostream& out      // What to write to.
00912   )
00913   {
00914   int frnum;
00915   if (!num_frames)
00916     return;     // Empty.
00917   assert(frames != 0 && *frames != 0);
00918   bool flat = !frames[0]->is_rle();
00919           // Save starting position.
00920   unsigned long startpos = out.tellp();
00921   
00922   if (!flat)
00923     {
00924     Write4(out, 0);   // Place-holder for total length.
00925           // Also for frame locations.
00926     for (frnum = 0; frnum < num_frames; frnum++)
00927       Write4(out, 0);
00928     }
00929   for (frnum = 0; frnum < num_frames; frnum++)
00930     {
00931     Shape_frame *frame = frames[frnum];
00932     assert(frame != 0); // Better all be the same type.
00933     assert(flat == !frame->is_rle());
00934     if (frame->is_rle())
00935       {   
00936           // Get position of frame.
00937       unsigned long pos = out.tellp();
00938       out.seekp(startpos + (frnum + 1)*4);
00939       Write4(out, pos - startpos);  // Store pos.
00940       out.seekp(pos);     // Get back.
00941       Write2(out, frame->xright);
00942       Write2(out, frame->xleft);
00943       Write2(out, frame->yabove);
00944       Write2(out, frame->ybelow);
00945       }
00946     out.write(reinterpret_cast<char *>(frame->data), frame->datalen); // The frame data.
00947     }
00948   if (!flat)
00949     {
00950     unsigned long pos = out.tellp();// Ending position.
00951     out.seekp(startpos);    // Store total length.
00952     Write4(out, pos - startpos);
00953     out.seekp(pos);     // And get back to end.
00954     }
00955   }
00956 
00957 /*
00958  *  Store frame that was read.
00959  *
00960  *  Output: ->frame, or 0 if not valid.
00961  */
00962 
00963 Shape_frame *Shape::store_frame
00964   (
00965   Shape_frame *frame,   // Frame that was read.
00966   int framenum      // It's frame #.
00967   )
00968   {
00969   if (framenum >= frames_size)  // Something fishy?
00970     {
00971     delete frame;
00972     cerr << "Shape::store_frame:  framenum >= frames_size"
00973                 << endl;
00974     return (0);
00975     }
00976   if (!frames)  // First one?
00977     {
00978     frames = new Shape_frame *[num_frames];
00979     memset((char *) frames, 0, num_frames * sizeof(Shape_frame *));
00980     }
00981   frames[framenum] = frame;
00982   return (frame);
00983   }
00984 
00985 /*
00986  *  Create with a single frame.
00987  */
00988 
00989 Shape::Shape(Shape_frame* fr)
00990 {
00991   num_frames = frames_size = 1;
00992   frames = new Shape_frame*[1];
00993   frames[0] = fr;
00994 }
00995 
00996 /*
00997  *  Create with space for a given number of frames.
00998  */
00999 
01000 Shape::Shape
01001   (
01002   int n       // # frames.
01003   )
01004   {
01005   create_frames_list(n);
01006   }
01007 
01008 void Shape::reset()
01009   {
01010   if (frames)
01011     {
01012     for(int i = 0; i < frames_size; i++)
01013       delete frames[i];
01014     delete [] frames;
01015     frames = 0;
01016     }
01017   else if (frames_size)
01018     cerr << "Shape::~Shape(): 'frames' is null, while frames_size="
01019         << (int) frames_size << endl;
01020   }
01021 
01022 /*
01023  *  Take frames from another shape and set that shape to empty.
01024  */
01025 
01026 void Shape::take
01027   (
01028   Shape *sh2
01029   )
01030   {
01031   reset();      // Clear ourself.
01032   frames = sh2->frames;
01033   sh2->frames = 0;
01034   frames_size = sh2->frames_size;
01035   num_frames = sh2->num_frames; 
01036   sh2->num_frames = sh2->frames_size = 0;
01037   }
01038 
01039 /*
01040  *  Load all frames for a single shape.  (Assumes RLE-type shape.)
01041  */
01042 
01043 void Shape::load
01044   (
01045   DataSource* shape_source    // datasource.
01046   )
01047   {
01048   reset();
01049   Shape_frame *frame = new Shape_frame();
01050   uint32 shapelen = shape_source->read4();
01051           // Read frame 0 & get frame count.
01052   create_frames_list(frame->read(shape_source, 0L, shapelen, 0));
01053   store_frame(frame, 0);
01054           // Get the rest.
01055   for (int i = 1; i < num_frames; i++)
01056     {
01057     frame = new Shape_frame();
01058     frame->read(shape_source, 0L, shapelen, i);
01059     store_frame(frame, i);
01060     }
01061   }
01062 
01063 Shape::~Shape()
01064   {
01065   reset();
01066   }
01067 
01068 /*
01069  *  Set desired frame.
01070  */
01071 
01072 void Shape::set_frame
01073   (
01074   Shape_frame *frame,   // Must be allocated.
01075   int framenum
01076   )
01077   {
01078   assert (framenum < num_frames);
01079   delete frames[framenum];  // Delete existing.
01080   frames[framenum] = frame;
01081   }
01082 
01083 /*
01084  *  Add/insert a frame.
01085  */
01086 
01087 void Shape::add_frame
01088   (
01089   Shape_frame *frame,   // Must be allocated.
01090   int framenum      // Insert here.
01091   )
01092   {
01093   assert (framenum <= num_frames);// Can append.
01094   enlarge(frames_size + 1); // Make room.
01095   for (int i = frames_size - 1; i > framenum; i--)
01096     frames[i] = frames[i - 1];
01097   frames[framenum] = frame;
01098   num_frames++;
01099   }
01100 
01101 /*
01102  *  Delete a frame.
01103  */
01104 
01105 void Shape::del_frame
01106   (
01107   int framenum
01108   )
01109   {
01110   assert (framenum < num_frames);
01111   delete frames[framenum];
01112           // Shift down.
01113   for (int i = framenum + 1; i < frames_size; i++)
01114     frames[i - 1] = frames[i];
01115   frames[frames_size - 1] = 0;  // Last spot is now free.
01116   num_frames--;
01117   }
01118 
01119 /*
01120  * Empty constructor
01121  */
01122 
01123 Shape_file::Shape_file() : Shape()
01124   {
01125     // Nothing to see here
01126   }
01127 
01128 /*
01129  *  Read in all shapes from a single-shape file.
01130  */
01131 
01132 Shape_file::Shape_file
01133   (
01134   const char *nm      // Path to file.
01135   ) : Shape()
01136   {
01137     load(nm);
01138   }
01139 
01140 /*
01141  *  Read in all shapes from a single-shape file.
01142  */
01143 
01144 void Shape_file::load
01145   (
01146   const char *nm      // Path to file.
01147   )
01148   {
01149   ifstream file;
01150   U7open(file, nm);
01151   StreamDataSource shape_source(&file);
01152   Shape::load(&shape_source);
01153   }
01154 
01155 /*
01156  *  Read in all shapes from a single-shape file.
01157  */
01158 
01159 Shape_file::Shape_file
01160   (
01161   DataSource* shape_source    // datasource.
01162   ) : Shape()
01163   {
01164     Shape::load(shape_source);
01165   }
01166 
01167 
01168 
01169 // NOTE: Only works on shapes other than the special 8x8 tile-shapes
01170 int Shape_file::get_size()
01171 {
01172   int size = 4;
01173   for (int i=0; i<num_frames; i++)
01174     size += frames[i]->get_size() + 4 + 8;
01175   return size;
01176 }
01177 
01178 // NOTE: Only works on shapes other than the special 8x8 tile-shapes
01179 void Shape_file::save(DataSource* shape_source)
01180 {
01181   int* offsets = new int[num_frames];
01182   int size;
01183   offsets[0] = 4 + num_frames * 4;
01184   int i;  // Blame MSVC
01185   for (i=1; i<num_frames; i++)
01186     offsets[i] = offsets[i-1] + frames[i-1]->get_size() + 8;
01187   size = offsets[num_frames-1] + frames[num_frames-1]->get_size() + 8;
01188   shape_source->write4(size);
01189   for (i=0; i<num_frames; i++)
01190     shape_source->write4(offsets[i]);
01191   for (i=0; i<num_frames; i++) {
01192     shape_source->write2(frames[i]->xright);
01193     shape_source->write2(frames[i]->xleft);
01194     shape_source->write2(frames[i]->yabove);
01195     shape_source->write2(frames[i]->ybelow);
01196     shape_source->write((char*)(frames[i]->data), frames[i]->get_size());
01197   }
01198   delete [] offsets;
01199 }
01200 
01201 
01202 
01203 
01204 
01205 /*
01206  *  Open file.
01207  */
01208 
01209 Vga_file::Vga_file
01210   (
01211   const char *nm,     // Path to file.
01212   int u7drag,     // # from u7drag.h, or -1.
01213   const char *nm2     // Patch file, or null.
01214   ) : shape_source(0), shape_source2(0),
01215       num_shapes(0), num_shapes1(0), num_shapes2(0), 
01216       shapes(0), u7drag_type(u7drag), flex(true)
01217   {
01218   load(nm, nm2);
01219   }
01220 
01221 Vga_file::Vga_file
01222   (
01223   ) : shape_source(0), shape_source2(0),
01224       num_shapes(0), num_shapes1(0), num_shapes2(0), 
01225       shapes(0), u7drag_type(-1), flex(true)
01226   {
01227     // Nothing to see here !!!
01228   }
01229 
01230 
01231 /*
01232  *  Open file.
01233  */
01234 
01235 void Vga_file::load
01236   (
01237   const char *nm,     // Path to file (required).
01238   const char *nm2     // Path to patch file (optional).
01239   )
01240   {
01241   reset();
01242   if (U7exists(nm))
01243   {
01244     U7open(file, nm);
01245     shape_source = new StreamDataSource(&file);
01246     StreamDataSource ds(&file);
01247     flex = Flex::is_flex(&ds);
01248   }
01249   if (nm2 && U7exists(nm2))
01250   {
01251     U7open(file2, nm2);   // throws an error if it fails
01252     shape_source2 = new StreamDataSource(&file2);
01253     StreamDataSource ds(&file2);
01254     flex = Flex::is_flex(&ds);
01255   }
01256   if (!shape_source && !shape_source2)
01257     throw file_open_exception(get_system_path(nm));
01258   if (!flex)      // Just one shape, which we preload.
01259     {
01260     num_shapes = num_shapes1 = num_shapes2 = 1;
01261     shapes = new Shape[1];
01262     shapes[0].load(shape_source2 ? shape_source2 : shape_source);
01263     return;
01264     }
01265   if (shape_source)
01266     {
01267     shape_source->seek(0x54); // Get # of shapes.
01268     num_shapes = num_shapes1 = shape_source->read4();
01269     }
01270   if (shape_source2)
01271   {
01272     shape_source2->seek(0x54);    // Get # of shapes.
01273     num_shapes2 = shape_source2->read4();
01274     if (num_shapes2 > num_shapes) num_shapes = num_shapes2;
01275   }
01276           // Set up lists of pointers.
01277   shapes = new Shape[num_shapes];
01278   }
01279 
01280 void Vga_file::reset()
01281   {
01282   if( shapes )
01283     delete [] shapes;
01284   if( shape_source )
01285     delete shape_source;
01286   file.close();
01287 
01288   if( shape_source2 )
01289     delete shape_source2;
01290 
01291   if (file2.is_open()) file2.close();
01292 
01293   num_shapes = 0;
01294   num_shapes1 = 0;
01295   num_shapes2 = 0;
01296   shape_source = 0;
01297   shape_source2 = 0;
01298   shapes = 0;
01299   }
01300 
01301 Vga_file::~Vga_file()
01302   {
01303   reset();
01304   }
01305 
01306 /*
01307  *  Make a spot for a new shape, and delete frames in existing shape.
01308  *
01309  *  Output: ->shape, or 0 if invalid shapenum.
01310  */
01311 
01312 Shape *Vga_file::new_shape
01313   (
01314   int shapenum
01315   )
01316   {
01317   if (shapenum < 0 || shapenum >= 2048) // (2048 is really arbitrary.)
01318     return 0;
01319   if (shapenum < num_shapes)
01320     {
01321     shapes[shapenum].reset();
01322     shapes[shapenum].num_frames = shapes[shapenum].frames_size = 0;
01323     }
01324   else        // Enlarge list.
01325     {
01326     if (!flex)
01327       return 0; // 1-shape file.
01328     Shape *newshapes = new Shape[shapenum + 1];
01329     for (int i = 0; i < num_shapes; i++)
01330       newshapes[i].take(&shapes[i]);
01331     delete [] shapes;
01332     shapes = newshapes;
01333     num_shapes = shapenum + 1;
01334     }
01335   return &shapes[shapenum];
01336   }
01337 

Generated on Mon Jul 9 14:42:50 2007 for ExultEngine by  doxygen 1.5.1