Shape.cpp

Go to the documentation of this file.
00001 /*
00002  *  Copyright (C) 2003-2004 The Pentagram Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 
00019 #include "pent_include.h"
00020 
00021 #include "Shape.h"
00022 #include "ShapeFrame.h"
00023 #include "ConvertShape.h"
00024 #include "u8/ConvertShapeU8.h"
00025 #include "crusader/ConvertShapeCrusader.h"
00026 #include "IDataSource.h"
00027 
00028 DEFINE_RUNTIME_CLASSTYPE_CODE_BASE_CLASS(Shape);
00029 
00030 DEFINE_CUSTOM_MEMORY_ALLOCATION(Shape);
00031 
00032 Shape::Shape(const uint8* data, uint32 size, const ConvertShapeFormat *format,
00033                          const uint16 id, const uint32 shape) : flexId(id), shapenum(shape)
00034 {
00035         // NB: U8 style!
00036 
00037         this->data = data;
00038         this->size = size;
00039         this->palette = 0;
00040 
00041         if (!format) format = DetectShapeFormat(data,size);
00042         
00043         if (!format) 
00044         {
00045                 // Should be fatal?
00046                 perr << "Error: Unable to detect shape format" << std::endl;
00047                 return;
00048         }
00049 
00050         // Load it as u8
00051         if (format == &U8ShapeFormat || format == &U82DShapeFormat)
00052                 LoadU8Format(data,size,format);
00053         else if (format == &PentagramShapeFormat)
00054                 LoadPentagramFormat(data,size,format);
00055         else 
00056                 LoadGenericFormat(data,size,format);
00057 }
00058 
00059 Shape::Shape(IDataSource *src, const ConvertShapeFormat *format)
00060         : flexId(0), shapenum(0)
00061 {
00062         // NB: U8 style!
00063 
00064         this->size = src->getSize();
00065         uint8 *d = new uint8[this->size];
00066         this->data = d;
00067         src->read(d, this->size);
00068         this->palette = 0;
00069 
00070         if (!format) format = DetectShapeFormat(data,size);
00071         
00072         if (!format) 
00073         {
00074                 // Should be fatal?
00075                 perr << "Error: Unable to detect shape format" << std::endl;
00076                 return;
00077         }
00078 
00079         // Load it as u8
00080         if (format == &U8ShapeFormat || format == &U82DShapeFormat)
00081                 LoadU8Format(data,size,format);
00082         else if (format == &PentagramShapeFormat)
00083                 LoadPentagramFormat(data,size,format);
00084         else 
00085                 LoadGenericFormat(data,size,format);
00086 }
00087 
00088 Shape::~Shape()
00089 {
00090         for (unsigned int i = 0; i < frames.size(); ++i)
00091                 delete frames[i];
00092 
00093         delete[] const_cast<uint8*>(data);
00094 }
00095 
00096 void Shape::getShapeId(uint16 & id, uint32 & shape)
00097 {
00098         id = flexId;
00099         shape = shapenum;
00100 }
00101 
00102 // Some macros to make things easier
00103 #define READ1(data,offset) (data[offset])
00104 #define READ2(data,offset) (data[offset] + (data[offset+1] << 8))
00105 #define READ3(data,offset) (data[offset] + (data[offset+1] << 8) + (data[offset+2] << 16))
00106 #define READ4(data,offset) (data[offset] + (data[offset+1] << 8) + (data[offset+2] << 16) + (data[offset+3] << 24))
00107 
00108 // This will load a u8 style shape 'optimzed'.
00109 void Shape::LoadU8Format(const uint8* data, uint32 size, const ConvertShapeFormat* format)
00110 {
00111         unsigned int framecount = READ2(data,4);
00112 
00113         if (framecount == 0) {
00114                 LoadGenericFormat(data, size, format);
00115                 return;
00116         }
00117 
00118         frames.reserve(framecount);
00119 
00120         for (unsigned int i = 0; i < framecount; ++i) {
00121                 uint32 frameoffset = READ3(data,6+6*i);
00122                 uint32 framesize = READ2(data,10+6*i);
00123                 
00124                 frames.push_back(new ShapeFrame(data + frameoffset, framesize, format));
00125         }
00126 }
00127 
00128 // This will load a pentagram style shape 'optimzed'.
00129 void Shape::LoadPentagramFormat(const uint8* data, uint32 size, const ConvertShapeFormat* format)
00130 {
00131         unsigned int framecount = READ4(data,4);
00132 
00133         if (framecount == 0) {
00134                 LoadGenericFormat(data, size, format);
00135                 return;
00136         }
00137 
00138         frames.reserve(framecount);
00139 
00140         for (unsigned int i = 0; i < framecount; ++i) {
00141                 uint32 frameoffset = READ4(data,8+8*i);
00142                 uint32 framesize = READ4(data,12+8*i);
00143                 
00144                 frames.push_back(new ShapeFrame(data + frameoffset, framesize, format));
00145         }
00146 }
00147 
00148 // This will load any sort of shape via a ConvertShapeFormat struct
00149 void Shape::LoadGenericFormat(const uint8* data, uint32 size, const ConvertShapeFormat* format)
00150 {
00151         uint32 framecount;
00152         uint32 frameoffset;
00153         uint32 framesize;
00154         IBufferDataSource ds(data,size);
00155 
00156         if (format->bytes_ident) {
00157                 uint8* ident = new uint8[format->bytes_ident];
00158                 ds.read(ident, format->bytes_ident);
00159                 bool match = std::memcmp(ident,format->ident,format->bytes_ident) == 0;
00160                 delete[] ident;
00161 
00162                 if (!match) {
00163                         frames.clear();
00164                         return;
00165                 }
00166         }
00167 
00168         // Read special buffer
00169         uint8 special[256];
00170         if (format->bytes_special) {
00171                 memset(special, 0, 256);
00172                 for (uint32 i = 0; i < format->bytes_special; i++) special[ds.read1()&0xFF] = i+2;
00173         }
00174 
00175         // Skip unknown
00176         ds.skip(format->bytes_header_unk);
00177 
00178         // Read framecount, default 1 if no
00179         if (format->bytes_num_frames) framecount = ds.readX(format->bytes_num_frames);
00180         else framecount = 1;
00181         if (framecount == 0) framecount = ConvertShape::CalcNumFrames(&ds,format,size,0);
00182 
00183         frames.reserve(framecount);
00184 
00185         for (unsigned int i = 0; i < framecount; ++i) {
00186                 // Read the offset
00187                 if (format->bytes_frame_offset) frameoffset = ds.readX(format->bytes_frame_offset) + format->bytes_special;
00188                 else frameoffset = format->len_header + (format->len_frameheader*i);
00189 
00190                 // Skip the unknown
00191                 ds.skip(format->bytes_frameheader_unk);
00192 
00193                 // Read frame_length
00194                 if (format->bytes_frame_length) framesize = ds.readX(format->bytes_frame_length) + format->bytes_frame_length_kludge;
00195                 else framesize = size-frameoffset;
00196                 
00197                 ConvertShapeFrame *prev=0, p;
00198 
00199                 if (format->bytes_special && i > 0) {
00200                         prev = &p;
00201                         frames[i-1]->getConvertShapeFrame(p);
00202                 }
00203 
00204                 frames.push_back(new ShapeFrame(data + frameoffset, framesize, format, special, prev));
00205         }
00206 }
00207 
00208 // This will detect the format of a shape
00209 const ConvertShapeFormat *Shape::DetectShapeFormat(const uint8* data, uint32 size)
00210 {
00211         IBufferDataSource ds(data,size);
00212         return Shape::DetectShapeFormat(&ds, size);
00213 }
00214 
00215 const ConvertShapeFormat *Shape::DetectShapeFormat(IDataSource * ds, uint32 size)
00216 {
00217         const ConvertShapeFormat *ret = 0;
00218 
00219         if (ConvertShape::CheckUnsafe(ds, &PentagramShapeFormat, size))
00220                 ret = &PentagramShapeFormat;
00221         else if (ConvertShape::CheckUnsafe(ds, &U8SKFShapeFormat, size))
00222                 ret = &U8SKFShapeFormat;
00223         else if (ConvertShape::CheckUnsafe(ds, &U8ShapeFormat, size))
00224                 ret = &U8ShapeFormat;
00225         else if (ConvertShape::CheckUnsafe(ds, &U82DShapeFormat, size))
00226                 ret = &U82DShapeFormat;
00227         else if (ConvertShape::CheckUnsafe(ds, &CrusaderShapeFormat, size))
00228                 ret = &CrusaderShapeFormat;
00229         else if (ConvertShape::CheckUnsafe(ds, &Crusader2DShapeFormat, size))
00230                 ret = &Crusader2DShapeFormat;
00231         else if (ConvertShape::CheckUnsafe(ds, &U8CMPShapeFormat, size))
00232                 ret = &U8CMPShapeFormat;
00233 
00234         return ret;
00235 }
00236 
00237 void Shape::getTotalDimensions(sint32& w,sint32& h,sint32& x,sint32& y) const
00238 {
00239         if (frames.empty()) {
00240                 w = 0; h = 0; x = 0; y = 0;
00241                 return;
00242         }
00243 
00244         sint32 minx = 1000000, maxx = -1000000;
00245         sint32 miny = 1000000, maxy = -1000000;
00246 
00247         for (unsigned int i = 0; i < frames.size(); ++i) {
00248                 ShapeFrame* frame = frames[i];
00249                 if (-frame->xoff < minx)
00250                         minx = -frame->xoff;
00251                 if (-frame->yoff < miny)
00252                         miny = -frame->yoff;
00253                 if (frame->width-frame->xoff-1 > maxx)
00254                         maxx = frame->width-frame->xoff-1;
00255                 if (frame->height-frame->yoff-1 > maxy)
00256                         maxy = frame->height-frame->yoff-1;
00257         }
00258 
00259         w = maxx - minx + 1;
00260         h = maxy - miny + 1;
00261         x = -minx;
00262         y = -miny;
00263 }

Generated on Fri Jul 27 22:27:36 2007 for pentagram by  doxygen 1.4.7