2 * This file is part of ShapeFusion (Copyright 2000 Tito Dal Canton)
4 * ShapeFusion is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * ShapeFusion is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with ShapeFusion; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "ShapesElements.h"
20 #include "utilities.h"
21 #include "../LittleEndianBuffer.h"
25 // on-file struct sizes
26 #define SIZEOF_collection_definition 544
27 #define SIZEOF_rgb_color_value 8
28 #define SIZEOF_bitmap_definition 30
29 #define SIZEOF_low_level_shape_definition 36
30 #define SIZEOF_high_level_shape_definition 88
31 // NOTE about SIZEOF_high_level_shape_definition. The original engine
32 // sets SIZEOF_high_level_shape_definition=90 because the first frame
33 // index is included in the high_level_shape_definition. I don't like
34 // this, so I do my way (but be careful!)
35 #define COLLECTION_VERSION 3
39 SELF_LUMINESCENT_COLOR = 1 << 7
43 COLUMN_ORDER = 1 << 15,
44 TRANSPARENCY_ENABLED = 1 << 14
48 X_MIRROR = 1 << 15, // mirror along vertical axis
49 Y_MIRROR = 1 << 14, // mirror along horizontal axis
50 KEYPOINT_OBSCURED = 1 << 13 // "host obscures parasite" (RenderPlaceObjs.cpp)
53 #define FOUR_CHARS_TO_INT(a,b,c,d) (((unsigned int)(a) << 24) | ((unsigned int)(b) << 16) | ((unsigned int)(c) << 8) | (unsigned int)(d))
55 ShapesColor::ShapesColor(bool verbose): ShapesElement(verbose)
60 ShapesColor::ShapesColor(unsigned int r, unsigned int g, unsigned int b, unsigned int value, bool luminescent, bool verbose):
61 ShapesElement(verbose), mLuminescent(luminescent), mValue(value), mRed(r), mGreen(g), mBlue(b)
66 ShapesColor::~ShapesColor(void)
71 bool ShapesColor::operator==(const ShapesColor& other) const
73 return mLuminescent == other.mLuminescent
74 && mValue == other.mValue
76 && mGreen == other.mGreen
77 && mBlue == other.mBlue;
80 BigEndianBuffer& ShapesColor::SaveObject(BigEndianBuffer& buffer)
82 unsigned char flags = mLuminescent ? SELF_LUMINESCENT_COLOR : 0;
84 buffer.WriteUChar(flags);
85 buffer.WriteUChar(mValue);
86 buffer.WriteUShort(mRed);
87 buffer.WriteUShort(mGreen);
88 buffer.WriteUShort(mBlue);
93 BigEndianBuffer& ShapesColor::LoadObject(BigEndianBuffer& buffer)
97 flags = buffer.ReadUChar();
98 mValue = buffer.ReadUChar();
99 mRed = buffer.ReadUShort();
100 mGreen = buffer.ReadUShort();
101 mBlue = buffer.ReadUShort();
103 mLuminescent = flags & SELF_LUMINESCENT_COLOR;
109 ShapesColorTable::ShapesColorTable(bool verbose): ShapesElement(verbose)
114 ShapesColorTable::ShapesColorTable(std::ifstream& ifs, wxString file_ext): ShapesElement(false)
116 // FIXME better error checking and reporting
117 if (file_ext == wxString(wxT("act"))) {
118 // Photoshop binary color table file (Adobe Color Table, .act)
119 ifs.seekg(0, std::ios::end);
120 unsigned int fileSize = ifs.tellg(),
122 ifs.seekg(0, std::ios::beg);
124 if (fileSize >= 3*256+4) {
125 // extra info found - get the color count from that
126 BigEndianBuffer extraInfo(4);
129 ifs.read((char *)extraInfo.Data(), 4);
130 colorCount = (unsigned int)extraInfo.ReadShort();
131 if (colorCount > 256)
133 } else if (fileSize == 3*256) {
134 // no extra info - exactly 256 colors and no transparent color
137 // we need at least 3*256 bytes
138 wxLogError(wxT("This Adobe Color Table file has an invalid size: will not try to load it."));
141 ifs.seekg(0, std::ios::beg);
142 for (unsigned int value = 0; value < colorCount; value++) {
143 unsigned char rgb[3];
144 ifs.read((char *)rgb, 3);
145 ShapesColor *newColor = new ShapesColor(rgb[0]<<8, rgb[1]<<8, rgb[2]<<8, value);
146 mColors.push_back(newColor);
148 } else if (file_ext == wxString(wxT("gpl"))) {
149 // Gimp ASCII palette file
150 unsigned int value = 0;
152 while (ifs.good() && value < 256) {
153 char buffer[256] = "";
154 unsigned int red, green, blue;
156 ifs.getline(buffer, 255);
157 if (sscanf(buffer, "%u %u %u", &red, &green, &blue) == 3) {
158 ShapesColor *newColor = new ShapesColor(red<<8, green<<8, blue<<8, value);
160 mColors.push_back(newColor);
167 ShapesColorTable::~ShapesColorTable(void)
169 for (unsigned int i = 0; i < mColors.size(); i++)
173 static bool compareShapesColorPtrs(ShapesColor* rhs, ShapesColor* lhs)
175 return (*rhs == *lhs);
178 bool ShapesColorTable::operator==(const ShapesColorTable& other) const
180 if (mColors.size() == other.mColors.size()) {
181 return std::equal(mColors.begin(), mColors.end(), other.mColors.begin(), compareShapesColorPtrs);
187 BigEndianBuffer& ShapesColorTable::SaveObject(BigEndianBuffer& stream)
189 for (unsigned int i = 0; i < mColors.size(); i++) {
190 ShapesColor *color = mColors[i];
192 color->SaveObject(stream);
197 BigEndianBuffer& ShapesColorTable::SavePatch(BigEndianBuffer& buffer, int index)
199 buffer.WriteLong(FOUR_CHARS_TO_INT('c','t','a','b'));
200 buffer.WriteLong(index);
201 return SaveObject(buffer);
204 BigEndianBuffer& ShapesColorTable::LoadObject(BigEndianBuffer& buffer, unsigned int offset, unsigned int color_count)
206 buffer.Position(offset);
208 for (unsigned int i = 0; i < color_count; i++) {
209 ShapesColor *color = new ShapesColor(IsVerbose());
211 color->LoadObject(buffer);
213 if (!color->IsGood()) {
214 wxLogError(wxT("[ShapesColorTable] Error loading color table"));
218 mColors.push_back(color);
225 // export a color table to Gimp ASCII format
226 int ShapesColorTable::SaveToGimp(wxString path) const
228 std::ofstream cts(path.fn_str(), std::ios::binary);
231 cts << "GIMP Palette\n";
232 cts << "Name: ShapeFusion exported palette\n";
234 for (unsigned int i = 0; i < ColorCount(); i++) {
235 ShapesColor *color = GetColor(i);
237 cts << (color->Red() >> 8) << ' ';
238 cts << (color->Green() >> 8) << ' ';
239 cts << (color->Blue() >> 8) << '\n';
248 // export a color table to Photoshop binary format
249 // (MacOS file type is '8BCT', extension '.act', Adobe Color Table)
250 int ShapesColorTable::SaveToPhotoshop(wxString path) const
252 std::ofstream cts(path.fn_str(), std::ios::binary);
255 BigEndianBuffer actData(3*256+4);
257 actData.WriteZeroes(3*256+4);
259 // write the RGB byte triplets for our colors
260 for (unsigned int i = 0; i < ColorCount(); i++) {
261 ShapesColor *color = GetColor(i);
263 actData.WriteChar(color->Red() >> 8);
264 actData.WriteChar(color->Green() >> 8);
265 actData.WriteChar(color->Blue() >> 8);
267 // write the extra info at the end:
268 // number of colors and index of the transparent color
269 actData.Position(3*256);
270 actData.WriteShort(ColorCount());
271 actData.WriteShort(0);
272 cts.write((char *)actData.Data(), actData.Size());
280 ShapesBitmap::ShapesBitmap(bool verbose): ShapesElement(verbose), mPixels(NULL)
284 ShapesBitmap::ShapesBitmap(wxImage image, ShapesColorTable *colortable):
285 ShapesElement(false), mPixels(NULL)
287 FromImage(image, colortable);
290 ShapesBitmap::~ShapesBitmap(void)
297 bool ShapesBitmap::operator==(const ShapesBitmap& other) const
299 if (mWidth == other.mWidth
300 && mHeight == other.mHeight
301 && mBytesPerRow == other.mBytesPerRow
302 && mBitDepth == other.mBitDepth
303 && mColumnOrder == other.mColumnOrder
304 && mTransparent == other.mTransparent) {
305 return std::equal(mPixels, mPixels + (mWidth * mHeight), other.mPixels);
311 unsigned int ShapesBitmap::SizeInFile(void) const
313 unsigned int size = 0;
315 // scanline pointer placeholder
320 if (mBytesPerRow == -1) {
323 for (int x = 0; x < mWidth; x++) {
324 unsigned char *pp = mPixels + x;
328 for (int y = 0; y < mHeight; y++) {
336 continue; // no opaque mPixels in this column
338 pp = mPixels + x + mWidth * (mHeight - 1);
339 for (int y = mHeight - 1; y >= 0; y--) {
350 size += mWidth * mHeight;
356 BigEndianBuffer& ShapesBitmap::SaveObject(BigEndianBuffer& buffer)
361 flags |= COLUMN_ORDER;
363 flags |= TRANSPARENCY_ENABLED;
364 buffer.WriteShort(mWidth);
365 buffer.WriteShort(mHeight);
366 buffer.WriteShort(mBytesPerRow);
367 buffer.WriteShort(flags);
368 buffer.WriteShort(mBitDepth);
369 buffer.WriteZeroes(20 + 4 * (mColumnOrder ? mWidth : mHeight));
370 if (mBytesPerRow == -1) {
372 for (int x = 0; x < mWidth; x++) {
373 unsigned char *pp = mPixels + x;
376 for (int y = 0; y < mHeight; y++) {
384 // no opaque pixels in this column
385 buffer.WriteShort(0);
386 buffer.WriteShort(0);
388 // found opaque pixels, go on
390 pp = mPixels + x + mWidth * (mHeight - 1);
391 for (int y = mHeight - 1; y >= 0; y--) {
398 buffer.WriteShort(p0);
399 buffer.WriteShort(p1 + 1);
400 pp = mPixels + x + p0 * mWidth;
401 for (int y = p0; y <= p1; y++) {
402 buffer.WriteChar(*pp);
409 for (int x = 0; x < mWidth; x++) {
410 for (int y = 0; y < mHeight; y++)
411 buffer.WriteChar(*(mPixels + x + y * mWidth));
414 buffer.WriteBlock(mWidth * mHeight, mPixels);
420 BigEndianBuffer& ShapesBitmap::SavePatch(BigEndianBuffer& buffer, int index)
422 buffer.WriteLong(FOUR_CHARS_TO_INT('b', 'm', 'a', 'p'));
423 buffer.WriteLong(index);
424 buffer.WriteLong(SizeInFile() + SIZEOF_bitmap_definition);
425 return SaveObject(buffer);
428 BigEndianBuffer& ShapesBitmap::LoadObject(BigEndianBuffer& buffer, unsigned int offset)
430 buffer.Position(offset);
432 mWidth = buffer.ReadShort();
433 mHeight = buffer.ReadShort();
434 mBytesPerRow = buffer.ReadShort();
437 wxLogError(wxT("[ShapesBitmap] Invalid bitmap width %d"), mWidth);
441 wxLogError(wxT("[ShapesBitmap] Invalid bitmap height %d"), mHeight);
444 if (mBytesPerRow < -1) {
445 wxLogError(wxT("[ShapesBitmap] Invalid bitmap bytes-per-row %d"), mBytesPerRow);
449 short flags = buffer.ReadShort();
451 mColumnOrder = flags & COLUMN_ORDER;
452 mTransparent = flags & TRANSPARENCY_ENABLED;
454 mBitDepth = buffer.ReadShort();
455 if (mBitDepth != 8) {
456 wxLogError(wxT("[ShapesBitmap] Invalid bitmap depth %d"), mBitDepth);
461 wxLogDebug(wxT("[ShapesBitmap] Width: %d"), mWidth);
462 wxLogDebug(wxT("[ShapesBitmap] Height: %d"), mHeight);
463 wxLogDebug(wxT("[ShapesBitmap] Bytes/Row: %d"), mBytesPerRow);
464 wxLogDebug(wxT("[ShapesBitmap] Flags: %d"), flags);
465 wxLogDebug(wxT("[ShapesBitmap] Bit Depth: %d"), mBitDepth);
468 // skip unused fields and placeholders
469 unsigned int numscanlines = (mColumnOrder ? mWidth : mHeight);
471 buffer.Position(buffer.Position() + 20 + numscanlines * 4);
474 mPixels = new unsigned char[mWidth * mHeight];
475 if (mPixels == NULL) {
476 wxLogError(wxT("[ShapesBitmap] Could not allocate pixel buffer"));
479 if (mBytesPerRow > -1) {
480 // uncompressed bitmap
485 for (int x = 0; x < mWidth; x++) {
487 for (int y = 0; y < mHeight; y++) {
488 *dstp = buffer.ReadUChar();
494 buffer.ReadBlock(mWidth * mHeight, mPixels);
497 // compressed bitmap (always column order)
498 memset(mPixels, 0, mWidth * mHeight);
499 for (int x = 0; x < mWidth; x++) {
503 p0 = buffer.ReadShort();
504 p1 = buffer.ReadShort();
505 dstp = mPixels + x + p0 * mWidth;
507 *dstp = buffer.ReadUChar();
518 // export the ShapesBitmap to an indexed BMP file specified by path
519 void ShapesBitmap::SaveToBMP(wxString path, ShapesColorTable *colorTable) const
521 std::ofstream stream(path.fn_str(), std::ios::binary);
524 unsigned int colorCount = colorTable->ColorCount();
525 unsigned long paddedWidth = (mWidth + 3) & 0xfffffffc;
528 LittleEndianBuffer headerBlock(54);
530 headerBlock.WriteChar('B');
531 headerBlock.WriteChar('M');
532 headerBlock.WriteULong(54 + 4*colorCount + paddedWidth * mHeight); // file size
533 headerBlock.WriteULong(0); // reserved
534 headerBlock.WriteULong(54 + 4*colorCount); // raster data offset
535 headerBlock.WriteULong(40); // info header size
536 headerBlock.WriteULong(mWidth);
537 headerBlock.WriteULong(mHeight);
538 headerBlock.WriteUShort(1); // plane count
539 headerBlock.WriteUShort(8); // bits per pixel
540 headerBlock.WriteULong(0); // no compression
541 headerBlock.WriteULong(0); // compressed size of image
542 headerBlock.WriteULong(0);
543 headerBlock.WriteULong(0);
544 headerBlock.WriteULong(colorCount); // FIXME
545 headerBlock.WriteULong(0); // FIXME
546 stream.write((const char *)headerBlock.Data(), headerBlock.Size());
549 LittleEndianBuffer paletteBlock(4*colorCount);
551 for (unsigned int i = 0; i < colorCount; i++) {
552 ShapesColor *color = colorTable->GetColor(i);
554 paletteBlock.WriteUChar(color->Blue() >> 8);
555 paletteBlock.WriteUChar(color->Green() >> 8);
556 paletteBlock.WriteUChar(color->Red() >> 8);
557 paletteBlock.WriteUChar(0);
559 stream.write((const char *)paletteBlock.Data(), paletteBlock.Size());
562 LittleEndianBuffer rasterBlock(paddedWidth * mHeight);
564 for (int y = 0; y < mHeight; y++) {
565 rasterBlock.WriteBlock(mWidth, mPixels + (mHeight - y - 1) * mWidth);
566 rasterBlock.WriteZeroes(paddedWidth - mWidth);
568 stream.write((const char *)rasterBlock.Data(), rasterBlock.Size());
574 // export the ShapesBitmap mask to a 1-bit BMP file specified by path
575 void ShapesBitmap::SaveMaskToBMP(wxString path) const
577 std::ofstream stream(path.fn_str(), std::ios::binary);
580 unsigned long rowBytes = ((mWidth + 31) & 0xffffffe0) >> 3;
583 LittleEndianBuffer headerBlock(54);
585 headerBlock.WriteChar('B');
586 headerBlock.WriteChar('M');
587 headerBlock.WriteULong(54 + 4*2 + rowBytes * mHeight); // file size
588 headerBlock.WriteULong(0); // reserved
589 headerBlock.WriteULong(54 + 4*2); // raster data offset
590 headerBlock.WriteULong(40); // info header size
591 headerBlock.WriteULong(mWidth);
592 headerBlock.WriteULong(mHeight);
593 headerBlock.WriteUShort(1); // plane count
594 headerBlock.WriteUShort(1); // bits per pixel
595 headerBlock.WriteULong(0); // no compression
596 headerBlock.WriteULong(0); // compressed size of image
597 headerBlock.WriteULong(0);
598 headerBlock.WriteULong(0);
599 headerBlock.WriteULong(2);
600 headerBlock.WriteULong(0);
601 stream.write((const char *)headerBlock.Data(), headerBlock.Size());
603 // black & white palette
604 LittleEndianBuffer paletteBlock(4*2);
606 paletteBlock.WriteUChar(0);
607 paletteBlock.WriteUChar(0);
608 paletteBlock.WriteUChar(0);
609 paletteBlock.WriteUChar(0);
610 paletteBlock.WriteUChar(255);
611 paletteBlock.WriteUChar(255);
612 paletteBlock.WriteUChar(255);
613 paletteBlock.WriteUChar(0);
614 stream.write((const char *)paletteBlock.Data(), paletteBlock.Size());
617 LittleEndianBuffer rasterBlock(rowBytes * mHeight);
619 rasterBlock.WriteZeroes(rowBytes * mHeight);
620 for (unsigned int y = 0; (int)y < mHeight; y++) {
621 unsigned char *p = mPixels + y * mWidth,
625 rasterBlock.Position((mHeight - y - 1) * rowBytes);
626 for (unsigned int x = 0; (int)x < mWidth; x++) {
632 rasterBlock.WriteUChar(byte);
637 rasterBlock.WriteUChar(byte);
639 stream.write((const char *)rasterBlock.Data(), rasterBlock.Size());
645 void ShapesBitmap::ClipboardCopy(ShapesColorTable* colortable) const
647 if (wxTheClipboard->Open()) {
648 // create an RGBA wxImage
650 image.Create(mWidth, mHeight, false);
652 unsigned char* src = mPixels;
653 unsigned char* dst = image.GetData();
654 for (int x = 0; x < mWidth; ++x) {
655 for (int y = 0; y < mHeight; ++y) {
656 unsigned char c = *src++;
657 ShapesColor* color = colortable->GetColor(c);
658 *dst++ = color->Red();
659 *dst++ = color->Green();
660 *dst++ = color->Blue();
664 wxTheClipboard->SetData(new wxBitmapDataObject(wxBitmap(image)));
665 wxTheClipboard->Close();
669 void ShapesBitmap::ClipboardPaste(ShapesColorTable* colortable)
671 if (wxTheClipboard->Open()) {
672 wxBitmapDataObject clipboardData;
673 if (wxTheClipboard->GetData(clipboardData)) {
674 FromImage(clipboardData.GetBitmap().ConvertToImage(), colortable);
676 wxTheClipboard->Close();
680 void ShapesBitmap::FromImage(wxImage image, ShapesColorTable* colortable)
682 mWidth = image.GetWidth();
683 mHeight = image.GetHeight();
684 mBytesPerRow = image.GetWidth();
687 mTransparent = false;
693 unsigned char* srcpixels = image.GetData(), *src = srcpixels, *dst;
695 mPixels = new unsigned char[mWidth * mHeight];
696 if (mPixels == NULL) {
697 wxLogError(wxT("Could not allocate new %dx%d bitmap\n"), mWidth, mHeight);
701 // quantize from 8-bit RGB pixels to an indexed bitmap
702 for (int i = 0; i < mWidth * mHeight; i++) {
703 unsigned char r = *src++, g = *src++, b = *src++,
707 for (unsigned int j = 0; j < colortable->ColorCount(); j++) {
708 unsigned short ct_r = colortable->GetColor(j)->Red(),
709 ct_g = colortable->GetColor(j)->Green(),
710 ct_b = colortable->GetColor(j)->Blue();
711 float dist = ColourDistance(r/255.0, g/255.0, b/255.0,
712 ct_r/65535.0, ct_g/65535.0, ct_b/65535.0);
714 if (dist < min_dist || j == 0) {
716 best_value = colortable->GetColor(j)->Value();
721 mTransparent = true; // guess the user will want transparency
725 ShapesFrame::ShapesFrame(bool verbose): ShapesElement(verbose)
727 // initialize values to something reasonable
729 mXmirror = mYmirror = mKeypointObscured = false;
730 mMinimumLightIntensity = 0;
731 mOriginX = mOriginY = mKeyX = mKeyY = 0;
733 mWorldLeft = mWorldRight = mWorldTop = mWorldBottom = 0;
734 mWorldX0 = mWorldY0 = 0;
737 ShapesFrame::~ShapesFrame(void)
742 bool ShapesFrame::operator==(const ShapesFrame& other) const
744 return mXmirror == other.mXmirror
745 && mYmirror == other.mYmirror
746 && mKeypointObscured == other.mKeypointObscured
747 && mMinimumLightIntensity == other.mMinimumLightIntensity
748 && mBitmapIndex == other.mBitmapIndex
749 && mScaleFactor == other.mScaleFactor
750 && mOriginX == other.mOriginX
751 && mOriginY == other.mOriginY
752 && mKeyX == other.mKeyX
753 && mKeyY == other.mKeyY;
756 BigEndianBuffer& ShapesFrame::SaveObject(BigEndianBuffer& buffer)
758 unsigned short flags = 0;
759 float mli_integer, mli_fractional;
760 long min_light_intensity = 0;
766 if (mKeypointObscured)
767 flags |= KEYPOINT_OBSCURED;
769 min_light_intensity = static_cast<long>(mMinimumLightIntensity * 65536.0 + 0.5); // convert float to 16.16 fixed
771 buffer.WriteUShort(flags);
772 buffer.WriteLong(min_light_intensity);
773 buffer.WriteShort(mBitmapIndex);
774 buffer.WriteShort(mOriginX);
775 buffer.WriteShort(mOriginY);
776 buffer.WriteShort(mKeyX);
777 buffer.WriteShort(mKeyY);
778 buffer.WriteShort(mWorldLeft);
779 buffer.WriteShort(mWorldRight);
780 buffer.WriteShort(mWorldTop);
781 buffer.WriteShort(mWorldBottom);
782 buffer.WriteShort(mWorldX0);
783 buffer.WriteShort(mWorldY0);
784 buffer.WriteZeroes(8);
789 BigEndianBuffer& ShapesFrame::SavePatch(BigEndianBuffer& buffer, int index)
791 buffer.WriteLong(FOUR_CHARS_TO_INT('l','l','s','h'));
792 buffer.WriteLong(index);
793 return SaveObject(buffer);
796 BigEndianBuffer& ShapesFrame::LoadObject(BigEndianBuffer& buffer, unsigned int offset)
798 unsigned short flags;
801 buffer.Position(offset);
803 flags = buffer.ReadUShort();
805 mXmirror = flags & X_MIRROR;
806 mYmirror = flags & Y_MIRROR;
807 mKeypointObscured = flags & KEYPOINT_OBSCURED;
809 mli_fixed = buffer.ReadLong();
811 mMinimumLightIntensity = mli_fixed / 65536.0; // convert 16.16 fixed to float
813 mBitmapIndex = buffer.ReadShort();
814 mOriginX = buffer.ReadShort();
815 mOriginY = buffer.ReadShort();
816 mKeyX = buffer.ReadShort();
817 mKeyY = buffer.ReadShort();
818 mWorldLeft = buffer.ReadShort();
819 mWorldRight = buffer.ReadShort();
820 mWorldTop = buffer.ReadShort();
821 mWorldBottom = buffer.ReadShort();
822 mWorldX0 = buffer.ReadShort();
823 mWorldY0 = buffer.ReadShort();
826 wxLogDebug(wxT("[ShapesFrame] Flags: %d"), flags);
827 wxLogDebug(wxT("[ShapesFrame] Min. Light Intensity: %f"), mMinimumLightIntensity);
828 wxLogDebug(wxT("[ShapesFrame] Bitmap Index: %d"), mBitmapIndex);
829 wxLogDebug(wxT("[ShapesFrame] Origin (X): %d"), mOriginX);
830 wxLogDebug(wxT("[ShapesFrame] Origin (Y): %d"), mOriginY);
831 wxLogDebug(wxT("[ShapesFrame] Key (X): %d"), mKeyX);
832 wxLogDebug(wxT("[ShapesFrame] Key (Y): %d"), mKeyY);
833 wxLogDebug(wxT("[ShapesFrame] World (Left): %d"), mWorldLeft);
834 wxLogDebug(wxT("[ShapesFrame] World (Right): %d"), mWorldRight);
835 wxLogDebug(wxT("[ShapesFrame] World (Top): %d"), mWorldTop);
836 wxLogDebug(wxT("[ShapesFrame] World (Bottom): %d"), mWorldBottom);
837 wxLogDebug(wxT("[ShapesFrame] World (X0): %d"), mWorldX0);
838 wxLogDebug(wxT("[ShapesFrame] World (Y0): %d"), mWorldY0);
845 ShapesSequence::ShapesSequence(bool verbose): ShapesElement(verbose)
847 // initialize values to something reasonable
850 mName = _T("new sequence");
851 mNumberOfViews = UNANIMATED;
856 mTransferModePeriod = 1;
857 mFirstFrameSound = mKeyFrameSound = mLastFrameSound = -1;
862 ShapesSequence::~ShapesSequence(void)
867 bool ShapesSequence::operator==(const ShapesSequence& other) const
869 if (mType == other.mType
870 && mFlags == other.mFlags
871 && mName == other.mName
872 && mNumberOfViews == other.mNumberOfViews
873 && mFramesPerView == other.mFramesPerView
874 && mTicksPerFrame == other.mTicksPerFrame
875 && mKeyFrame == other.mKeyFrame
876 && mTransferMode == other.mTransferMode
877 && mTransferModePeriod == other.mTransferModePeriod
878 && mFirstFrameSound == other.mFirstFrameSound
879 && mKeyFrameSound == other.mKeyFrameSound
880 && mLastFrameSound == other.mLastFrameSound
881 && mPixelsToWorld == other.mPixelsToWorld
882 && mLoopFrame == other.mLoopFrame
883 && mFrameIndexes.size() == other.mFrameIndexes.size()) {
884 return std::equal(mFrameIndexes.begin(), mFrameIndexes.end(), other.mFrameIndexes.begin());
890 unsigned int ShapesSequence::SizeInFile() const
892 return 2 * (FrameIndexCount() + 1);
895 BigEndianBuffer& ShapesSequence::SaveObject(BigEndianBuffer& buffer)
899 // Ugh--wxGTK doesn't recognize wxFONTENCODING_MACROMAN, and
900 // if you try to create a new wsCSConv with it, successive
901 // attempts to create wxT("macintosh") fail. Windows, on the
902 // other hand, doesn't recognize wxT("macintosh"), although if
903 // you ask it if seqnameconv.IsOk() it returns true and only
904 // fails when you try to convert something. So, #ifdef to
907 wxCSConv seqnameconv(wxFONTENCODING_MACROMAN);
909 wxCSConv seqnameconv(wxT("macintosh"));
912 buffer.WriteShort(mType);
913 buffer.WriteUShort(mFlags);
914 buffer.WriteChar(mName.Length());
915 strncpy(name, seqnameconv.cWC2MB(mName.wc_str(*wxConvCurrent)), 33);
916 buffer.WriteBlock(33, (unsigned char *)name);
917 buffer.WriteShort(mNumberOfViews);
918 buffer.WriteShort(mFramesPerView);
919 buffer.WriteShort(mTicksPerFrame);
920 buffer.WriteShort(mKeyFrame);
921 buffer.WriteShort(mTransferMode);
922 buffer.WriteShort(mTransferModePeriod);
923 buffer.WriteShort(mFirstFrameSound);
924 buffer.WriteShort(mKeyFrameSound);
925 buffer.WriteShort(mLastFrameSound);
926 buffer.WriteShort(mPixelsToWorld);
927 buffer.WriteShort(mLoopFrame);
928 buffer.WriteZeroes(28);
929 for (unsigned int i = 0; i < mFrameIndexes.size(); i++)
930 buffer.WriteShort(mFrameIndexes[i]);
931 buffer.WriteShort(0);
936 BigEndianBuffer& ShapesSequence::SavePatch(BigEndianBuffer& buffer, int index)
938 buffer.WriteLong(FOUR_CHARS_TO_INT('h','l','s','h'));
939 buffer.WriteLong(index);
940 buffer.WriteLong(SizeInFile() + SIZEOF_high_level_shape_definition);
941 return SaveObject(buffer);
944 BigEndianBuffer& ShapesSequence::LoadObject(BigEndianBuffer& buffer, long offset)
946 buffer.Position(offset);
947 mType = buffer.ReadShort();
948 mFlags = buffer.ReadUShort();
950 // the mName is a Mac Pascal string, not a C string (length,chars)
951 unsigned char namelen = buffer.ReadUChar();
954 wxLogError(wxT("[ShapesSequence] Sequence name too long (%d/32)"), namelen);
960 wxCSConv seqnameconv(wxFONTENCODING_MACROMAN);
962 wxCSConv seqnameconv(wxT("macintosh"));
965 buffer.ReadBlock(33, (unsigned char *)name);
967 mName = wxString(seqnameconv.cMB2WC(name), *wxConvCurrent, namelen);
969 mNumberOfViews = buffer.ReadShort();
970 mFramesPerView = buffer.ReadShort();
971 mTicksPerFrame = buffer.ReadShort();
972 mKeyFrame = buffer.ReadShort();
973 mTransferMode = buffer.ReadShort();
974 mTransferModePeriod = buffer.ReadShort();
975 mFirstFrameSound = buffer.ReadShort();
976 mKeyFrameSound = buffer.ReadShort();
977 mLastFrameSound = buffer.ReadShort();
978 mPixelsToWorld = buffer.ReadShort();
979 mLoopFrame = buffer.ReadShort();
980 buffer.Position(buffer.Position() + 28);
983 wxLogDebug(wxT("[ShapesSequence] Type: %d"), mType);
984 wxLogDebug(wxT("[ShapesSequence] Flags: %d"), mFlags);
985 wxLogDebug(wxT("[ShapesSequence] Name: %s"), mName.c_str());
986 wxLogDebug(wxT("[ShapesSequence] Number of Views: %d"), mNumberOfViews);
987 wxLogDebug(wxT("[ShapesSequence] Frames/Views: %d"), mFramesPerView);
988 wxLogDebug(wxT("[ShapesSequence] Ticks/Frame: %d"), mTicksPerFrame);
989 wxLogDebug(wxT("[ShapesSequence] Key Frame: %d"), mKeyFrame);
990 wxLogDebug(wxT("[ShapesSequence] Transfer Mode: %d"), mTransferMode);
991 wxLogDebug(wxT("[ShapesSequence] Transfer Mode Period: %d"), mTransferModePeriod);
992 wxLogDebug(wxT("[ShapesSequence] First Frame Sound: %d"), mFirstFrameSound);
993 wxLogDebug(wxT("[ShapesSequence] Key Frame Sound: %d"), mKeyFrameSound);
994 wxLogDebug(wxT("[ShapesSequence] Last Frame Sound: %d"), mLastFrameSound);
995 wxLogDebug(wxT("[ShapesSequence] Pixels to World: %d"), mPixelsToWorld);
996 wxLogDebug(wxT("[ShapesSequence] Loop Frame: %d"), mLoopFrame);
999 if (mNumberOfViews < 0 || mFramesPerView < 0) {
1000 wxLogError(wxT("[ShapesSequence] Invalid sequence type parameters: numberOfViews=%d, framesPerView=%d"),
1001 mNumberOfViews, mFramesPerView);
1004 // guess these shouldn't be < 0, but RED Shapes have a case with mKeyFrame=-1
1005 if (mKeyFrame < -1 || mLoopFrame < -1) {
1006 wxLogError(wxT("[ShapesSequence] Invalid key/loop frame values in sequence data: keyFrame=%d, loopFrame=%d"),
1007 mKeyFrame, mLoopFrame);
1010 if (mFirstFrameSound < -1 || mKeyFrameSound < -1 || mLastFrameSound < -1) {
1011 wxLogError(wxT("[ShapesSequence] Invalid sound values in sequence data: firstFrameSound=%d, keyFrameSound=%d, lastFrameSound=%d"),
1012 mFirstFrameSound, mKeyFrameSound, mLastFrameSound);
1016 // load frame indexes
1017 int n = ActualNumberOfViews(mNumberOfViews) * mFramesPerView;
1020 for (int k = 0; k < n; k++)
1021 mFrameIndexes.push_back(buffer.ReadShort());
1024 buffer.ReadShort(); // terminating index (usually 0 but can be garbage)
1030 // given a high_level_shape_definition.mNumberOfViews value,
1031 // return the real number of views
1032 int ActualNumberOfViews(int t)
1049 wxLogError(wxT("[ShapesSequence] Unknown sequence type %d, don't know the number of views"), t);
1055 ShapesChunk::ShapesChunk(bool verbose): ShapesElement(verbose)
1060 ShapesChunk::~ShapesChunk(void)
1065 void ShapesChunk::Clear(void)
1069 for (i = 0; i < mColorTables.size(); i++)
1070 delete mColorTables[i];
1071 for (i = 0; i < mSequences.size(); i++)
1072 delete mSequences[i];
1073 for (i = 0; i < mFrames.size(); i++)
1075 for (i = 0; i < mBitmaps.size(); i++)
1078 mColorTables.clear();
1086 static bool compareColorTablePtrs(ShapesColorTable* lhs, ShapesColorTable* rhs) {
1087 return *lhs == *rhs;
1090 static bool compareSequencePtrs(ShapesSequence* lhs, ShapesSequence* rhs) {
1091 return *lhs == *rhs;
1094 static bool compareFramePtrs(ShapesFrame* lhs, ShapesFrame* rhs) {
1095 return *lhs == *rhs;
1098 static bool compareBitmapPtrs(ShapesBitmap* lhs, ShapesBitmap* rhs) {
1099 return *lhs == *rhs;
1102 bool ShapesChunk::operator==(const ShapesChunk& other) const
1104 if (mVersion == other.mVersion
1105 && mType == other.mType
1106 && mFlags == other.mFlags
1107 && mPixelsToWorld == other.mPixelsToWorld
1108 && mColorTables.size() == other.mColorTables.size()
1109 && mSequences.size() == other.mSequences.size()
1110 && mFrames.size() == other.mFrames.size()
1111 && mBitmaps.size() == other.mBitmaps.size()) {
1112 if (!std::equal(mColorTables.begin(), mColorTables.end(), other.mColorTables.begin(), compareColorTablePtrs))
1114 if (!std::equal(mSequences.begin(), mSequences.end(), other.mSequences.begin(), compareSequencePtrs))
1116 if (!std::equal(mFrames.begin(), mFrames.end(), other.mFrames.begin(), compareFramePtrs))
1118 return (std::equal(mBitmaps.begin(), mBitmaps.end(), other.mBitmaps.begin(), compareBitmapPtrs));
1124 ShapesColorTable* ShapesChunk::GetColorTable(unsigned int index) const
1126 if (index < 0 || index > mColorTables.size())
1128 return mColorTables[index];
1131 ShapesBitmap* ShapesChunk::GetBitmap(unsigned int index) const
1133 if (index < 0 || index > mBitmaps.size())
1135 return mBitmaps[index];
1138 ShapesFrame* ShapesChunk::GetFrame(unsigned int index) const
1140 if (index < 0 || index > mFrames.size())
1142 return mFrames[index];
1145 ShapesSequence* ShapesChunk::GetSequence(unsigned int index) const
1147 if (index < 0 || index > mSequences.size())
1149 return mSequences[index];
1152 void ShapesChunk::InsertColorTable(ShapesColorTable *ct)
1154 mColorTables.push_back(ct);
1157 void ShapesChunk::DeleteColorTable(unsigned int ct)
1159 mColorTables.erase(mColorTables.begin() + ct);
1162 void ShapesChunk::InsertBitmap(ShapesBitmap *b)
1164 mBitmaps.push_back(b);
1167 void ShapesChunk::DeleteBitmap(unsigned int b)
1169 if (b < mBitmaps.size()) {
1170 // preserve existing frame-bitmap associations and associate
1171 // a null bitmap to frames using the bitmap we're deleting
1172 for (unsigned int i = 0; i < mFrames.size(); i++) {
1173 short bitmap_index = mFrames[i]->BitmapIndex();
1175 if (bitmap_index == (int)b)
1176 mFrames[i]->SetBitmapIndex(-1);
1177 else if (bitmap_index > (int)b)
1178 mFrames[i]->SetBitmapIndex(bitmap_index - 1);
1180 // now actually delete the bitmap
1181 mBitmaps.erase(mBitmaps.begin() + b);
1185 void ShapesChunk::InsertFrame(ShapesFrame *f)
1187 mFrames.push_back(f);
1190 void ShapesChunk::DeleteFrame(unsigned int f)
1192 if (f < mFrames.size()) {
1193 // preserve existing sequence-frame associations and
1194 // unreference this frame index from any sequence using it
1195 for (unsigned int i = 0; i < mSequences.size(); i++) {
1196 for (unsigned int j = 0; j < mSequences[i]->FrameIndexCount(); j++) {
1197 short frame_index = mSequences[i]->GetFrameIndex(j);
1199 if (frame_index == (int)f)
1200 mSequences[i]->SetFrameIndex(j, -1);
1201 else if (frame_index > (int)f)
1202 mSequences[i]->SetFrameIndex(j, frame_index - 1);
1205 // now actually delete the frame
1206 mFrames.erase(mFrames.begin() + f);
1210 void ShapesChunk::InsertSequence(ShapesSequence *s)
1212 mSequences.push_back(s);
1215 void ShapesChunk::DeleteSequence(unsigned int s)
1217 if (s < mSequences.size())
1218 mSequences.erase(mSequences.begin() + s);
1221 void ShapesChunk::ClipboardCopy()
1223 if (wxTheClipboard->Open()) {
1224 size_t size = SizeInFile();
1225 unsigned char* data = new unsigned char[size];
1226 BigEndianBuffer buffer(data, size);
1230 wxCustomDataObject* dataObject = new wxCustomDataObject(wxDataFormat(wxT("application/vnd.shapefusion.shapeschunk")));
1231 dataObject->TakeData(size, data);
1233 wxTheClipboard->SetData(dataObject);
1235 wxTheClipboard->Close();
1239 void ShapesChunk::ClipboardPaste()
1241 if (wxTheClipboard->Open()) {
1242 wxCustomDataObject dataObject(wxDataFormat(wxT("application/vnd.shapefusion.shapeschunk")));
1243 if (wxTheClipboard->GetData(dataObject)) {
1244 BigEndianBuffer buffer(reinterpret_cast<unsigned char *>(dataObject.GetData()), dataObject.GetSize());
1251 wxTheClipboard->Close();
1255 unsigned int ShapesChunk::SizeInFile(void) const
1257 unsigned int bitmap_count = BitmapCount(),
1258 frame_count = FrameCount(),
1259 sequence_count = SequenceCount(),
1260 color_table_count = ColorTableCount(),
1263 // size of our definition
1264 size = SIZEOF_collection_definition;
1265 // add contribute of sequence offset table
1266 size += 4 * sequence_count;
1267 // add contribute of bitmap offset table
1268 size += 4 * bitmap_count;
1269 // add contribute of frame offset table
1270 size += 4 * frame_count;
1271 // add contribute of color tables
1272 if (color_table_count > 0)
1273 size += SIZEOF_rgb_color_value * color_table_count * GetColorTable(0)->ColorCount();
1274 // add contribute of bitmaps
1275 size += SIZEOF_bitmap_definition * bitmap_count;
1276 for (unsigned int i = 0; i < bitmap_count; i++) {
1277 ShapesBitmap *bitmap = mBitmaps[i];
1279 size += bitmap->SizeInFile();
1281 // add contribute of frame definitions
1282 size += SIZEOF_low_level_shape_definition * frame_count;
1283 // add contribute of sequence definitions (and following frame indexes)
1284 size += SIZEOF_high_level_shape_definition * sequence_count;
1285 for (unsigned int i = 0 ; i < sequence_count ; i++) {
1286 ShapesSequence *seq = mSequences[i];
1288 size += seq->SizeInFile();
1294 unsigned int ShapesChunk::SizeInPatch(const ShapesChunk* other) const {
1295 unsigned int size = 4; // 'cldf'
1297 size += SIZEOF_collection_definition;
1299 for (unsigned int i = 0; i < mColorTables.size(); ++i) {
1300 if (other == NULL || i >= other->mColorTables.size() || *mColorTables[i] != *other->mColorTables[i]) {
1301 size += SIZEOF_rgb_color_value * mColorTables[i]->ColorCount() + 8;
1305 for (unsigned int i = 0; i < mSequences.size(); ++i) {
1306 if (other == NULL || i >= other->mSequences.size() || *mSequences[i] != *other->mSequences[i]) {
1307 size += SIZEOF_high_level_shape_definition + mSequences[i]->SizeInPatch();
1312 for (unsigned int i = 0; i < mFrames.size(); ++i) {
1313 if (other == NULL || i >= other->mFrames.size() || *mFrames[i] != *other->mFrames[i]) {
1314 size += SIZEOF_low_level_shape_definition + 8;
1318 for (unsigned int i = 0; i < mBitmaps.size(); ++i) {
1319 if (other == NULL || i >= other->mBitmaps.size() || *mBitmaps[i] != *other->mBitmaps[i]) {
1320 size += SIZEOF_bitmap_definition + mBitmaps[i]->SizeInPatch();
1327 BigEndianBuffer& ShapesChunk::SaveObject(BigEndianBuffer& buffer)
1329 unsigned int bitmap_count = BitmapCount(),
1330 frame_count = FrameCount(),
1331 sequence_count = SequenceCount(),
1333 long sequence_table_offset,
1334 sequence_offsets[sequence_count],
1336 frame_offsets[frame_count],
1337 bitmap_table_offset,
1338 bitmap_offsets[bitmap_count];
1340 // skip the collection definition, we'll fill it at the end
1341 buffer.Position(SIZEOF_collection_definition);
1342 // write color tables
1343 for (i = 0; i < ColorTableCount(); i++)
1344 mColorTables[i]->SaveObject(buffer);
1347 sequence_table_offset = buffer.Position();
1348 if (sequence_count > 0) {
1349 buffer.Position(buffer.Position() + sequence_count * 4);
1351 for (i = 0; i < sequence_count; i++) {
1352 sequence_offsets[i] = buffer.Position();
1354 mSequences[i]->SaveObject(buffer);
1358 frame_table_offset = buffer.Position();
1359 buffer.Position(buffer.Position() + frame_count * 4);
1360 for (i = 0; i < frame_count; i++) {
1361 frame_offsets[i] = buffer.Position();
1363 mFrames[i]->SaveObject(buffer);
1367 bitmap_table_offset = buffer.Position();
1368 buffer.Position(buffer.Position() + bitmap_count * 4);
1369 for (i = 0; i < bitmap_count; i++) {
1370 bitmap_offsets[i] = buffer.Position();
1372 mBitmaps[i]->SaveObject(buffer);
1375 // go back and write the collection definition (with correct offsets)
1377 buffer.WriteShort(mVersion);
1378 buffer.WriteShort(mType);
1379 buffer.WriteUShort(mFlags);
1380 buffer.WriteShort(GetColorTable(0)->ColorCount());
1381 buffer.WriteShort(ColorTableCount());
1382 buffer.WriteLong(SIZEOF_collection_definition);
1383 buffer.WriteShort(sequence_count);
1384 buffer.WriteLong(sequence_table_offset);
1385 buffer.WriteShort(frame_count);
1386 buffer.WriteLong(frame_table_offset);
1387 buffer.WriteShort(bitmap_count);
1388 buffer.WriteLong(bitmap_table_offset);
1389 buffer.WriteShort(mPixelsToWorld);
1390 buffer.WriteLong(SizeInFile());
1391 buffer.WriteZeroes(506);
1393 // fill offset tables
1394 if (bitmap_count > 0) {
1395 buffer.Position(bitmap_table_offset);
1396 for (i = 0; i < bitmap_count; i++)
1397 buffer.WriteLong(bitmap_offsets[i]);
1399 if (frame_count > 0) {
1400 buffer.Position(frame_table_offset);
1401 for (i = 0; i < frame_count; i++)
1402 buffer.WriteLong(frame_offsets[i]);
1404 if (sequence_count > 0) {
1405 buffer.Position(sequence_table_offset);
1406 for (i = 0; i < sequence_count; i++)
1407 buffer.WriteLong(sequence_offsets[i]);
1413 BigEndianBuffer& ShapesChunk::SavePatch(BigEndianBuffer& buffer, const ShapesChunk* other)
1415 buffer.WriteLong(FOUR_CHARS_TO_INT('c','l','d','f'));
1417 // collection header
1418 buffer.WriteShort(mVersion);
1419 buffer.WriteShort(mType);
1420 buffer.WriteUShort(mFlags);
1421 buffer.WriteShort(GetColorTable(0)->ColorCount());
1422 buffer.WriteShort(ColorTableCount());
1423 buffer.WriteLong(SIZEOF_collection_definition);
1424 buffer.WriteShort(SequenceCount());
1425 buffer.WriteLong(0);
1426 buffer.WriteShort(FrameCount());
1427 buffer.WriteLong(0);
1428 buffer.WriteShort(BitmapCount());
1429 buffer.WriteLong(0);
1430 buffer.WriteShort(mPixelsToWorld);
1431 buffer.WriteLong(0);
1432 buffer.WriteZeroes(506);
1434 for (unsigned int i = 0; i < mColorTables.size(); ++i) {
1435 if (other == NULL || i >= other->mColorTables.size() || *mColorTables[i] != *other->mColorTables[i]) {
1436 mColorTables[i]->SavePatch(buffer, i);
1440 for (unsigned int i = 0; i < mSequences.size(); ++i) {
1441 if (other == NULL || i >= other->mSequences.size() || *mSequences[i] != *other->mSequences[i]) {
1442 mSequences[i]->SavePatch(buffer, i);
1446 for (unsigned int i = 0; i < mFrames.size(); ++i) {
1447 if (other == NULL || i >= other->mFrames.size() || *mFrames[i] != *other->mFrames[i]) {
1448 mFrames[i]->SavePatch(buffer, i);
1452 for (unsigned int i = 0; i < mBitmaps.size(); ++i) {
1453 if (other == NULL || i >= other->mBitmaps.size() || *mBitmaps[i] != *other->mBitmaps[i]) {
1454 mBitmaps[i]->SavePatch(buffer, i);
1461 BigEndianBuffer& ShapesChunk::LoadObject(BigEndianBuffer& buffer)
1466 high_level_shape_count,
1467 low_level_shape_count,
1469 long color_table_offset,
1470 high_level_shape_offset_table_offset,
1471 low_level_shape_offset_table_offset,
1472 bitmap_offset_table_offset,
1477 mVersion = buffer.ReadShort();
1478 mType = buffer.ReadShort();
1479 mFlags = buffer.ReadUShort();
1480 color_count = buffer.ReadShort();
1481 clut_count = buffer.ReadShort();
1482 color_table_offset = buffer.ReadLong();
1483 high_level_shape_count = buffer.ReadShort();
1484 high_level_shape_offset_table_offset = buffer.ReadLong();
1485 low_level_shape_count = buffer.ReadShort();
1486 low_level_shape_offset_table_offset = buffer.ReadLong();
1487 bitmap_count = buffer.ReadShort();
1488 bitmap_offset_table_offset = buffer.ReadLong();
1489 mPixelsToWorld = buffer.ReadShort();
1490 size = buffer.ReadLong();
1493 if (mVersion != COLLECTION_VERSION) {
1494 wxLogError(wxT("[ShapesChunk] Unknown collection version %d"), mVersion);
1498 if ((unsigned long)size != buffer.Size()) {
1499 wxLogError(wxT("[ShapesChunk] Chunk size mismatch (%ld/%d): this may not be a Marathon shapes file"), size, buffer.Size());
1502 if (color_table_offset < SIZEOF_collection_definition
1503 || color_table_offset >= size
1504 || high_level_shape_offset_table_offset < SIZEOF_collection_definition
1505 || high_level_shape_offset_table_offset >= size
1506 || low_level_shape_offset_table_offset < SIZEOF_collection_definition
1507 || low_level_shape_offset_table_offset >= size
1508 || bitmap_offset_table_offset < SIZEOF_collection_definition
1509 || bitmap_offset_table_offset >= size) {
1510 wxLogError(wxT("[ShapesChunk] Invalid offsets in collection definition: this may not be a Marathon shapes file"));
1513 if (color_count < 0 || clut_count < 0 || high_level_shape_count < 0 || low_level_shape_count < 0 || bitmap_count < 0) {
1514 wxLogError(wxT("[ShapesChunk] Invalid object counts in collection definition: this may not be a Marathon shapes file"));
1519 wxLogDebug(wxT("[ShapesChunk] Version: %d"), mVersion);
1520 wxLogDebug(wxT("[ShapesChunk] Type: %d"), mType);
1521 wxLogDebug(wxT("[ShapesChunk] Flags: %d"), mFlags);
1522 wxLogDebug(wxT("[ShapesChunk] %d color tables, %d colors per table"), clut_count, color_count);
1523 wxLogDebug(wxT("[ShapesChunk] %d sequences"), high_level_shape_count);
1524 wxLogDebug(wxT("[ShapesChunk] %d frames"), low_level_shape_count);
1525 wxLogDebug(wxT("[ShapesChunk] %d bitmaps"), bitmap_count);
1528 // load color tables
1529 for (i = 0; i < clut_count; i++) {
1530 ShapesColorTable *color_table = new ShapesColorTable(IsVerbose());
1533 wxLogDebug(wxT("[ShapesChunk] Loading colortable %d/%d"), i+1, clut_count);
1535 oldpos = buffer.Position();
1537 color_table->LoadObject(buffer, color_table_offset + i * color_count * SIZEOF_rgb_color_value, color_count);
1539 buffer.Position(oldpos);
1541 // we stop if an error occured
1542 if (!color_table->IsGood()) {
1543 wxLogError(wxT("[ShapesChunk] Error loading color table %d... Dropped"), i);
1547 mColorTables.push_back(color_table);
1550 // load bitmaps, decoding compressed ones
1551 buffer.Position(bitmap_offset_table_offset);
1552 for (i = 0; i < bitmap_count; i++) {
1553 offset = buffer.ReadLong();
1554 if (offset < SIZEOF_collection_definition || offset >= size) {
1555 wxLogError(wxT("[ShapesChunk] Invalid bitmap offset: this may not be a Marathon shapes file"));
1559 ShapesBitmap *bitmap = new ShapesBitmap(IsVerbose());
1561 wxLogDebug(wxT("[ShapesChunk] Loading bitmap %d/%d"), i+1, bitmap_count);
1563 oldpos = buffer.Position();
1565 bitmap->LoadObject(buffer, offset);
1567 buffer.Position(oldpos);
1569 // we stop if an error occured
1570 if (!bitmap->IsGood()) {
1571 wxLogError(wxT("[ShapesDocument] Error loading bitmap %d... Dropped"), i);
1575 mBitmaps.push_back(bitmap);
1579 buffer.Position(high_level_shape_offset_table_offset);
1580 for (i = 0; i < high_level_shape_count; i++) {
1581 offset = buffer.ReadLong();
1582 if (offset < SIZEOF_collection_definition || offset >= size) {
1583 wxLogError(wxT("[ShapesChunk] Invalid sequence offset: this may not be a Marathon shapes file"));
1587 ShapesSequence *sequence = new ShapesSequence(IsVerbose());
1589 wxLogDebug(wxT("[ShapesChunk] Loading sequence %d/%d"), i+1, high_level_shape_count);
1591 oldpos = buffer.Position();
1593 sequence->LoadObject(buffer, offset);
1595 buffer.Position(oldpos);
1597 // we stop if an error occured
1598 if (!sequence->IsGood()) {
1599 wxLogError(wxT("[ShapesDocument] Error loading sequence... Dropped"));
1603 mSequences.push_back(sequence);
1607 buffer.Position(low_level_shape_offset_table_offset);
1608 for (i = 0; i < low_level_shape_count; i++) {
1609 offset = buffer.ReadLong();
1610 if (offset < SIZEOF_collection_definition || offset >= size) {
1611 wxLogError(wxT("[ShapesChunk] Invalid frame offset: this may not be a Marathon shapes file"));
1615 ShapesFrame *frame = new ShapesFrame(IsVerbose());
1617 wxLogDebug(wxT("[ShapesChunk] Loading frame %d/%d"), i+1, low_level_shape_count);
1619 oldpos = buffer.Position();
1621 frame->LoadObject(buffer, offset);
1623 buffer.Position(oldpos);
1624 // calculate scale factor from world_* fields and associated bitmap dimensions.
1625 // If this fails, default to collection global scale factor
1626 if (frame->BitmapIndex() >= 0 && frame->BitmapIndex() < (int)mBitmaps.size()) {
1627 int bitmapWidth = mBitmaps[frame->BitmapIndex()]->Width();
1629 if (bitmapWidth > 0)
1630 frame->SetScaleFactor((frame->WorldRight() - frame->WorldLeft()) / bitmapWidth);
1632 frame->SetScaleFactor(mPixelsToWorld);
1634 frame->SetScaleFactor(mPixelsToWorld);
1638 if (!frame->IsGood()) {
1639 wxLogError(wxT("[ShapesDocument] Error loading frame %d... Dropped"), i);
1643 mFrames.push_back(frame);
1650 BigEndianBuffer& ShapesChunk::LoadPatch(BigEndianBuffer& buffer)
1654 long tag = buffer.ReadLong();
1655 short color_count = 0;
1657 while (tag != FOUR_CHARS_TO_INT('e','n','d','c')) {
1659 case FOUR_CHARS_TO_INT('c','l','d','f'): {
1660 mVersion = buffer.ReadShort();
1661 if (mVersion != COLLECTION_VERSION) {
1662 wxLogError(wxT("[ShapesChunk] Unknown 'cldf' version %d in patch"), mVersion);
1667 mType = buffer.ReadShort();
1668 mFlags = buffer.ReadUShort();
1669 color_count = buffer.ReadShort();
1670 mColorTables.resize(buffer.ReadShort());
1671 buffer.ReadLong(); // color table offset
1672 mSequences.resize(buffer.ReadShort());
1673 buffer.ReadLong(); // high level shape offset
1674 mFrames.resize(buffer.ReadShort());
1675 buffer.ReadLong(); // low level shape offset
1676 mBitmaps.resize(buffer.ReadShort());
1677 buffer.ReadLong(); // bitmap offsets
1678 mPixelsToWorld = buffer.ReadShort();
1679 buffer.ReadLong(); // size
1680 buffer.Position(buffer.Position() + 506);
1683 case FOUR_CHARS_TO_INT('c','t','a','b'): {
1684 long index = buffer.ReadLong();
1685 if (index < mColorTables.size()) {
1686 ShapesColorTable* c = new ShapesColorTable(IsVerbose());
1687 c->LoadObject(buffer, buffer.Position(), color_count);
1689 delete mColorTables[index];
1690 mColorTables[index] = c;
1696 wxLogError(wxT("[ShapesChunk] Invliad 'ctab' index"));
1702 case FOUR_CHARS_TO_INT('h','l','s','h'): {
1703 long index = buffer.ReadLong();
1704 long chunk_size = buffer.ReadLong();
1705 long position = buffer.Position();
1706 if (index < mSequences.size()) {
1707 ShapesSequence* ss = new ShapesSequence(IsVerbose());
1708 ss->LoadObject(buffer, position);
1709 buffer.Position(position + chunk_size);
1711 delete mSequences[index];
1712 mSequences[index] = ss;
1718 wxLogError(wxT("[ShapesChunk] Invalid 'hlsh' index"));
1724 case FOUR_CHARS_TO_INT('l','l','s','h'): {
1725 long index = buffer.ReadLong();
1726 if (index < mFrames.size()) {
1727 ShapesFrame* sf = new ShapesFrame(IsVerbose());
1728 sf->LoadObject(buffer, buffer.Position());
1730 delete mFrames[index];
1731 mFrames[index] = sf;
1737 wxLogError(wxT("[ShapesChunk] Invalid 'llsh' index"));
1743 case FOUR_CHARS_TO_INT('b','m','a','p'): {
1744 long index = buffer.ReadLong();
1745 long size = buffer.ReadLong();
1746 long position = buffer.Position();
1748 if (index < mBitmaps.size()) {
1749 ShapesBitmap* b = new ShapesBitmap(IsVerbose());
1750 b->LoadObject(buffer, position);
1751 buffer.Position(position + size);
1753 delete mBitmaps[index];
1754 mBitmaps[index] = b;
1760 wxLogError(wxT("[ShapesChunk] Invalid 'bmap' index"));
1768 tag = buffer.ReadLong();
1774 ShapesCollection::ShapesCollection(bool verbose): ShapesElement(verbose)
1780 ShapesCollection::~ShapesCollection(void)
1788 bool ShapesCollection::Defined(unsigned int chunk) const
1790 if (chunk > COLL_VERSION_TRUECOLOR)
1792 return mChunks[chunk] != NULL;
1795 int ShapesCollection::Version(unsigned int chunk) const
1797 return (Defined(chunk) ? mChunks[chunk]->Version() : 0);
1800 int ShapesCollection::Type(unsigned int chunk) const
1802 return (Defined(chunk) ? mChunks[chunk]->Type() : 0);
1805 int ShapesCollection::Flags(unsigned int chunk) const
1807 return (Defined(chunk) ? mChunks[chunk]->Flags() : 0);
1810 int ShapesCollection::ScaleFactor(unsigned int chunk) const
1812 return (Defined(chunk) ? mChunks[chunk]->ScaleFactor() : 0);
1815 int ShapesCollection::ColorTableCount(unsigned int chunk) const
1817 return (Defined(chunk) ? mChunks[chunk]->ColorTableCount() : 0);
1820 int ShapesCollection::BitmapCount(unsigned int chunk) const
1822 return (Defined(chunk) ? mChunks[chunk]->BitmapCount() : 0);
1825 int ShapesCollection::FrameCount(unsigned int chunk) const
1827 return (Defined(chunk) ? mChunks[chunk]->FrameCount() : 0);
1830 int ShapesCollection::SequenceCount(unsigned int chunk) const
1832 return (Defined(chunk) ? mChunks[chunk]->SequenceCount() : 0);
1835 ShapesColorTable* ShapesCollection::GetColorTable(unsigned int chunk, unsigned int index) const
1837 return (Defined(chunk) ? mChunks[chunk]->GetColorTable(index) : NULL);
1840 ShapesBitmap* ShapesCollection::GetBitmap(unsigned int chunk, unsigned int index) const
1842 return (Defined(chunk) ? mChunks[chunk]->GetBitmap(index) : NULL);
1845 ShapesFrame* ShapesCollection::GetFrame(unsigned int chunk, unsigned int index) const
1847 return (Defined(chunk) ? mChunks[chunk]->GetFrame(index) : NULL);
1850 ShapesSequence* ShapesCollection::GetSequence(unsigned int chunk, unsigned int index) const
1852 return (Defined(chunk) ? mChunks[chunk]->GetSequence(index) : NULL);
1855 ShapesChunk* ShapesCollection::GetChunk(unsigned int chunk) const
1857 return (Defined(chunk) ? mChunks[chunk] : NULL);
1860 void ShapesCollection::InsertColorTable(ShapesColorTable *ct, unsigned int chunk)
1863 mChunks[chunk]->InsertColorTable(ct);
1866 void ShapesCollection::DeleteColorTable(unsigned int chunk, unsigned int ct)
1869 mChunks[chunk]->DeleteColorTable(ct);
1872 void ShapesCollection::InsertBitmap(ShapesBitmap *b, unsigned int chunk)
1875 mChunks[chunk]->InsertBitmap(b);
1878 void ShapesCollection::DeleteBitmap(unsigned int chunk, unsigned int b)
1881 mChunks[chunk]->DeleteBitmap(b);
1884 void ShapesCollection::InsertFrame(ShapesFrame *f, unsigned int chunk)
1887 mChunks[chunk]->InsertFrame(f);
1890 void ShapesCollection::DeleteFrame(unsigned int chunk, unsigned int f)
1893 mChunks[chunk]->DeleteFrame(f);
1896 void ShapesCollection::InsertSequence(ShapesSequence *s, unsigned int chunk)
1899 mChunks[chunk]->InsertSequence(s);
1902 void ShapesCollection::DeleteSequence(unsigned int chunk, unsigned int s)
1905 mChunks[chunk]->DeleteSequence(s);
1908 // calculate how much space a collection is going
1909 // to take when encoded to its on-file format.
1910 unsigned int ShapesCollection::SizeInFile(unsigned int chunk) const
1912 if (!Defined(chunk))
1915 unsigned int size = 0;
1917 size += mChunks[chunk]->SizeInFile();
1921 #if wxUSE_STD_IOSTREAM
1922 wxSTD ostream& ShapesCollection::SaveObject(wxSTD ostream& stream)
1924 wxOutputStream& ShapesCollection::SaveObject(wxOutputStream& stream)
1927 for (unsigned int i = 0; i < 2 ; i++) {
1929 BigEndianBuffer chunkbuffer(mChunks[i]->SizeInFile());
1931 mChunks[i]->SaveObject(chunkbuffer);
1932 #if wxUSE_STD_IOSTREAM
1933 stream.write((char *)chunkbuffer.Data(), chunkbuffer.Size());
1935 stream.Write((char *)chunkbuffer.Data(), chunkbuffer.Size());
1942 #if wxUSE_STD_IOSTREAM
1943 wxSTD ostream& ShapesCollection::SavePatch(wxSTD ostream& stream, const ShapesCollection& other, int index, int depth)
1945 wxOutputStream& ShapesCollection::SavePatch(wxOutputStream& stream, const ShapesCollection& other, int index, int depth)
1948 bool diff = Defined(depth) && (other.mChunks[depth] == NULL || *mChunks[depth] != *other.mChunks[depth]);
1949 unsigned int size = 12;
1951 size += mChunks[depth]->SizeInPatch(other.mChunks[depth]);
1954 BigEndianBuffer chunkbuffer(size);
1955 chunkbuffer.WriteLong(index);
1956 chunkbuffer.WriteLong(depth ? 16 : 8);
1958 mChunks[depth]->SavePatch(chunkbuffer, other.mChunks[depth]);
1960 chunkbuffer.WriteLong(FOUR_CHARS_TO_INT('e','n','d','c'));
1961 #if wxUSE_STD_IOSTREAM
1962 stream.write((char *)chunkbuffer.Data(), chunkbuffer.Size());
1964 stream.Write((char *)chunkbuffer.Data(), chunkbuffer.Size());
1970 #if wxUSE_STD_IOSTREAM
1971 wxSTD istream& ShapesCollection::LoadObject(wxSTD istream& stream)
1973 wxInputStream& ShapesCollection::LoadObject(wxInputStream& stream)
1976 BigEndianBuffer coll_header(SIZEOF_collection_header);
1978 #if wxUSE_STD_IOSTREAM
1979 stream.read((char *)coll_header.Data(), coll_header.Size());
1981 stream.Read((char *)coll_header.Data(), coll_header.Size());
1984 #if wxUSE_STD_IOSTREAM
1985 stream.seekg(0, std::ios::end);
1986 wxInt32 filesize = stream.tellg();
1987 stream.seekg(0, std::ios::beg);
1989 wxInt32 filesize = stream.GetSize();
1992 long offset8, length8,
1995 mStatus = coll_header.ReadShort();
1996 mFlags = coll_header.ReadUShort();
1997 offset8 = coll_header.ReadLong();
1998 length8 = coll_header.ReadLong();
1999 offset16 = coll_header.ReadLong();
2000 length16 = coll_header.ReadLong();
2002 if (offset8 < -1 || length8 < 0 || offset16 < -1 || length16 < 0)
2004 if ((offset8 + length8) > filesize)
2006 if ((offset16 + length16) > filesize)
2010 wxLogDebug(wxT("[ShapesCollection] Status: %d"), mStatus);
2011 wxLogDebug(wxT("[ShapesCollection] Flags: %d"), mFlags);
2014 // is there the 8-bit version?
2015 if (offset8 != -1) {
2017 wxLogDebug(wxT("[ShapesCollection] 8-bit chunk present"));
2019 BigEndianBuffer chunkbuffer(length8);
2021 #if wxUSE_STD_IOSTREAM
2022 stream.seekg(offset8, std::ios::beg);
2023 stream.read((char *)chunkbuffer.Data(), chunkbuffer.Size());
2025 stream.SeekI(offset8, wxFromStart);
2026 stream.Read((char *)chunkbuffer.Data(), chunkbuffer.Size());
2029 ShapesChunk *pc = new ShapesChunk(IsVerbose());
2030 pc->LoadObject(chunkbuffer);
2032 if (!pc->IsGood()) {
2033 wxLogError(wxT("[ShapesCollection] Error loading 8-bit chunk... Dropped"));
2039 // is there the 16-bit version?
2040 if (offset16 != -1) {
2042 wxLogDebug(wxT("[ShapesCollection] 16/32-bit chunk present"));
2044 BigEndianBuffer chunkbuffer(length16);
2046 #if wxUSE_STD_IOSTREAM
2047 stream.seekg(offset16, std::ios::beg);
2048 stream.read((char *)chunkbuffer.Data(), chunkbuffer.Size());
2050 stream.SeekI(offset16, wxFromStart);
2051 stream.Read((char *)chunkbuffer.Data(), chunkbuffer.Size());
2054 ShapesChunk *pc = new ShapesChunk(IsVerbose());
2055 pc->LoadObject(chunkbuffer);
2057 if (!pc->IsGood()) {
2058 wxLogError(wxT("[ShapesCollection] Error loading 16/32-bit chunk... Dropped"));
2068 BigEndianBuffer& ShapesCollection::LoadPatch(BigEndianBuffer& buffer)
2070 int depth = buffer.ReadLong();
2071 ShapesChunk* chunk = 0;
2074 mChunks[0] = new ShapesChunk(IsVerbose());
2077 } else if (depth == 16) {
2079 mChunks[1] = new ShapesChunk(IsVerbose());
2083 wxLogError(wxT("[ShapesCollection] Error loading patch chunk; invalid depth"));
2088 chunk->LoadPatch(buffer);
2089 if (!chunk->IsGood()) {