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 #include "cruise/cruise_main.h"
24 #include "cruise/polys.h"
25 #include "common/endian.h"
26 #include "common/util.h"
27 
28 namespace Cruise {
29 
30 struct autoCellStruct {
31 	struct autoCellStruct *next;
32 	short int ovlIdx;
33 	short int objIdx;
34 	short int type;
35 	short int newValue;
36 	cellStruct *pCell;
37 };
38 
39 autoCellStruct autoCellHead;
40 
addAutoCell(int overlayIdx,int idx,int type,int newVal,cellStruct * pObject)41 void addAutoCell(int overlayIdx, int idx, int type, int newVal, cellStruct *pObject) {
42 	autoCellStruct *pNewEntry;
43 
44 	pNewEntry = new autoCellStruct;
45 
46 	pNewEntry->next = autoCellHead.next;
47 	autoCellHead.next = pNewEntry;
48 
49 	pNewEntry->ovlIdx = overlayIdx;
50 	pNewEntry->objIdx = idx;
51 	pNewEntry->type = type;
52 	pNewEntry->newValue = newVal;
53 	pNewEntry->pCell = pObject;
54 }
55 
freeAutoCell()56 void freeAutoCell() {
57 	autoCellStruct *pCurrent = autoCellHead.next;
58 
59 	while (pCurrent) {
60 		autoCellStruct *next = pCurrent->next;
61 
62 		if (pCurrent->type == 5) {
63 			objInit(pCurrent->ovlIdx, pCurrent->objIdx, pCurrent->newValue);
64 		} else {
65 			setObjectPosition(pCurrent->ovlIdx, pCurrent->objIdx, pCurrent->type, pCurrent->newValue);
66 		}
67 
68 		if (pCurrent->pCell->animWait < 0) {
69 			objectParamsQuery params;
70 
71 			getMultipleObjectParam(pCurrent->ovlIdx, pCurrent->objIdx, &params);
72 
73 			pCurrent->pCell->animCounter = params.state2 - 1;
74 		}
75 
76 		delete pCurrent;
77 
78 		pCurrent = next;
79 	}
80 }
81 
calcRGB(uint8 * pColorSrc,uint8 * pColorDst,int * offsetTable)82 void calcRGB(uint8* pColorSrc, uint8* pColorDst, int* offsetTable) {
83 	for (unsigned long int i = 0; i < 3; i++) {
84 		int color = *(pColorSrc++);
85 		int offset = offsetTable[i];
86 
87 		color += offset;
88 		if (color < 0)
89 			color = 0;
90 		if (color > 0xFF)
91 			color = 0xFF;
92 
93 		*(pColorDst++) = (uint8)color;
94 	}
95 }
96 
fadeIn()97 void fadeIn() {
98 	for (long int i = 256; i >= 0; i -= 32) {
99 		for (long int j = 0; j < 256; j++) {
100 			int offsetTable[3];
101 			offsetTable[0] = -i;
102 			offsetTable[1] = -i;
103 			offsetTable[2] = -i;
104 			calcRGB(&palScreen[masterScreen][3*j], &workpal[3*j], offsetTable);
105 		}
106 		gfxModuleData_setPal256(workpal);
107 
108 		gfxModuleData_updatePalette();
109 		gfxModuleData_updateScreen();
110 	}
111 
112 	for (long int j = 0; j < 256; j++) {
113 		int offsetTable[3];
114 		offsetTable[0] = 0;
115 		offsetTable[1] = 0;
116 		offsetTable[2] = 0;
117 		calcRGB(&palScreen[masterScreen][3*j], &workpal[3*j], offsetTable);
118 	}
119 
120 	gfxModuleData_setPal256(workpal);
121 
122 	fadeFlag = 0;
123 	PCFadeFlag = false;
124 }
125 
flipScreen()126 void flipScreen() {
127 	if (switchPal) {
128 		for (unsigned long int i = 0; i < 256*3; i++) {
129 			workpal[i] = palScreen[masterScreen][i];
130 		}
131 		switchPal = 0;
132 		gfxModuleData_setPal256(workpal);
133 	}
134 
135 	SWAP(gfxModuleData.pPage00, gfxModuleData.pPage10);
136 
137 	gfxModuleData_flipScreen();
138 
139 	if (doFade) {
140 		fadeIn();
141 		doFade = 0;
142 	}
143 }
144 
145 int spriteX1;
146 int spriteX2;
147 int spriteY1;
148 int spriteY2;
149 
150 char *polyOutputBuffer;
151 
pixel(int x,int y,char color)152 void pixel(int x, int y, char color) {
153 	if (x >= 0 && x < 320 && y >= 0 && y < 200)
154 		polyOutputBuffer[320 * y + x] = color;
155 }
156 
157 // this function checks if the dataPtr is not 0, else it retrives the data for X, Y, scale and DataPtr again (OLD: mainDrawSub1Sub1)
flipPoly(int fileId,int16 * dataPtr,int scale,char ** newFrame,int X,int Y,int * outX,int * outY,int * outScale)158 void flipPoly(int fileId, int16 *dataPtr, int scale, char** newFrame, int X, int Y, int *outX, int *outY, int *outScale) {
159 	if (*dataPtr == 0) {
160 		int16 offset;
161 		int16 newX;
162 		int16 newY;
163 
164 		dataPtr ++;
165 
166 		offset = (int16)READ_BE_UINT16(dataPtr);
167 		dataPtr++;
168 
169 		newX = (int16)READ_BE_UINT16(dataPtr);
170 		dataPtr++;
171 
172 		newY = (int16)READ_BE_UINT16(dataPtr);
173 		dataPtr++;
174 
175 		offset += fileId;
176 
177 		if (offset >= 0) {
178 			if (filesDatabase[offset].resType == OBJ_TYPE_LINE && filesDatabase[offset].subData.ptr) {
179 				dataPtr = (int16 *)filesDatabase[offset].subData.ptr;
180 			}
181 		}
182 
183 		scale = -scale;
184 		X -= newX;
185 		Y -= newY;
186 	}
187 
188 	*newFrame = (char *)dataPtr;
189 	*outX = X;
190 	*outY = Y;
191 	*outScale = scale;
192 }
193 
upscaleValue(int value,int scale)194 int upscaleValue(int value, int scale) {
195 	return (((value * scale) << 8) / 2);
196 }
197 
198 int m_flipLeftRight;
199 int m_useSmallScale;
200 int m_lowerX;
201 int m_lowerY;
202 int m_coordCount;
203 int m_first_X;
204 int m_first_Y;
205 int m_scaleValue;
206 int m_color;
207 
208 /*
209    FIXME: Whether intentional or not, the game often seems to use negative indexing
210    of one or more of the arrays below and expects(?) to end up in the preceding one.
211    This "worked" on many platforms so far, but on OSX apparently the buffers don't
212    occupy contiguous memory, and this causes severe corruption and subsequent crashes.
213    Since I'm not really familiar with how the strange drawing code is supposed to work,
214    or whether this behavior is intentional or not, the short-term fix is to allocate a big
215    buffer and setup pointers within it.  This fixes the crashes I'm seeing without causing any
216    (visual) side-effects.
217    If anyone wants to look, this is easily reproduced by starting the game and examining the rug.
218    drawPolyMode1() will then (indirectly) negatively index polyBuffer4.   Good luck!
219 */
220 
221 //int16 DIST_3D[512];
222 //int16 polyBuffer2[512];
223 //int16 XMIN_XMAX[404];
224 //int16 polyBuffer4[512];
225 
226 int16 bigPolyBuf[512 + 512 + 404 + 512];	/* consolidates the 4 separate buffers above */
227 
228 //set up the replacement index pointers.
229 int16 *DIST_3D = &bigPolyBuf[0];
230 int16 *polyBuffer2 = &bigPolyBuf[512];
231 int16 *XMIN_XMAX = &bigPolyBuf[512 + 512];
232 int16 *polyBuffer4 = &bigPolyBuf[512 + 512 + 404];
233 
234 
235 
236 
237 // this function fills the sizeTable for the poly (OLD: mainDrawSub1Sub2)
getPolySize(int positionX,int positionY,int scale,int sizeTable[4],unsigned char * dataPtr)238 void getPolySize(int positionX, int positionY, int scale, int sizeTable[4], unsigned char *dataPtr) {
239 	int upperBorder;
240 	int lowerBorder;
241 	m_flipLeftRight = 0;
242 
243 	if (scale < 0) {		// flip left right
244 		m_flipLeftRight = 1;
245 		scale = -scale;
246 	}
247 	// X1
248 
249 	upperBorder = *(dataPtr + 3);
250 
251 	if (m_flipLeftRight) {
252 		upperBorder = -upperBorder;
253 	}
254 
255 	upperBorder = (upscaleValue(upperBorder, scale) + 0x8000) >> 16;
256 	upperBorder = -upperBorder;
257 	lowerBorder = upperBorder;
258 
259 	// X2
260 
261 	upperBorder = *(dataPtr + 1);
262 	upperBorder -= *(dataPtr + 3);
263 
264 	if (m_flipLeftRight) {
265 		upperBorder = -upperBorder;
266 	}
267 
268 	upperBorder = (upscaleValue(upperBorder, scale) + 0x8000) >> 16;
269 
270 	if (upperBorder < lowerBorder) {	// exchange borders if lower > upper
271 		SWAP(upperBorder, lowerBorder);
272 	}
273 
274 	sizeTable[0] = lowerBorder + positionX;	// left
275 	sizeTable[1] = upperBorder + positionX;	// right
276 
277 	// Y1
278 
279 	upperBorder = *(dataPtr + 4);
280 	upperBorder = (upscaleValue(upperBorder, scale) + 0x8000) >> 16;
281 	upperBorder = -upperBorder;
282 	lowerBorder = upperBorder;
283 
284 	// Y2
285 
286 	upperBorder = *(dataPtr + 2);
287 	upperBorder -= *(dataPtr + 4);
288 	upperBorder = (upscaleValue(upperBorder, scale) + 0x8000) >> 16;
289 
290 	if (upperBorder < lowerBorder) {	// exchange borders if lower > upper
291 		SWAP(upperBorder, lowerBorder);
292 	}
293 
294 	sizeTable[2] = lowerBorder + positionY;	// bottom
295 	sizeTable[3] = upperBorder + positionY;	// top
296 }
297 
298 int nbseg;
299 int16 nbligne;
300 
blitPolyMode1(char * dest,char * pMask,int16 * buffer,char color)301 void blitPolyMode1(char *dest, char *pMask, int16 * buffer, char color) {
302 	int Y = XMIN_XMAX[0];
303 
304 	for (int i = 0; i < nbligne; i++) {
305 		int currentY = Y + i;
306 		int XMIN = XMIN_XMAX[1+i*2];
307 		int XMAX = XMIN_XMAX[1+i*2+1];
308 
309 		for (int x = XMIN; x <= XMAX; x++) {
310 			if (testMask(x, currentY, (unsigned char*)pMask, 40)) {
311 				*(dest + currentY * 320 + x) = color;
312 			}
313 		}
314 		//line(XMIN, currentY, XMAX, currentY, color);
315 	}
316 }
317 
blitPolyMode2(char * dest,int16 * buffer,char color)318 void blitPolyMode2(char *dest, int16 * buffer, char color) {
319 	int Y = XMIN_XMAX[0];
320 
321 	for (int i = 0; i < nbligne; i++) {
322 		int currentY = Y + i;
323 		int XMIN = XMIN_XMAX[1+i*2];
324 		int XMAX = XMIN_XMAX[1+i*2+1];
325 
326 		for (int x = XMIN; x <= XMAX; x++) {
327 			*(dest + currentY * 320 + x) = color;
328 		}
329 	}
330 }
331 
332 int polyXMin;
333 int polyXMax;
334 int polyYMax;
335 int polyYMin;
336 
337 int16 *A2ptr;
338 
339 
340 
buildSegment()341 void buildSegment() {
342 	int16* pOut = XMIN_XMAX;
343 
344 	if ((polyXMin >= 320) || (polyXMax < 0) || (polyYMax < 0) || (polyYMin >= 200)) {
345 		XMIN_XMAX[0] = -1;
346 		nbligne = -1;
347 		return;
348 	}
349 
350 	if (polyYMin == polyYMax) { // line
351 		*(pOut++) = polyYMin; // store initial Y
352 
353 		int cx = nbseg - 1;
354 		int16* pIn = A2ptr;
355 
356 		int XLeft;
357 		int XRight;
358 
359 		XLeft = XRight = *pIn; // init to first X
360 		pIn += 2;
361 
362 		do {
363 			int X = *pIn;
364 			if (XLeft > X)
365 				XLeft = X;
366 			if (XRight < X)
367 				XRight = X;
368 			pIn += 2;
369 		} while (--cx);
370 
371 		// now store left and right coordinates in XMIN_XMAX
372 
373 		int XMin = XLeft;
374 		int XMax = XRight;
375 
376 		if (XLeft < 0)
377 			XMin = 0;
378 
379 		if (XRight >= 320)
380 			XMax = 319;
381 
382 		*(pOut++) = XMin;
383 		*(pOut++) = XMax;
384 		*(pOut++) = -1;
385 
386 		nbligne = 1;
387 		return;
388 	}
389 
390 	// true polygon
391 
392 	int ydep;
393 
394 	if (polyYMin < 0)
395 		ydep = 0;
396 	else
397 		ydep = polyYMin;
398 
399 	int yfin;
400 
401 	if (polyYMax > 199)
402 		yfin = 199;
403 	else
404 		yfin = polyYMax;
405 
406 	nbligne = yfin - ydep + 1;
407 
408 	int16* ptrMini = XMIN_XMAX + 1;
409 	XMIN_XMAX[0] = ydep;
410 
411 	int16* ptrMax = XMIN_XMAX + ((yfin - ydep) * 2) + 1;
412 	ptrMax[2] = -1; // mark the end
413 
414 	// init table with default values
415 	int16* si = XMIN_XMAX + 1;
416 	int tempCount = nbligne;
417 	do {
418 		si[0] = 5000;
419 		si[1] = -5000;
420 		si += 2;
421 	} while (--tempCount);
422 
423 	int16* di = A2ptr;
424 	int segCount = nbseg;
425 
426 	do {
427 		int X2 = di[2];
428 		int X1 = di[0];
429 		int Y2 = di[3];
430 		int Y1 = di[1];
431 
432 
433 		int tempAX = Y1;
434 		int tempDX = Y2;
435 		if (tempAX > tempDX) {
436 			// swap
437 			tempAX = Y2;
438 			tempDX = Y1;
439 		}
440 
441 		// is segment on screen ?
442 		if (!((tempAX > 199) || (tempDX < 0))) {
443 			int cx = X2 - X1;
444 			if (cx == 0) {
445 				// vertical line
446 				int CX = X2;
447 				if (CX < 0)
448 					CX = 0;
449 
450 				int DX = X2;
451 				if (DX > 319)
452 					DX = 319;
453 
454 				int16* BX = XMIN_XMAX + (Y2 - ydep) * 2 + 1;
455 				int16* DI = XMIN_XMAX + (Y1 - ydep) * 2 + 1;
456 
457 				if (Y2 >= Y1) {
458 					SWAP(BX, DI);
459 				}
460 
461 				do {
462 					if ((BX <= ptrMax) && (BX >= ptrMini)) { // are we in screen ?
463 						if (CX < BX[0])
464 							BX[0] = CX;
465 
466 						if (DX > BX[1])
467 							BX[1] = DX;
468 					}
469 
470 					BX += 2;
471 				} while (BX <= DI);
472 			} else {
473 				if (cx < 0) {
474 					cx = -cx;
475 
476 					SWAP(X1, X2);
477 					SWAP(Y1, Y2);
478 				}
479 				// swap again ?
480 				SWAP(X1, X2);
481 
482 				int dy = Y2 - Y1;
483 				if (dy == 0) {
484 					// hline
485 					int16* ptr = (Y1 - ydep) * 2 + XMIN_XMAX + 1;
486 
487 					if ((ptr <= ptrMax) && (ptr >= ptrMini)) { // are we in screen ?
488 						int CX = X1;
489 						if (CX < 0)
490 							CX = 0;
491 
492 						int SI = X2;
493 						if (SI > 319)
494 							SI = 319;
495 
496 						if (CX < ptr[0])
497 							ptr[0] = CX;
498 
499 						if (SI > ptr[1])
500 							ptr[1] = SI;
501 					}
502 				} else {
503 					int patchAdd = 2;
504 
505 					if (dy < 0) {
506 						dy = -dy;
507 						patchAdd = -2;
508 					}
509 
510 					int stepType = 0; // small DY <= DX
511 
512 					if (dy > cx) {
513 						stepType = 1; // DX < DY
514 
515 						SWAP(dy, cx);
516 					}
517 					int patchinc1 = 2 * dy;
518 
519 					int d = 2 * dy - cx;
520 					int bx = 2 * (dy - cx);
521 
522 					int patchinc2 = bx;
523 
524 					cx++; // cx is the number of pixels to trace
525 
526 					int16* ptr = (Y1 - ydep) * 2 + XMIN_XMAX + 1;
527 
528 					if (stepType == 0) {
529 						// small step
530 						int BP = X2;
531 
532 						int SI = BP;
533 						if (SI < 0)
534 							SI = 0;
535 						int DX = BP;
536 						if (DX > 319)
537 							DX = 319;
538 
539 						do {
540 							if ((ptr <= ptrMax) && (ptr >= ptrMini)) { // are we in screen ?
541 								if (SI < ptr[0])
542 									ptr[0] = SI;
543 
544 								if (DX > ptr[1])
545 									ptr[1] = DX;
546 							}
547 
548 							BP ++;
549 
550 							// test limits
551 							SI = BP;
552 							if (SI < 0)
553 								SI = 0;
554 							DX = BP;
555 							if (DX > 319)
556 								DX = 319;
557 
558 							if (d < 0) {
559 								d += patchinc1;
560 								if (cx == 1) {   // last ?
561 									if ((ptr <= ptrMax) && (ptr >= ptrMini)) { // are we in screen ?
562 										if (SI < ptr[0])
563 											ptr[0] = SI;
564 
565 										if (DX > ptr[1])
566 											ptr[1] = DX;
567 									}
568 								}
569 							} else {
570 								d += patchinc2;
571 								ptr += patchAdd;
572 							}
573 						} while (--cx);
574 					} else {
575 						// big step
576 						int BP = X2;
577 
578 						int SI = BP;
579 						if (SI < 0)
580 							SI = 0;
581 						int DX = BP;
582 						if (DX > 319)
583 							DX = 319;
584 
585 						do {
586 							if ((ptr <= ptrMax) && (ptr >= ptrMini)) { // are we in screen ?
587 								if (SI < ptr[0])
588 									ptr[0] = SI;
589 
590 								if (DX > ptr[1])
591 									ptr[1] = DX;
592 							}
593 
594 							ptr += patchAdd; // next line
595 
596 							if (d < 0) {
597 								d += patchinc1;
598 							} else {
599 								d += patchinc2;
600 								BP ++;
601 
602 								// test limits
603 								SI = BP;
604 								if (SI < 0)
605 									SI = 0;
606 								DX = BP;
607 								if (DX > 319)
608 									DX = 319;
609 							}
610 						} while (--cx);
611 					}
612 
613 				}
614 			}
615 		}
616 
617 		di += 2;
618 	} while (--segCount);
619 }
620 
drawPolyMode1(unsigned char * dataPointer,int linesToDraw)621 unsigned char *drawPolyMode1(unsigned char *dataPointer, int linesToDraw) {
622 	int index;
623 	int16 *pBufferDest = polyBuffer4 + nbseg * 2;
624 
625 	nbseg = linesToDraw;
626 	index = *(dataPointer++);
627 
628 	polyXMin = polyXMax = pBufferDest[-2] = pBufferDest[-2 + linesToDraw * 2] = polyBuffer2[index * 2];
629 	polyYMin = polyYMax = pBufferDest[-1] = pBufferDest[-1 + linesToDraw * 2] = polyBuffer2[(index * 2) + 1];
630 
631 	linesToDraw--;
632 
633 	pBufferDest -= 2;
634 
635 	A2ptr = pBufferDest;
636 
637 	do {
638 		int value;
639 
640 		index = *(dataPointer++);
641 		value = pBufferDest[-2] = pBufferDest[-2 + nbseg * 2] = polyBuffer2[index * 2];
642 
643 		if (value < polyXMin) {
644 			polyXMin = value;
645 		}
646 		if (value > polyXMax) {
647 			polyXMax = value;
648 		}
649 
650 		value = pBufferDest[-1] = pBufferDest[-1 + nbseg * 2] = polyBuffer2[(index * 2) + 1];
651 
652 		if (value < polyYMin) {
653 			polyYMin = value;
654 		}
655 		if (value > polyYMax) {
656 			polyYMax = value;
657 			A2ptr = pBufferDest;
658 		}
659 
660 		pBufferDest -= 2;
661 
662 	} while (--linesToDraw);
663 
664 	buildSegment();
665 
666 	return dataPointer;
667 }
668 
drawPolyMode2(unsigned char * dataPointer,int linesToDraw)669 unsigned char *drawPolyMode2(unsigned char *dataPointer, int linesToDraw) {
670 	int index;
671 	int16 *pBufferDest;
672 
673 	pBufferDest = polyBuffer4;
674 	nbseg = linesToDraw;
675 	A2ptr = polyBuffer4;
676 	index = *(dataPointer++);
677 
678 	polyXMin = polyXMax = pBufferDest[0] = pBufferDest[linesToDraw * 2] = polyBuffer2[index * 2];
679 	polyYMin = polyYMax = pBufferDest[1] = pBufferDest[linesToDraw * 2 + 1] = polyBuffer2[(index * 2) + 1];
680 
681 	linesToDraw--;
682 
683 	pBufferDest += 2;
684 
685 	do {
686 		int value;
687 
688 		index = *(dataPointer++);
689 		value = pBufferDest[0] = pBufferDest[nbseg * 2] = polyBuffer2[index * 2];
690 
691 		if (value < polyXMin) {
692 			polyXMin = value;
693 		}
694 		if (value > polyXMax) {
695 			polyXMax = value;
696 		}
697 
698 		value = pBufferDest[1] = pBufferDest[nbseg * 2 + 1] = polyBuffer2[(index * 2) + 1];
699 
700 		if (value < polyYMin) {
701 			polyYMin = value;
702 		}
703 		if (value > polyYMax) {
704 			polyYMax = value;
705 			A2ptr = pBufferDest;
706 		}
707 
708 		pBufferDest += 2;
709 
710 	} while (--linesToDraw);
711 
712 	buildSegment();
713 
714 	return dataPointer;
715 }
716 
717 // this function builds the poly model and then calls the draw functions (OLD: mainDrawSub1Sub5)
buildPolyModel(int positionX,int positionY,int scale,char * pMask,char * destBuffer,char * dataPtr)718 void buildPolyModel(int positionX, int positionY, int scale, char *pMask, char *destBuffer, char *dataPtr) {
719 	int counter = 0;	// numbers of coordinates to process
720 	int startX = 0;		// first X in model
721 	int startY = 0;		// first Y in model
722 	int x = 0;		// current X
723 	int offsetXinModel = 0;	// offset of the X value in the model
724 	int offsetYinModel = 0;	// offset of the Y value in the model
725 	unsigned char *dataPointer = (unsigned char *)dataPtr;
726 	int16 *ptrPoly_1_Buf = DIST_3D;
727 	int16 *ptrPoly_2_Buf;
728 	polyOutputBuffer = destBuffer;	// global
729 
730 	m_flipLeftRight = 0;
731 	m_useSmallScale = 0;
732 	m_lowerX = *(dataPointer + 3);
733 	m_lowerY = *(dataPointer + 4);
734 
735 	if (scale < 0) {
736 		scale = -scale;	// flip left right
737 		m_flipLeftRight = 1;
738 	}
739 
740 	if (scale < 0x180) {	// If scale is smaller than 384
741 		m_useSmallScale = 1;
742 		m_scaleValue = scale << 1;	// double scale
743 	} else {
744 		m_scaleValue = scale;
745 	}
746 
747 	dataPointer += 5;
748 
749 	m_coordCount = (*(dataPointer++)) + 1;	// original uses +1 here but its later substracted again, we could skip it
750 	m_first_X = *(dataPointer);
751 	dataPointer++;
752 	m_first_Y = *(dataPointer);
753 	dataPointer++;
754 	startX = m_lowerX - m_first_X;
755 	startY = m_lowerY - m_first_Y;
756 
757 	if (m_useSmallScale) {
758 		startX >>= 1;
759 		startY >>= 1;
760 	}
761 
762 	if (m_flipLeftRight)
763 		startX = -startX;
764 
765 	/*
766 	 * NOTE:
767 	 *
768 	 * The original code continues here with using X, Y instead of startX and StartY.
769 	 *
770 	 * Original code:
771 	 * positionX -= (upscaleValue(startX, m_scaleValue) + 0x8000) >> 16;
772 	 * positionY -= (upscaleValue(startX, m_scaleValue) + 0x8000) >> 16;
773 	 */
774 
775 	// get coordinates from data
776 
777 	startX = positionX - ((upscaleValue(startX, m_scaleValue) + 0x8000) >> 16);
778 	startY = positionY - ((upscaleValue(startY, m_scaleValue) + 0x8000) >> 16);
779 
780 	ptrPoly_1_Buf[0] = 0;
781 	ptrPoly_1_Buf[1] = 0;
782 	ptrPoly_1_Buf += 2;
783 	counter = m_coordCount - 1 - 1;	// skip the first pair, we already have the values
784 
785 	// dpbcl0
786 	do {
787 		x = *(dataPointer) - m_first_X;
788 		dataPointer++;
789 		if (m_useSmallScale) {	// shrink all coordinates by factor 2 if a scale smaller than 384 is used
790 			x >>= 1;
791 		}
792 		ptrPoly_1_Buf[0] = offsetXinModel - x;
793 		ptrPoly_1_Buf++;
794 		offsetXinModel = x;
795 
796 		int y = *(dataPointer) - m_first_Y;
797 		dataPointer++;
798 		if (m_useSmallScale) {
799 			y >>= 1;
800 		}
801 		ptrPoly_1_Buf[0] = -(offsetYinModel - y);
802 		ptrPoly_1_Buf++;
803 		offsetYinModel = y;
804 
805 	} while (--counter);
806 
807 	// scale and adjust coordinates with offset (using two polybuffers by doing that)
808 	ptrPoly_2_Buf = DIST_3D;
809 	ptrPoly_1_Buf = polyBuffer2;
810 	counter = m_coordCount - 1;	// reset counter // process first pair two
811 	int m_current_X = 0;
812 	int m_current_Y = 0;
813 
814 	do {
815 		x = ptrPoly_2_Buf[0];
816 
817 		if (m_flipLeftRight == 0) {
818 			x = -x;
819 		}
820 		//////////////////
821 
822 		m_current_X += upscaleValue(x, m_scaleValue);
823 		ptrPoly_1_Buf[0] = ((m_current_X + 0x8000) >> 16) + startX;	// adjust X value with start offset
824 
825 		m_current_Y += upscaleValue(ptrPoly_2_Buf[1], m_scaleValue);
826 		ptrPoly_1_Buf[1] = ((m_current_Y + 0x8000) >> 16) + startY;	// adjust Y value with start offset
827 
828 		/////////////////
829 
830 		ptrPoly_1_Buf += 2;
831 		ptrPoly_2_Buf += 2;
832 
833 	} while (--counter);
834 
835 	// position of the dataPointer is m_coordCount * 2
836 
837 	int polygonCount = 0;
838 
839 	do {
840 		int linesToDraw = *dataPointer++;
841 
842 		if (linesToDraw > 1) {	// if value not zero
843 			uint16 minimumScale;
844 
845 			m_color = *dataPointer;	// color
846 			dataPointer += 2;
847 
848 			minimumScale = READ_BE_UINT16(dataPointer);
849 			dataPointer += 2;
850 
851 			if ((minimumScale <= scale)) {
852 				if (m_flipLeftRight) {
853 					drawPolyMode1((unsigned char *)dataPointer, linesToDraw);
854 				} else {
855 					drawPolyMode2((unsigned char *)dataPointer, linesToDraw);
856 				}
857 
858 				if (destBuffer) {
859 					if (pMask) {
860 						blitPolyMode1(destBuffer, pMask, polyBuffer4, m_color & 0xFF);
861 					} else {
862 						blitPolyMode2(destBuffer, polyBuffer4, m_color & 0xFF);
863 					}
864 				}
865 			}
866 
867 			dataPointer += linesToDraw;
868 		} else {
869 			dataPointer += 4;
870 		}
871 
872 		polygonCount ++;
873 	} while (*dataPointer != 0xFF);
874 }
875 
findPoly(char * dataPtr,int positionX,int positionY,int scale,int mouseX,int mouseY)876 bool findPoly(char* dataPtr, int positionX, int positionY, int scale, int mouseX, int mouseY) {
877 	int counter = 0;	// numbers of coordinates to process
878 	int startX = 0;		// first X in model
879 	int startY = 0;		// first Y in model
880 	int x = 0;		// current X
881 	int offsetXinModel = 0;	// offset of the X value in the model
882 	int offsetYinModel = 0;	// offset of the Y value in the model
883 	unsigned char *dataPointer = (unsigned char *)dataPtr;
884 	int16 *ptrPoly_1_Buf = DIST_3D;
885 	int16 *ptrPoly_2_Buf;
886 
887 	m_flipLeftRight = 0;
888 	m_useSmallScale = 0;
889 	m_lowerX = *(dataPointer + 3);
890 	m_lowerY = *(dataPointer + 4);
891 
892 	if (scale < 0) {
893 		scale = -scale;	// flip left right
894 		m_flipLeftRight = 1;
895 	}
896 
897 	if (scale < 0x180) {	// If scale is smaller than 384
898 		m_useSmallScale = 1;
899 		m_scaleValue = scale << 1;	// double scale
900 	} else {
901 		m_scaleValue = scale;
902 	}
903 
904 	dataPointer += 5;
905 
906 	m_coordCount = (*(dataPointer++)) + 1;	// original uses +1 here but its later substracted again, we could skip it
907 	m_first_X = *(dataPointer);
908 	dataPointer++;
909 	m_first_Y = *(dataPointer);
910 	dataPointer++;
911 	startX = m_lowerX - m_first_X;
912 	startY = m_lowerY - m_first_Y;
913 
914 	if (m_useSmallScale) {
915 		startX >>= 1;
916 		startY >>= 1;
917 	}
918 
919 	if (m_flipLeftRight) {
920 		startX = -startX;
921 	}
922 
923 	/*
924 	 * NOTE:
925 	 *
926 	 * The original code continues here with using X, Y instead of startX and StartY.
927 	 *
928 	 * Original code:
929 	 * positionX -= (upscaleValue(startX, m_scaleValue) + 0x8000) >> 16;
930 	 * positionY -= (upscaleValue(startX, m_scaleValue) + 0x8000) >> 16;
931 	 */
932 
933 	// get coordinates from data
934 
935 	startX = positionX - ((upscaleValue(startX, m_scaleValue) + 0x8000) >> 16);
936 	startY = positionY - ((upscaleValue(startY, m_scaleValue) + 0x8000) >> 16);
937 
938 	ptrPoly_1_Buf[0] = 0;
939 	ptrPoly_1_Buf[1] = 0;
940 	ptrPoly_1_Buf += 2;
941 	counter = m_coordCount - 1 - 1;	// skip the first pair, we already have the values
942 
943 	// dpbcl0
944 	do {
945 		x = *(dataPointer) - m_first_X;
946 		dataPointer++;
947 		if (m_useSmallScale) {	// shrink all coordinates by factor 2 if a scale smaller than 384 is used
948 			x >>= 1;
949 		}
950 		ptrPoly_1_Buf[0] = offsetXinModel - x;
951 		ptrPoly_1_Buf++;
952 		offsetXinModel = x;
953 
954 		int y = *(dataPointer) - m_first_Y;
955 		dataPointer++;
956 		if (m_useSmallScale)
957 			y >>= 1;
958 
959 		ptrPoly_1_Buf[0] = -(offsetYinModel - y);
960 		ptrPoly_1_Buf++;
961 		offsetYinModel = y;
962 
963 	} while (--counter);
964 
965 	// scale and adjust coordinates with offset (using two polybuffers by doing that)
966 	ptrPoly_2_Buf = DIST_3D;
967 	ptrPoly_1_Buf = polyBuffer2;
968 	counter = m_coordCount - 1;	// reset counter // process first pair two
969 	int m_current_X = 0;
970 	int m_current_Y = 0;
971 
972 	do {
973 		x = ptrPoly_2_Buf[0];
974 
975 		if (m_flipLeftRight == 0) {
976 			x = -x;
977 		}
978 		//////////////////
979 
980 		m_current_X += upscaleValue(x, m_scaleValue);
981 		ptrPoly_1_Buf[0] = ((m_current_X + 0x8000) >> 16) + startX;	// adjust X value with start offset
982 
983 		m_current_Y += upscaleValue(ptrPoly_2_Buf[1], m_scaleValue);
984 		ptrPoly_1_Buf[1] = ((m_current_Y + 0x8000) >> 16) + startY;	// adjust Y value with start offset
985 
986 		/////////////////
987 
988 		ptrPoly_1_Buf += 2;
989 		ptrPoly_2_Buf += 2;
990 
991 	} while (--counter);
992 
993 	// position of the dataPointer is m_coordCount * 2
994 
995 	int polygonCount = 0;
996 
997 	do {
998 		int linesToDraw = *dataPointer++;
999 
1000 		if (linesToDraw > 1) {	// if value not zero
1001 			uint16 minimumScale;
1002 
1003 			m_color = *dataPointer;	// color
1004 			dataPointer += 2;
1005 
1006 			minimumScale = READ_BE_UINT16(dataPointer);
1007 			dataPointer += 2;
1008 
1009 			if ((minimumScale <= scale)) {
1010 				if (m_flipLeftRight) {
1011 					drawPolyMode1((unsigned char *)dataPointer, linesToDraw);
1012 				} else {
1013 					drawPolyMode2((unsigned char *)dataPointer, linesToDraw);
1014 				}
1015 
1016 				int polygonYMin = XMIN_XMAX[0];
1017 				int polygonYMax = polygonYMin + nbligne;
1018 
1019 				if ((mouseY >= polygonYMin) && (mouseY < polygonYMax)) {
1020 					int polygonLineNumber = mouseY - polygonYMin;
1021 
1022 					int XMIN = XMIN_XMAX[1+polygonLineNumber*2];
1023 					int XMAX = XMIN_XMAX[1+polygonLineNumber*2+1];
1024 
1025 					if ((mouseX >= XMIN) && (mouseX <= XMAX))
1026 						return true;
1027 				}
1028 			}
1029 
1030 			dataPointer += linesToDraw;
1031 		} else {
1032 			dataPointer += 4;
1033 		}
1034 
1035 		polygonCount ++;
1036 	} while (*dataPointer != 0xFF);
1037 
1038 	return false;
1039 }
1040 
clearMaskBit(int x,int y,unsigned char * pData,int stride)1041 void clearMaskBit(int x, int y, unsigned char* pData, int stride) {
1042 	unsigned char* ptr = y * stride + x / 8 + pData;
1043 
1044 	unsigned char bitToTest = 0x80 >> (x & 7);
1045 
1046 	*(ptr) &= ~bitToTest;
1047 }
1048 
1049 
drawMask(unsigned char * workBuf,int wbWidth,int wbHeight,unsigned char * pMask,int maskWidth,int maskHeight,int maskX,int maskY,int passIdx)1050 void drawMask(unsigned char* workBuf, int wbWidth, int wbHeight, unsigned char* pMask, int maskWidth, int maskHeight, int maskX, int maskY, int passIdx) {
1051 	for (int y = 0; y < maskHeight; y++) {
1052 		for (int x = 0; x < maskWidth*8; x++) {
1053 			if (testMask(x, y, pMask, maskWidth)) {
1054 				int destX = maskX + x;
1055 				int destY = maskY + y;
1056 
1057 				if ((destX >= 0) && (destX < wbWidth*8) && (destY >= 0) && (destY < wbHeight))
1058 					clearMaskBit(destX, destY, workBuf, wbWidth);
1059 			}
1060 		}
1061 	}
1062 }
1063 
1064 unsigned char polygonMask[(320*200)/8];
1065 
1066 // draw poly sprite (OLD: mainDrawSub1)
mainDrawPolygons(int fileIndex,cellStruct * plWork,int X,int scale,int Y,char * destBuffer,char * dataPtr)1067 void mainDrawPolygons(int fileIndex, cellStruct *plWork, int X, int scale, int Y, char *destBuffer, char *dataPtr) {
1068 	int newX;
1069 	int newY;
1070 	int newScale;
1071 	char *newFrame;
1072 
1073 	int sizeTable[4];	// 0 = left, 1 = right, 2 = bottom, 3 = top
1074 
1075 	// this function checks if the dataPtr is not 0, else it retrives the data for X, Y, scale and DataPtr again (OLD: mainDrawSub1Sub1)
1076 	flipPoly(fileIndex, (int16 *)dataPtr, scale, &newFrame, X, Y, &newX, &newY, &newScale);
1077 
1078 	// this function fills the sizeTable for the poly (OLD: mainDrawSub1Sub2)
1079 	getPolySize(newX, newY, newScale, sizeTable, (unsigned char*)newFrame);
1080 
1081 	spriteX2 = sizeTable[0] - 2;	// left   border
1082 	spriteX1 = sizeTable[1] + 18;	// right  border
1083 	spriteY2 = sizeTable[2] - 2;	// bottom border
1084 	spriteY1 = sizeTable[3] + 2;	// top    border
1085 
1086 	if (spriteX2 >= 320)
1087 		return;
1088 	if (spriteX1 < 0)
1089 		return;
1090 	if (spriteY2 >= 200)
1091 		return;
1092 	if (spriteY1 < 0)
1093 		return;
1094 
1095 	if (spriteX2 < 0) {
1096 		spriteX2 = 0;
1097 	}
1098 	if (spriteX1 > 320) {
1099 		spriteX1 = 320;
1100 	}
1101 	if (spriteY2 < 0) {
1102 		spriteY2 = 0;
1103 	}
1104 	if (spriteY1 > 200) {
1105 		spriteY1 = 200;
1106 	}
1107 
1108 	if (spriteX1 == spriteX2)
1109 		return;
1110 	if (spriteY1 == spriteY2)
1111 		return;
1112 
1113 	gfxModuleData_addDirtyRect(Common::Rect(spriteX2, spriteY2, spriteX1, spriteY1));
1114 
1115 	memset(polygonMask, 0xFF, (320*200) / 8);
1116 
1117 	int numPasses = 0;
1118 
1119 	while (plWork) {
1120 		if (plWork->type == OBJ_TYPE_BGMASK && plWork->freeze == 0) {
1121 			objectParamsQuery params;
1122 
1123 			getMultipleObjectParam(plWork->overlay, plWork->idx, &params);
1124 
1125 			int maskX = params.X;
1126 			int maskY = params.Y;
1127 			int maskFrame = params.fileIdx;
1128 
1129 			if (filesDatabase[maskFrame].subData.resourceType == OBJ_TYPE_BGMASK && filesDatabase[maskFrame].subData.ptrMask) {
1130 				drawMask(polygonMask, 40, 200, filesDatabase[maskFrame].subData.ptrMask, filesDatabase[maskFrame].width / 8, filesDatabase[maskFrame].height, maskX, maskY, numPasses++);
1131 			} else
1132 				if (filesDatabase[maskFrame].subData.resourceType == OBJ_TYPE_SPRITE && filesDatabase[maskFrame].subData.ptrMask) {
1133 					drawMask(polygonMask, 40, 200, filesDatabase[maskFrame].subData.ptrMask, filesDatabase[maskFrame].width / 8, filesDatabase[maskFrame].height, maskX, maskY, numPasses++);
1134 				}
1135 
1136 		}
1137 
1138 		plWork = plWork->next;
1139 	}
1140 
1141 	// this function builds the poly model and then calls the draw functions (OLD: mainDrawSub1Sub5)
1142 	buildPolyModel(newX, newY, newScale, (char *)polygonMask, destBuffer, newFrame);
1143 }
1144 
drawMessage(const gfxEntryStruct * pGfxPtr,int globalX,int globalY,int width,int newColor,uint8 * ouputPtr)1145 void drawMessage(const gfxEntryStruct *pGfxPtr, int globalX, int globalY, int width, int newColor, uint8 *ouputPtr) {
1146 	// this is used for font only
1147 
1148 	if (pGfxPtr) {
1149 		const uint8 *ptr = pGfxPtr->imagePtr;
1150 		int height = pGfxPtr->height;
1151 
1152 		if (width > 310)
1153 			width = 310;
1154 		if (width + globalX > 319)
1155 			globalX = 319 - width;
1156 		if (globalY < 0)
1157 			globalY = 0;
1158 		if (globalX < 0)
1159 			globalX = 0;
1160 
1161 		if (globalY + pGfxPtr->height >= 198) {
1162 			globalY = 198 - pGfxPtr->height;
1163 		}
1164 
1165 		gfxModuleData_addDirtyRect(Common::Rect(globalX, globalY, globalX + width, globalY + height));
1166 
1167 		uint8 *initialOuput = ouputPtr + (globalY * 320) + globalX;
1168 
1169 		for (int yp = 0; yp < height; yp++) {
1170 			uint8 *output = initialOuput + 320 * yp;
1171 			int y = globalY + yp;
1172 
1173 			for (int xp = 0; xp < pGfxPtr->width; xp++) {
1174 				int x = globalX + xp;
1175 				uint8 color = *(ptr++);
1176 
1177 				if (color) {
1178 					if ((x >= 0) && (x < 320) && (y >= 0) && (y < 200)) {
1179 						if (color == 1) {
1180 							*output = (uint8) 0;
1181 						} else {
1182 							*output = (uint8) newColor;
1183 						}
1184 					}
1185 				}
1186 				output++;
1187 			}
1188 		}
1189 	}
1190 }
1191 
drawSprite(int width,int height,cellStruct * currentObjPtr,const uint8 * dataIn,int ys,int xs,uint8 * output,const uint8 * dataBuf)1192 void drawSprite(int width, int height, cellStruct *currentObjPtr, const uint8 *dataIn, int ys, int xs, uint8 *output, const uint8 *dataBuf) {
1193 	int x = 0;
1194 	int y = 0;
1195 
1196 	// Flag the given area as having been changed
1197 	Common::Point ps = Common::Point(MAX(MIN(xs, 320), 0), MAX(MIN(ys, 200), 0));
1198 	Common::Point pe = Common::Point(MAX(MIN(xs + width, 320), 0), MAX(MIN(ys + height, 200), 0));
1199 	if ((ps.x != pe.x) && (ps.y != pe.y))
1200 		// At least part of sprite is on-screen
1201 		gfxModuleData_addDirtyRect(Common::Rect(ps.x, ps.y, pe.x, pe.y));
1202 
1203 	cellStruct* plWork = currentObjPtr;
1204 	int workBufferSize = height * (width / 8);
1205 
1206 	unsigned char* workBuf = (unsigned char*)MemAlloc(workBufferSize);
1207 	memcpy(workBuf, dataBuf, workBufferSize);
1208 
1209 	int numPasses = 0;
1210 
1211 	while (plWork) {
1212 		if (plWork->type == OBJ_TYPE_BGMASK && plWork->freeze == 0) {
1213 			objectParamsQuery params;
1214 
1215 			getMultipleObjectParam(plWork->overlay, plWork->idx, &params);
1216 
1217 			int maskX = params.X;
1218 			int maskY = params.Y;
1219 			int maskFrame = params.fileIdx;
1220 
1221 			if (filesDatabase[maskFrame].subData.resourceType == OBJ_TYPE_BGMASK && filesDatabase[maskFrame].subData.ptrMask) {
1222 				drawMask(workBuf, width / 8, height, filesDatabase[maskFrame].subData.ptrMask, filesDatabase[maskFrame].width / 8, filesDatabase[maskFrame].height, maskX - xs, maskY - ys, numPasses++);
1223 			} else
1224 				if (filesDatabase[maskFrame].subData.resourceType == OBJ_TYPE_SPRITE && filesDatabase[maskFrame].subData.ptrMask) {
1225 					drawMask(workBuf, width / 8, height, filesDatabase[maskFrame].subData.ptrMask, filesDatabase[maskFrame].width / 8, filesDatabase[maskFrame].height, maskX - xs, maskY - ys, numPasses++);
1226 				}
1227 
1228 		}
1229 
1230 		plWork = plWork->next;
1231 	}
1232 
1233 	for (y = 0; y < height; y++) {
1234 		for (x = 0; x < (width); x++) {
1235 			uint8 color = *dataIn++;
1236 
1237 			if ((x + xs) >= 0 && (x + xs) < 320 && (y + ys) >= 0 && (y + ys) < 200) {
1238 				if (testMask(x, y, workBuf, width / 8)) {
1239 					output[320 * (y + ys) + x + xs] = color;
1240 				}
1241 			}
1242 		}
1243 	}
1244 
1245 	MemFree(workBuf);
1246 }
1247 
1248 #ifdef _DEBUG
drawCtp()1249 void drawCtp() {
1250 	/*	if (ctp_walkboxTable) {
1251 			for (int i = 0; i < 15; i++) {
1252 				uint16 *dataPtr = &ctp_walkboxTable[i * 40];
1253 				int type = walkboxColor[i];	// show different types in different colors
1254 
1255 				if (*dataPtr) {
1256 					fillpoly((short *)dataPtr + 1, *dataPtr, type);
1257 
1258 					for (int j = 0; j < (*dataPtr - 1); j++) {
1259 						line(dataPtr[1 + j * 2],
1260 						    dataPtr[1 + j * 2 + 1],
1261 						    dataPtr[1 + (j + 1) * 2],
1262 						    dataPtr[1 + (j + 1) * 2 + 1], 0);
1263 					}
1264 
1265 					line(dataPtr[1 + j * 2],
1266 					    dataPtr[1 + j * 2 + 1], dataPtr[1],
1267 					    dataPtr[2], 0);
1268 				}
1269 			}
1270 		}*/
1271 }
1272 #endif
1273 
drawMenu(menuStruct * pMenu)1274 void drawMenu(menuStruct *pMenu) {
1275 	if (pMenu == NULL)
1276 		return;
1277 
1278 	if (pMenu->numElements == 0)
1279 		return;
1280 
1281 	int hline = pMenu->gfx->height;
1282 	int x = pMenu->x;
1283 	int y = pMenu->y + hline;
1284 
1285 	int numItemByLine = (199 - hline * 2) / hline;
1286 	int nbcol = pMenu->numElements / numItemByLine;
1287 
1288 	if (!nbcol) {
1289 		nbcol++;
1290 
1291 		if (y + pMenu->numElements*hline > 199 - hline) {
1292 			y = 200 - (pMenu->numElements * hline) - hline;
1293 		}
1294 	} else {
1295 		if (pMenu->numElements % numItemByLine) {
1296 			nbcol++;
1297 		}
1298 
1299 		y = hline;
1300 	}
1301 
1302 	if (x > (320 - (nbcol*160)))
1303 		x = 320 - (nbcol * 160);
1304 
1305 	if (x < 0)
1306 		x = 0;
1307 
1308 	int wx = x + (nbcol - 1) * (160 / 2);
1309 
1310 	if (wx <= 320 - 160) {
1311 		drawMessage(pMenu->gfx, wx, y - hline, 160, titleColor, gfxModuleData.pPage10);
1312 	}
1313 
1314 	wx = x;
1315 	int wy = y;
1316 	int wc = 0;
1317 	menuElementStruct* p1 = pMenu->ptrNextElement;
1318 
1319 	while (p1) {
1320 		gfxEntryStruct *p2 = p1->gfx;
1321 
1322 		p1->x = wx;
1323 		p1->y = wy;
1324 		p1->varA = 160;
1325 
1326 		int color;
1327 
1328 		if (p1->selected) {
1329 			color = selectColor;
1330 		} else {
1331 			if (p1->color != 255) {
1332 				color = p1->color;
1333 			} else {
1334 				color = itemColor;
1335 			}
1336 		}
1337 
1338 		if (wx <= (320 - 160)) {
1339 			drawMessage(p2, wx, wy, 160, color, gfxModuleData.pPage10);
1340 		}
1341 
1342 		wy += hline;
1343 		wc ++;
1344 
1345 		if (wc == numItemByLine) {
1346 			wc = 0;
1347 			wx += 160;
1348 			wy = y;
1349 		}
1350 
1351 		p1 = p1->next;
1352 	}
1353 }
1354 
getValueFromObjectQuerry(objectParamsQuery * params,int idx)1355 int getValueFromObjectQuerry(objectParamsQuery *params, int idx) {
1356 	switch (idx) {
1357 	case 0:
1358 		return params->X;
1359 	case 1:
1360 		return params->Y;
1361 	case 2:
1362 		return params->baseFileIdx;
1363 	case 3:
1364 		return params->fileIdx;
1365 	case 4:
1366 		return params->scale;
1367 	case 5:
1368 		return params->state;
1369 	case 6:
1370 		return params->state2;
1371 	case 7:
1372 		return params->nbState;
1373 	default:
1374 		break;
1375 	}
1376 
1377 	assert(0);
1378 
1379 	return 0;
1380 }
1381 
mainDraw(bool waitFl)1382 void mainDraw(bool waitFl) {
1383 	uint8 *bgPtr;
1384 	cellStruct *currentObjPtr;
1385 	int16 currentObjIdx;
1386 	int16 objX1 = 0;
1387 	int16 objY1 = 0;
1388 	int16 objZ1 = 0;
1389 	int16 objX2 = 0;
1390 	int16 objY2 = 0;
1391 	int16 objZ2 = 0;
1392 	int16 spriteHeight;
1393 
1394 	/*if (PCFadeFlag) {
1395 		return;
1396 	}*/
1397 
1398 	bgPtr = backgroundScreens[masterScreen];
1399 
1400 	if (bgPtr) {
1401 		gfxModuleData_gfxCopyScreen(bgPtr, gfxModuleData.pPage10);
1402 		if (backgroundChanged[masterScreen]) {
1403 			backgroundChanged[masterScreen] = false;
1404 			switchBackground(bgPtr);
1405 		}
1406 	}
1407 
1408 	autoCellHead.next = NULL;
1409 
1410 	currentObjPtr = cellHead.next;
1411 
1412 #ifdef _DEBUG
1413 	/*	polyOutputBuffer = (char *)bgPtr;
1414 		drawCtp(); */
1415 #endif
1416 
1417 	//-------------------------------------------------- PROCESS SPRITES -----------------------------------------//
1418 
1419 	while (currentObjPtr) {
1420 		if ((masterScreen == currentObjPtr->backgroundPlane) && (currentObjPtr->freeze == 0) && (currentObjPtr->type == OBJ_TYPE_SPRITE)) {
1421 			objectParamsQuery params;
1422 
1423 			currentObjIdx = currentObjPtr->idx;
1424 
1425 			if ((currentObjPtr->followObjectOverlayIdx != currentObjPtr->overlay) || (currentObjPtr->followObjectIdx != currentObjPtr->idx)) {
1426 				// Declaring this twice ?
1427 				// objectParamsQuery params;
1428 
1429 				getMultipleObjectParam(currentObjPtr->followObjectOverlayIdx, currentObjPtr->followObjectIdx, &params);
1430 
1431 				objX1 = params.X;
1432 				objY1 = params.Y;
1433 				objZ1 = params.fileIdx;
1434 			} else {
1435 				objX1 = 0;
1436 				objY1 = 0;
1437 				objZ1 = 0;
1438 			}
1439 
1440 			getMultipleObjectParam(currentObjPtr->overlay, currentObjIdx, &params);
1441 
1442 			objX2 = objX1 + params.X;
1443 			objY2 = objY1 + params.Y;
1444 			objZ2 = params.fileIdx;
1445 
1446 			if (objZ2 >= 0) {
1447 				objZ2 += objZ1;
1448 			}
1449 
1450 			if ((params.state >= 0) && (objZ2 >= 0) && filesDatabase[objZ2].subData.ptr) {
1451 				if (filesDatabase[objZ2].subData.resourceType == 8) {	// Poly
1452 					mainDrawPolygons(objZ2, currentObjPtr, objX2, params.scale, objY2, (char *)gfxModuleData.pPage10, (char *)filesDatabase[objZ2].subData.ptr);	// poly
1453 				} else if (filesDatabase[objZ2].subData.resourceType == OBJ_TYPE_SOUND) {
1454 				} else if (filesDatabase[objZ2].resType == OBJ_TYPE_MASK) {
1455 				} else if (filesDatabase[objZ2].subData.resourceType == OBJ_TYPE_SPRITE) {
1456 					objX1 = filesDatabase[objZ2].width;	// width
1457 					spriteHeight = filesDatabase[objZ2].height;	// height
1458 
1459 					if (filesDatabase[objZ2].subData.ptr) {
1460 						drawSprite(objX1, spriteHeight, currentObjPtr, filesDatabase[objZ2].subData.ptr, objY2, objX2, gfxModuleData.pPage10, filesDatabase[objZ2].subData.ptrMask);
1461 					}
1462 				}
1463 			}
1464 
1465 			// automatic animation process
1466 			if (currentObjPtr->animStep && !waitFl) {
1467 				if (currentObjPtr->animCounter <= 0) {
1468 
1469 					bool change = true;
1470 
1471 					int newVal = getValueFromObjectQuerry(&params, currentObjPtr->animChange) + currentObjPtr->animStep;
1472 
1473 					if (currentObjPtr->animStep > 0) {
1474 						if (newVal > currentObjPtr->animEnd) {
1475 							if (currentObjPtr->animLoop) {
1476 								newVal = currentObjPtr->animStart;
1477 								if (currentObjPtr->animLoop > 0)
1478 									currentObjPtr->animLoop--;
1479 							} else {
1480 								change = false;
1481 								currentObjPtr->animStep = 0;
1482 
1483 								if (currentObjPtr->animType) {	// should we resume the script ?
1484 									if (currentObjPtr->parentType == 20) {
1485 										changeScriptParamInList(currentObjPtr->parentOverlay, currentObjPtr->parent, &procHead, -1, 0);
1486 									} else if (currentObjPtr->parentType == 30) {
1487 										changeScriptParamInList(currentObjPtr->parentOverlay, currentObjPtr->parent, &relHead, -1, 0);
1488 									}
1489 								}
1490 							}
1491 						}
1492 					} else {
1493 						if (newVal < currentObjPtr->animEnd) {
1494 							if (currentObjPtr->animLoop) {
1495 								newVal = currentObjPtr->animStart;
1496 								if (currentObjPtr->animLoop > 0)
1497 									currentObjPtr->animLoop--;
1498 							} else {
1499 								change = false;
1500 								currentObjPtr->animStep = 0;
1501 
1502 								if (currentObjPtr->animType) {	// should we resume the script ?
1503 									if (currentObjPtr->parentType == 20) {
1504 										changeScriptParamInList(currentObjPtr->parentOverlay, currentObjPtr->parent, &procHead, -1, 0);
1505 									} else if (currentObjPtr->parentType == 30) {
1506 										changeScriptParamInList(currentObjPtr->parentOverlay, currentObjPtr->parent, &relHead, -1, 0);
1507 									}
1508 								}
1509 							}
1510 						}
1511 					}
1512 
1513 					if (currentObjPtr->animWait >= 0) {
1514 						currentObjPtr->animCounter = currentObjPtr->animWait;
1515 					}
1516 
1517 					if ((currentObjPtr->animSignal >= 0) && (currentObjPtr->animSignal == newVal) && (currentObjPtr->animType != 0)) {
1518 						if (currentObjPtr->parentType == 20) {
1519 							changeScriptParamInList(currentObjPtr->parentOverlay, currentObjPtr->parent, &procHead, -1, 0);
1520 						} else if (currentObjPtr->parentType == 30) {
1521 							changeScriptParamInList(currentObjPtr->parentOverlay, currentObjPtr->parent, &relHead, -1, 0);
1522 						}
1523 
1524 						currentObjPtr->animType = 0;
1525 					}
1526 
1527 					if (change) {
1528 						addAutoCell(currentObjPtr->overlay, currentObjPtr->idx, currentObjPtr->animChange, newVal, currentObjPtr);
1529 					}
1530 				} else {
1531 					currentObjPtr->animCounter--;
1532 				}
1533 			}
1534 		}
1535 
1536 		currentObjPtr = currentObjPtr->next;
1537 	}
1538 
1539 	//----------------------------------------------------------------------------------------------------------------//
1540 
1541 	freeAutoCell();
1542 	isMessage = 0;
1543 
1544 	//-------------------------------------------------- DRAW OBJECTS TYPE 5 (MSG)-----------------------------------------//
1545 
1546 	currentObjPtr = cellHead.next;
1547 
1548 	while (currentObjPtr) {
1549 		if (currentObjPtr->type == OBJ_TYPE_MESSAGE && currentObjPtr->freeze == 0) {
1550 			drawMessage(currentObjPtr->gfxPtr, currentObjPtr->x, currentObjPtr->field_C, currentObjPtr->spriteIdx, currentObjPtr->color, gfxModuleData.pPage10);
1551 			isMessage = 1;
1552 		}
1553 		currentObjPtr = currentObjPtr->next;
1554 	}
1555 
1556 	//----------------------------------------------------------------------------------------------------------------//
1557 
1558 	if (currentActiveMenu != -1) {
1559 		if (menuTable[currentActiveMenu]) {
1560 			drawMenu(menuTable[currentActiveMenu]);
1561 			return;
1562 		}
1563 	} else if ((linkedRelation) && (linkedMsgList)) {
1564 		int16 mouseX;
1565 		int16 mouseY;
1566 		int16 button;
1567 		getMouseStatus(&main10, &mouseX, &button, &mouseY);
1568 
1569 		if (mouseY > (linkedMsgList->height)*2)
1570 			drawMessage(linkedMsgList, 0, 0, 320, findHighColor(), gfxModuleData.pPage10);
1571 		else
1572 			drawMessage(linkedMsgList, 0, 200, 320, findHighColor(), gfxModuleData.pPage10);
1573 	}
1574 }
1575 
1576 } // End of namespace Cruise
1577