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