1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 /*
24 * This code is based on Broken Sword 2.5 engine
25 *
26 * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
27 *
28 * Licensed under GNU GPL v2
29 *
30 */
31
32 // -----------------------------------------------------------------------------
33 // Includes
34 // -----------------------------------------------------------------------------
35
36 #include "sword25/gfx/image/art.h"
37 #include "sword25/gfx/image/vectorimage.h"
38 #include "sword25/gfx/image/renderedimage.h"
39
40 namespace Sword25 {
41
42 #define BEZSMOOTHNESS 0.5
43
44 // -----------------------------------------------------------------------------
45 // SWF datatype
46 // -----------------------------------------------------------------------------
47
48 // -----------------------------------------------------------------------------
49 // Bitstream helper class
50 // -----------------------------------------------------------------------------
51 // The parsing of SWF files requires both bitwise readout and on Byte boundaries
52 // oriented reading.
53 // This class is specially equipped for this.
54 // -----------------------------------------------------------------------------
55
56 class VectorImage::SWFBitStream {
57 public:
SWFBitStream(const byte * pData,uint dataSize)58 SWFBitStream(const byte *pData, uint dataSize) :
59 m_Pos(pData), m_End(pData + dataSize), m_WordMask(0)
60 {}
61
getBits(uint bitCount)62 inline uint32 getBits(uint bitCount) {
63 if (bitCount == 0 || bitCount > 32) {
64 error("SWFBitStream::GetBits() must read at least 1 and at most 32 bits at a time");
65 }
66
67 uint32 value = 0;
68 while (bitCount) {
69 if (m_WordMask == 0)
70 flushByte();
71
72 value <<= 1;
73 value |= ((m_Word & m_WordMask) != 0) ? 1 : 0;
74 m_WordMask >>= 1;
75
76 --bitCount;
77 }
78
79 return value;
80 }
81
getSignedBits(uint bitCount)82 inline int32 getSignedBits(uint bitCount) {
83 // readout bits
84 uint32 temp = getBits(bitCount);
85
86 // If the sign-bit is set, fill the rest of the return value with 1-bit (sign extension)
87 if (temp & 1 << (bitCount - 1))
88 return (0xffffffff << bitCount) | temp;
89 else
90 return temp;
91 }
92
getUInt32()93 inline uint32 getUInt32() {
94 uint32 byte1 = getByte();
95 uint32 byte2 = getByte();
96 uint32 byte3 = getByte();
97 uint32 byte4 = getByte();
98
99 return byte1 | (byte2 << 8) | (byte3 << 16) | (byte4 << 24);
100 }
101
getUInt16()102 inline uint16 getUInt16() {
103 uint32 byte1 = getByte();
104 uint32 byte2 = getByte();
105
106 return byte1 | (byte2 << 8);
107 }
108
getByte()109 inline byte getByte() {
110 flushByte();
111 byte value = m_Word;
112 m_WordMask = 0;
113 flushByte();
114
115 return value;
116 }
117
flushByte()118 inline void flushByte() {
119 if (m_WordMask != 128) {
120 if (m_Pos >= m_End) {
121 error("Attempted to read past end of file");
122 } else {
123 m_Word = *m_Pos++;
124 m_WordMask = 128;
125 }
126 }
127 }
128
skipBytes(uint skipLength)129 inline void skipBytes(uint skipLength) {
130 flushByte();
131 if (m_Pos + skipLength >= m_End) {
132 error("Attempted to read past end of file");
133 } else {
134 m_Pos += skipLength;
135 m_Word = *(m_Pos - 1);
136 }
137 }
138
139 private:
140 const byte *m_Pos;
141 const byte *m_End;
142
143 byte m_Word;
144 uint m_WordMask;
145 };
146
147
148 // -----------------------------------------------------------------------------
149 // Constants and utility functions
150 // -----------------------------------------------------------------------------
151
152 namespace {
153 // -----------------------------------------------------------------------------
154 // Constants
155 // -----------------------------------------------------------------------------
156
157 const uint32 MAX_ACCEPTED_FLASH_VERSION = 3; // The maximum flash file version that is accepted by the loader
158
159
160 // -----------------------------------------------------------------------------
161 // Converts SWF rectangle data in a bit stream in Common::Rect objects
162 // -----------------------------------------------------------------------------
163
flashRectToBSRect(VectorImage::SWFBitStream & bs)164 Common::Rect flashRectToBSRect(VectorImage::SWFBitStream &bs) {
165 bs.flushByte();
166
167 // Determines how many bits of the single components are encoded
168 uint32 bitsPerValue = bs.getBits(5);
169
170 // Readout the single components
171 int32 xMin = bs.getSignedBits(bitsPerValue);
172 int32 xMax = bs.getSignedBits(bitsPerValue);
173 int32 yMin = bs.getSignedBits(bitsPerValue);
174 int32 yMax = bs.getSignedBits(bitsPerValue);
175
176 return Common::Rect(xMin, yMin, xMax + 1, yMax + 1);
177 }
178
179 // -----------------------------------------------------------------------------
180 // Calculate the bounding box of a BS_VectorImageElement
181 // -----------------------------------------------------------------------------
182
CalculateBoundingBox(const VectorImageElement & vectorImageElement)183 Common::Rect CalculateBoundingBox(const VectorImageElement &vectorImageElement) {
184 double x0 = 0.0, y0 = 0.0, x1 = 0.0, y1 = 0.0;
185
186 for (int j = vectorImageElement.getPathCount() - 1; j >= 0; j--) {
187 ArtBpath *bez = vectorImageElement.getPathInfo(j).getVec();
188 ArtVpath *vec = art_bez_path_to_vec(bez, 0.5);
189
190 if (vec[0].code == ART_END) {
191 free(vec);
192 continue;
193 } else {
194 x0 = x1 = vec[0].x;
195 y0 = y1 = vec[0].y;
196 for (int i = 1; vec[i].code != ART_END; i++) {
197 if (vec[i].x < x0) x0 = vec[i].x;
198 if (vec[i].x > x1) x1 = vec[i].x;
199 if (vec[i].y < y0) y0 = vec[i].y;
200 if (vec[i].y > y1) y1 = vec[i].y;
201 }
202 }
203 free(vec);
204 }
205
206 return Common::Rect(static_cast<int>(x0), static_cast<int>(y0), static_cast<int>(x1) + 1, static_cast<int>(y1) + 1);
207 }
208
209 }
210
211
212 // -----------------------------------------------------------------------------
213 // Construction
214 // -----------------------------------------------------------------------------
215
VectorImage(const byte * pFileData,uint fileSize,bool & success,const Common::String & fname)216 VectorImage::VectorImage(const byte *pFileData, uint fileSize, bool &success, const Common::String &fname) : _pixelData(0), _fname(fname) {
217 success = false;
218 _bgColor = 0;
219
220 // Create bitstream object
221 // In the following the file data will be readout of the bitstream object.
222 SWFBitStream bs(pFileData, fileSize);
223
224 // Check SWF signature
225 uint32 signature[3];
226 signature[0] = bs.getByte();
227 signature[1] = bs.getByte();
228 signature[2] = bs.getByte();
229 if (signature[0] != 'F' ||
230 signature[1] != 'W' ||
231 signature[2] != 'S') {
232 error("File is not a valid SWF-file");
233 return;
234 }
235
236 // Check the version
237 uint32 version = bs.getByte();
238 if (version > MAX_ACCEPTED_FLASH_VERSION) {
239 error("File is of version %d. Highest accepted version is %d.", version, MAX_ACCEPTED_FLASH_VERSION);
240 return;
241 }
242
243 // Readout filesize and compare with the actual size
244 uint32 storedFileSize = bs.getUInt32();
245 if (storedFileSize != fileSize) {
246 error("File is not a valid SWF-file");
247 return;
248 }
249
250 // readout SWF size
251 flashRectToBSRect(bs);
252
253 // Get frame rate and frame count
254 /* uint32 frameRate = */
255 bs.getUInt16();
256 /* uint32 frameCount = */
257 bs.getUInt16();
258
259 // Parse tags
260 // Because we are only interested in the first DifneShape-Tag...
261 bool keepParsing = true;
262 while (keepParsing) {
263 // Tags always begin on byte boundaries
264 bs.flushByte();
265
266 // Readout tag type and length
267 uint16 tagTypeAndLength = bs.getUInt16();
268 uint32 tagType = tagTypeAndLength >> 6;
269 uint32 tagLength = tagTypeAndLength & 0x3f;
270 if (tagLength == 0x3f)
271 tagLength = bs.getUInt32();
272
273 switch (tagType) {
274 case 2:
275 // DefineShape
276 success = parseDefineShape(2, bs);
277 return;
278 case 22:
279 // DefineShape2
280 success = parseDefineShape(2, bs);
281 return;
282 case 32:
283 success = parseDefineShape(3, bs);
284 return;
285 case 9:
286 // SetBackgroundColor
287 {
288 byte r, g, b;
289 r = bs.getByte();
290 g = bs.getByte();
291 b = bs.getByte();
292 _bgColor = BS_RGB(r, g, b);
293 }
294 break;
295 default:
296 warning("Ignoring tag: %d, %d bytes", tagType, tagLength);
297 // Ignore unknown tags
298 bs.skipBytes(tagLength);
299 }
300 }
301
302 // The execution must not arrive at this point: Either a shape is found, then the function will be leaved before, or it is found none, then
303 // an exception occurs as soon as it is read beyond of the end of file.
304 assert(false);
305 }
306
~VectorImage()307 VectorImage::~VectorImage() {
308 for (int j = _elements.size() - 1; j >= 0; j--)
309 for (int i = _elements[j].getPathCount() - 1; i >= 0; i--)
310 if (_elements[j].getPathInfo(i).getVec())
311 free(_elements[j].getPathInfo(i).getVec());
312
313 free(_pixelData);
314 }
315
316
ensureBezStorage(ArtBpath * bez,int nodes,int * allocated)317 ArtBpath *ensureBezStorage(ArtBpath *bez, int nodes, int *allocated) {
318 if (*allocated <= nodes) {
319 (*allocated) += 20;
320
321 return art_renew(bez, ArtBpath, *allocated);
322 }
323
324 return bez;
325 }
326
storeBez(ArtBpath * bez,int lineStyle,int fillStyle0,int fillStyle1,int * bezNodes,int * bezAllocated)327 ArtBpath *VectorImage::storeBez(ArtBpath *bez, int lineStyle, int fillStyle0, int fillStyle1, int *bezNodes, int *bezAllocated) {
328 (*bezNodes)++;
329
330 bez = ensureBezStorage(bez, *bezNodes, bezAllocated);
331 bez[*bezNodes].code = ART_END;
332
333 ArtBpath *bez1 = art_new(ArtBpath, *bezNodes + 1);
334 if (!bez1)
335 error("[VectorImage::storeBez] Cannot allocate memory");
336
337 for (int i = 0; i <= *bezNodes; i++)
338 bez1[i] = bez[i];
339
340 _elements.back()._pathInfos.push_back(VectorPathInfo(bez1, *bezNodes, lineStyle, fillStyle0, fillStyle1));
341
342 return bez;
343 }
344
parseDefineShape(uint shapeType,SWFBitStream & bs)345 bool VectorImage::parseDefineShape(uint shapeType, SWFBitStream &bs) {
346 /*uint32 shapeID = */bs.getUInt16();
347
348 // readout bounding box
349 _boundingBox = flashRectToBSRect(bs);
350
351 // create first image element
352 _elements.resize(1);
353
354 // read styles
355 uint numFillBits;
356 uint numLineBits;
357 if (!parseStyles(shapeType, bs, numFillBits, numLineBits))
358 return false;
359
360 uint lineStyle = 0;
361 uint fillStyle0 = 0;
362 uint fillStyle1 = 0;
363
364 // parse shaperecord
365 // ------------------
366
367 double curX = 0;
368 double curY = 0;
369 int bezNodes = 0;
370 int bezAllocated = 10;
371 ArtBpath *bez = art_new(ArtBpath, bezAllocated);
372
373 bool endOfShapeDiscovered = false;
374 while (!endOfShapeDiscovered) {
375 uint32 typeFlag = bs.getBits(1);
376
377 // Non-Edge Record
378 if (typeFlag == 0) {
379 // Determines which parameters are set
380 uint32 stateNewStyles = bs.getBits(1);
381 uint32 stateLineStyle = bs.getBits(1);
382 uint32 stateFillStyle1 = bs.getBits(1);
383 uint32 stateFillStyle0 = bs.getBits(1);
384 uint32 stateMoveTo = bs.getBits(1);
385
386 uint prevLineStyle = lineStyle;
387 uint prevFillStyle0 = fillStyle0;
388 uint prevFillStyle1 = fillStyle1;
389
390 // End of the shape definition is reached?
391 if (!stateNewStyles && !stateLineStyle && !stateFillStyle0 && !stateFillStyle1 && !stateMoveTo) {
392 endOfShapeDiscovered = true;
393 // Decode parameters
394 } else {
395 if (stateMoveTo) {
396 uint32 moveToBits = bs.getBits(5);
397 curX = bs.getSignedBits(moveToBits);
398 curY = bs.getSignedBits(moveToBits);
399 }
400
401 if (stateFillStyle0) {
402 if (numFillBits > 0)
403 fillStyle0 = bs.getBits(numFillBits);
404 else
405 fillStyle0 = 0;
406 }
407
408 if (stateFillStyle1) {
409 if (numFillBits > 0)
410 fillStyle1 = bs.getBits(numFillBits);
411 else
412 fillStyle1 = 0;
413 }
414
415 if (stateLineStyle) {
416 if (numLineBits)
417 lineStyle = bs.getBits(numLineBits);
418 else
419 numLineBits = 0;
420 }
421
422 // Create a new path, unless there were only defined new styles
423 if (stateLineStyle || stateFillStyle0 || stateFillStyle1 || stateMoveTo) {
424 // Store previous curve if any
425 if (bezNodes) {
426 bez = storeBez(bez, prevLineStyle, prevFillStyle0, prevFillStyle1, &bezNodes, &bezAllocated);
427 }
428
429 // Start new curve
430 bez = ensureBezStorage(bez, 1, &bezAllocated);
431 bez[0].code = ART_MOVETO_OPEN;
432 bez[0].x3 = curX;
433 bez[0].y3 = curY;
434 bezNodes = 0;
435 }
436
437 if (stateNewStyles) {
438 // The old style definitions will be discarded and overwritten with the new at this point in Flash.
439 // A new element will be started with a new element.
440 _elements.resize(_elements.size() + 1);
441 if (!parseStyles(shapeType, bs, numFillBits, numLineBits))
442 return false;
443 }
444 }
445 } else {
446 // Edge record
447 uint32 edgeFlag = bs.getBits(1);
448 uint32 numBits = bs.getBits(4) + 2;
449
450 // Curved edge
451 if (edgeFlag == 0) {
452 double controlDeltaX = bs.getSignedBits(numBits);
453 double controlDeltaY = bs.getSignedBits(numBits);
454 double anchorDeltaX = bs.getSignedBits(numBits);
455 double anchorDeltaY = bs.getSignedBits(numBits);
456
457 double controlX = curX + controlDeltaX;
458 double controlY = curY + controlDeltaY;
459 double newX = controlX + anchorDeltaX;
460 double newY = controlY + anchorDeltaY;
461
462 #define WEIGHT (2.0/3.0)
463
464 bezNodes++;
465 bez = ensureBezStorage(bez, bezNodes, &bezAllocated);
466 bez[bezNodes].code = ART_CURVETO;
467 bez[bezNodes].x1 = WEIGHT * controlX + (1 - WEIGHT) * curX;
468 bez[bezNodes].y1 = WEIGHT * controlY + (1 - WEIGHT) * curY;
469 bez[bezNodes].x2 = WEIGHT * controlX + (1 - WEIGHT) * newX;
470 bez[bezNodes].y2 = WEIGHT * controlY + (1 - WEIGHT) * newY;
471 bez[bezNodes].x3 = newX;
472 bez[bezNodes].y3 = newY;
473
474 curX = newX;
475 curY = newY;
476 } else {
477 // Staight edge
478 int32 deltaX = 0;
479 int32 deltaY = 0;
480
481 uint32 generalLineFlag = bs.getBits(1);
482 if (generalLineFlag) {
483 deltaX = bs.getSignedBits(numBits);
484 deltaY = bs.getSignedBits(numBits);
485 } else {
486 uint32 vertLineFlag = bs.getBits(1);
487 if (vertLineFlag)
488 deltaY = bs.getSignedBits(numBits);
489 else
490 deltaX = bs.getSignedBits(numBits);
491 }
492
493 curX += deltaX;
494 curY += deltaY;
495
496 bezNodes++;
497 bez = ensureBezStorage(bez, bezNodes, &bezAllocated);
498 bez[bezNodes].code = ART_LINETO;
499 bez[bezNodes].x3 = curX;
500 bez[bezNodes].y3 = curY;
501 }
502 }
503 }
504
505 // Store last curve
506 if (bezNodes)
507 bez = storeBez(bez, lineStyle, fillStyle0, fillStyle1, &bezNodes, &bezAllocated);
508
509 free(bez);
510
511 // Calculate the bounding boxes of each element
512 Common::Array<VectorImageElement>::iterator it = _elements.begin();
513 for (; it != _elements.end(); ++it)
514 it->_boundingBox = CalculateBoundingBox(*it);
515
516 return true;
517 }
518
519
520 // -----------------------------------------------------------------------------
521
parseStyles(uint shapeType,SWFBitStream & bs,uint & numFillBits,uint & numLineBits)522 bool VectorImage::parseStyles(uint shapeType, SWFBitStream &bs, uint &numFillBits, uint &numLineBits) {
523 bs.flushByte();
524
525 // Parse fill styles
526 // -----------------
527
528 // Determine number of fill styles
529 uint fillStyleCount = bs.getByte();
530 if (fillStyleCount == 0xff)
531 fillStyleCount = bs.getUInt16();
532
533 // Readout all fill styles. If a fill style with Typ != 0 is found, the parsing is aborted.
534 // Only "solid fill" (Typ 0) is supported.
535 _elements.back()._fillStyles.reserve(fillStyleCount);
536 for (uint i = 0; i < fillStyleCount; ++i) {
537 byte type = bs.getByte();
538 uint32 color;
539 byte r = bs.getByte();
540 byte g = bs.getByte();
541 byte b = bs.getByte();
542 byte a = 0xff;
543
544 if (shapeType == 3)
545 a = bs.getByte();
546
547 color = BS_ARGB(a, r, g, b);
548
549 if (type != 0)
550 return false;
551
552 _elements.back()._fillStyles.push_back(color);
553 }
554
555 // Line styles parsen
556 // -----------------
557
558 // Determine number of line styles
559 uint lineStyleCount = bs.getByte();
560 if (lineStyleCount == 0xff)
561 lineStyleCount = bs.getUInt16();
562
563 // Readout all line styles
564 _elements.back()._lineStyles.reserve(lineStyleCount);
565 for (uint i = 0; i < lineStyleCount; ++i) {
566 double width = bs.getUInt16();
567 uint32 color;
568 byte r = bs.getByte();
569 byte g = bs.getByte();
570 byte b = bs.getByte();
571 byte a = 0xff;
572
573 if (shapeType == 3)
574 a = bs.getByte();
575
576 color = BS_ARGB(a, r, g, b);
577
578 _elements.back()._lineStyles.push_back(VectorImageElement::LineStyleType(width, color));
579 }
580
581 // Readout the bit width for the following style indices
582 numFillBits = bs.getBits(4);
583 numLineBits = bs.getBits(4);
584
585 return true;
586 }
587
588
589 // -----------------------------------------------------------------------------
590
fill(const Common::Rect * pFillRect,uint color)591 bool VectorImage::fill(const Common::Rect *pFillRect, uint color) {
592 error("Fill() is not supported.");
593 return false;
594 }
595
596
597 // -----------------------------------------------------------------------------
598
getPixel(int x,int y)599 uint VectorImage::getPixel(int x, int y) {
600 error("GetPixel() is not supported. Returning black.");
601 return 0;
602 }
603
604 // -----------------------------------------------------------------------------
605
setContent(const byte * pixeldata,uint size,uint offset,uint stride)606 bool VectorImage::setContent(const byte *pixeldata, uint size, uint offset, uint stride) {
607 error("SetContent() is not supported.");
608 return 0;
609 }
610
blit(int posX,int posY,int flipping,Common::Rect * pPartRect,uint color,int width,int height,RectangleList * updateRects)611 bool VectorImage::blit(int posX, int posY,
612 int flipping,
613 Common::Rect *pPartRect,
614 uint color,
615 int width, int height,
616 RectangleList *updateRects) {
617 static VectorImage *oldThis = 0;
618 static int oldWidth = -2;
619 static int oldHeight = -2;
620
621 // If width or height to 0, nothing needs to be shown.
622 if (width == 0 || height == 0)
623 return true;
624
625 // Determine if the old image in the cache can not be reused and must be recalculated
626 if (!(oldThis == this && oldWidth == width && oldHeight == height)) {
627 render(width, height);
628
629 oldThis = this;
630 oldHeight = height;
631 oldWidth = width;
632 }
633
634 RenderedImage *rend = new RenderedImage();
635
636 rend->replaceContent(_pixelData, width, height);
637 rend->blit(posX, posY, flipping, pPartRect, color, width, height, updateRects);
638
639 delete rend;
640
641 return true;
642 }
643
644 } // End of namespace Sword25
645