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 * This file contains utilities to handle multi-part objects.
22 */
23
24 #include "tinsel/multiobj.h"
25 #include "tinsel/handle.h"
26 #include "tinsel/object.h"
27 #include "tinsel/tinsel.h"
28
29 namespace Tinsel {
30
31 /**
32 * Initialize a multi-part object using a list of images to init
33 * each object piece. One object is created for each image in the list.
34 * All objects are given the same palette as the first image. A pointer
35 * to the first (master) object created is returned.
36 * @param pInitTbl Pointer to multi-object initialisation table
37 */
MultiInitObject(const MULTI_INIT * pInitTbl)38 OBJECT *MultiInitObject(const MULTI_INIT *pInitTbl) {
39 OBJ_INIT obj_init; // object init table
40 OBJECT *pFirst, *pObj; // object pointers
41 FRAME *pFrame; // list of images for the multi-part object
42
43 if (FROM_32(pInitTbl->hMulFrame)) {
44 // we have a frame handle
45 pFrame = (FRAME *)LockMem(FROM_32(pInitTbl->hMulFrame));
46
47 obj_init.hObjImg = READ_32(pFrame); // first objects shape
48 } else { // this must be a animation list for a NULL object
49 pFrame = NULL;
50 obj_init.hObjImg = 0; // first objects shape
51 }
52
53 // init the object init table
54 obj_init.objFlags = (int)FROM_32(pInitTbl->mulFlags); // all objects have same flags
55 obj_init.objID = (int)FROM_32(pInitTbl->mulID); // all objects have same ID
56 obj_init.objX = (int)FROM_32(pInitTbl->mulX); // all objects have same X ani pos
57 obj_init.objY = (int)FROM_32(pInitTbl->mulY); // all objects have same Y ani pos
58 obj_init.objZ = (int)FROM_32(pInitTbl->mulZ); // all objects have same Z pos
59
60 // create and init the first object
61 pObj = pFirst = InitObject(&obj_init);
62
63 if (pFrame) {
64 // if we have any animation frames
65
66 pFrame++;
67
68 while (READ_32(pFrame) != 0) {
69 // set next objects shape
70 obj_init.hObjImg = READ_32(pFrame);
71
72 // create next object and link to previous
73 pObj = pObj->pSlave = InitObject(&obj_init);
74
75 pFrame++;
76 }
77 }
78
79 // null end of list for final object
80 pObj->pSlave = NULL;
81
82 // return master object
83 return pFirst;
84 }
85
86 /**
87 * Inserts the multi-part object onto the specified object list.
88 * @param pObjList List to insert multi-part object onto
89 * @param pInsObj Head of multi-part object to insert
90
91 */
92
MultiInsertObject(OBJECT ** pObjList,OBJECT * pInsObj)93 void MultiInsertObject(OBJECT **pObjList, OBJECT *pInsObj) {
94 // validate object pointer
95 assert(isValidObject(pInsObj));
96
97 // for all the objects that make up this multi-part
98 do {
99 // add next part to the specified list
100 InsertObject(pObjList, pInsObj);
101
102 // next obj in list
103 pInsObj = pInsObj->pSlave;
104 } while (pInsObj != NULL);
105 }
106
107 /**
108 * Deletes all the pieces of a multi-part object from the
109 * specified object list.
110 * @param pObjList List to delete multi-part object from
111 * @param pMultiObj Multi-part object to be deleted
112 */
113
MultiDeleteObject(OBJECT ** pObjList,OBJECT * pMultiObj)114 void MultiDeleteObject(OBJECT **pObjList, OBJECT *pMultiObj) {
115 // validate object pointer
116 assert(isValidObject(pMultiObj));
117
118 // for all the objects that make up this multi-part
119 do {
120 // delete object
121 DelObject(pObjList, pMultiObj);
122
123 // next obj in list
124 pMultiObj = pMultiObj->pSlave;
125 } while (pMultiObj != NULL);
126 }
127
128 /**
129 * Hides a multi-part object by giving each object a "NullImage"
130 * image pointer.
131 * @param pMultiObj Multi-part object to be hidden
132 */
133
MultiHideObject(OBJECT * pMultiObj)134 void MultiHideObject(OBJECT *pMultiObj) {
135 // validate object pointer
136 assert(isValidObject(pMultiObj));
137
138 // set master shape to null animation frame
139 pMultiObj->hShape = 0;
140
141 // change all objects
142 MultiReshape(pMultiObj);
143 }
144
145 /**
146 * Horizontally flip a multi-part object.
147 * @param pFlipObj Head of multi-part object to flip
148 */
149
MultiHorizontalFlip(OBJECT * pFlipObj)150 void MultiHorizontalFlip(OBJECT *pFlipObj) {
151 // validate object pointer
152 assert(isValidObject(pFlipObj));
153
154 // for all the objects that make up this multi-part
155 do {
156 // horizontally flip the next part
157 AnimateObjectFlags(pFlipObj, pFlipObj->flags ^ DMA_FLIPH,
158 pFlipObj->hImg);
159
160 // next obj in list
161 pFlipObj = pFlipObj->pSlave;
162 } while (pFlipObj != NULL);
163 }
164
165 /**
166 * Vertically flip a multi-part object.
167 * @param pFlipObj Head of multi-part object to flip
168 */
169
MultiVerticalFlip(OBJECT * pFlipObj)170 void MultiVerticalFlip(OBJECT *pFlipObj) {
171 // validate object pointer
172 assert(isValidObject(pFlipObj));
173
174 // for all the objects that make up this multi-part
175 do {
176 // vertically flip the next part
177 AnimateObjectFlags(pFlipObj, pFlipObj->flags ^ DMA_FLIPV,
178 pFlipObj->hImg);
179
180 // next obj in list
181 pFlipObj = pFlipObj->pSlave;
182 } while (pFlipObj != NULL);
183 }
184
185 /**
186 * Adjusts the coordinates of a multi-part object. The adjustments
187 * take into account the orientation of the object.
188 * @param pMultiObj Multi-part object to be adjusted
189 * @param deltaX X adjustment
190 * @param deltaY Y adjustment
191 */
192
MultiAdjustXY(OBJECT * pMultiObj,int deltaX,int deltaY)193 void MultiAdjustXY(OBJECT *pMultiObj, int deltaX, int deltaY) {
194 // validate object pointer
195 assert(isValidObject(pMultiObj));
196
197 if (deltaX == 0 && deltaY == 0)
198 return; // ignore no change
199
200 if (!TinselV2) {
201 // *** This may be wrong!!!
202 if (pMultiObj->flags & DMA_FLIPH) {
203 // image is flipped horizontally - flip the x direction
204 deltaX = -deltaX;
205 }
206
207 if (pMultiObj->flags & DMA_FLIPV) {
208 // image is flipped vertically - flip the y direction
209 deltaY = -deltaY;
210 }
211 }
212
213 // for all the objects that make up this multi-part
214 do {
215 // signal a change in the object
216 pMultiObj->flags |= DMA_CHANGED;
217
218 // adjust the x position
219 pMultiObj->xPos += intToFrac(deltaX);
220
221 // adjust the y position
222 pMultiObj->yPos += intToFrac(deltaY);
223
224 // next obj in list
225 pMultiObj = pMultiObj->pSlave;
226
227 } while (pMultiObj != NULL);
228 }
229
230 /**
231 * Moves all the pieces of a multi-part object by the specified
232 * amount. Does not take into account the objects orientation.
233 * @param pMultiObj Multi-part object to be adjusted
234 * @param deltaX X movement
235 * @param deltaY Y movement
236 */
237
MultiMoveRelXY(OBJECT * pMultiObj,int deltaX,int deltaY)238 void MultiMoveRelXY(OBJECT *pMultiObj, int deltaX, int deltaY) {
239 // validate object pointer
240 assert(isValidObject(pMultiObj));
241
242 if (deltaX == 0 && deltaY == 0)
243 return; // ignore no change
244
245 // for all the objects that make up this multi-part
246 do {
247 // signal a change in the object
248 pMultiObj->flags |= DMA_CHANGED;
249
250 // adjust the x position
251 pMultiObj->xPos += intToFrac(deltaX);
252
253 // adjust the y position
254 pMultiObj->yPos += intToFrac(deltaY);
255
256 // next obj in list
257 pMultiObj = pMultiObj->pSlave;
258
259 } while (pMultiObj != NULL);
260 }
261
262 /**
263 * Sets the x & y anim position of all pieces of a multi-part object.
264 * @param pMultiObj Multi-part object whose position is to be changed
265 * @param newAniX New x animation position
266 * @param newAniY New y animation position
267 */
268
MultiSetAniXY(OBJECT * pMultiObj,int newAniX,int newAniY)269 void MultiSetAniXY(OBJECT *pMultiObj, int newAniX, int newAniY) {
270 int curAniX, curAniY; // objects current animation position
271
272 // validate object pointer
273 assert(isValidObject(pMultiObj));
274
275 // get master objects current animation position
276 GetAniPosition(pMultiObj, &curAniX, &curAniY);
277
278 // calc difference between current and new positions
279 newAniX -= curAniX;
280 newAniY -= curAniY;
281
282 // move all pieces by the difference
283 MultiMoveRelXY(pMultiObj, newAniX, newAniY);
284 }
285
286 /**
287 * Sets the x anim position of all pieces of a multi-part object.
288 * @param pMultiObj Multi-part object whose x position is to be changed
289 * @param newAniX New x animation position
290 */
291
MultiSetAniX(OBJECT * pMultiObj,int newAniX)292 void MultiSetAniX(OBJECT *pMultiObj, int newAniX) {
293 int curAniX, curAniY; // objects current animation position
294
295 // validate object pointer
296 assert(isValidObject(pMultiObj));
297
298 // get master objects current animation position
299 GetAniPosition(pMultiObj, &curAniX, &curAniY);
300
301 // calc x difference between current and new positions
302 newAniX -= curAniX;
303 curAniY = 0;
304
305 // move all pieces by the difference
306 MultiMoveRelXY(pMultiObj, newAniX, curAniY);
307 }
308
309 /**
310 * Sets the y anim position of all pieces of a multi-part object.
311 * @param pMultiObj Multi-part object whose x position is to be changed
312 * @param newAniX New y animation position
313 */
314
MultiSetAniY(OBJECT * pMultiObj,int newAniY)315 void MultiSetAniY(OBJECT *pMultiObj, int newAniY) {
316 int curAniX, curAniY; // objects current animation position
317
318 // validate object pointer
319 assert(isValidObject(pMultiObj));
320
321 // get master objects current animation position
322 GetAniPosition(pMultiObj, &curAniX, &curAniY);
323
324 // calc y difference between current and new positions
325 curAniX = 0;
326 newAniY -= curAniY;
327
328 // move all pieces by the difference
329 MultiMoveRelXY(pMultiObj, curAniX, newAniY);
330 }
331
332 /**
333 * Sets the Z position of all pieces of a multi-part object.
334 * @param pMultiObj Multi-part object to be adjusted
335 * @param newZ New Z order
336 */
337
MultiSetZPosition(OBJECT * pMultiObj,int newZ)338 void MultiSetZPosition(OBJECT *pMultiObj, int newZ) {
339 // validate object pointer
340 assert(isValidObject(pMultiObj));
341
342 // for all the objects that make up this multi-part
343 do {
344 // signal a change in the object
345 pMultiObj->flags |= DMA_CHANGED;
346
347 // set the new z position
348 pMultiObj->zPos = newZ;
349
350 // next obj in list
351 pMultiObj = pMultiObj->pSlave;
352 } while (pMultiObj != NULL);
353 }
354
355 /**
356 * Reshape a multi-part object.
357 * @param pMultiObj Multi-part object to re-shape
358 */
359
MultiReshape(OBJECT * pMultiObj)360 void MultiReshape(OBJECT *pMultiObj) {
361 SCNHANDLE hFrame;
362
363 // validate object pointer
364 assert(isValidObject(pMultiObj));
365
366 // get objects current anim frame
367 hFrame = pMultiObj->hShape;
368
369 if (hFrame != 0 && hFrame != pMultiObj->hMirror) {
370 // a valid shape frame which is different from previous
371
372 // get pointer to frame
373 const FRAME *pFrame = (const FRAME *)LockMem(hFrame);
374
375 // update previous
376 pMultiObj->hMirror = hFrame;
377
378 while (READ_32(pFrame) != 0 && pMultiObj != NULL) {
379 // a normal image - update the current object with this image
380 AnimateObject(pMultiObj, READ_32(pFrame));
381
382 // move to next image for this frame
383 pFrame++;
384
385 // move to next part of object
386 pMultiObj = pMultiObj->pSlave;
387 }
388
389 // null the remaining object parts
390 while (pMultiObj != NULL) {
391 // set a null image for this object part
392 AnimateObject(pMultiObj, 0);
393
394 // move to next part of object
395 pMultiObj = pMultiObj->pSlave;
396 }
397 } else if (hFrame == 0) {
398 // update previous
399 pMultiObj->hMirror = hFrame;
400
401 // null all the object parts
402 while (pMultiObj != NULL) {
403 // set a null image for this object part
404 AnimateObject(pMultiObj, 0);
405
406 // move to next part of object
407 pMultiObj = pMultiObj->pSlave;
408 }
409 }
410 }
411
412 /**
413 * Returns the left-most point of a multi-part object.
414 * @param pMulti Multi-part object
415 */
416
MultiLeftmost(OBJECT * pMulti)417 int MultiLeftmost(OBJECT *pMulti) {
418 int left;
419
420 // validate object pointer
421 assert(isValidObject(pMulti));
422
423 // init leftmost point to first object
424 left = fracToInt(pMulti->xPos);
425
426 // for all the objects in this multi
427 while ((pMulti = pMulti->pSlave) != NULL) {
428 if (pMulti->hImg != 0) {
429 // non null object part
430
431 if (fracToInt(pMulti->xPos) < left)
432 // this object is further left
433 left = fracToInt(pMulti->xPos);
434 }
435 }
436
437 // return left-most point
438 return left;
439 }
440
441 /**
442 * Returns the right-most point of a multi-part object.
443 * @param pMulti Multi-part object
444 */
445
MultiRightmost(OBJECT * pMulti)446 int MultiRightmost(OBJECT *pMulti) {
447 int right;
448
449 // validate object pointer
450 assert(isValidObject(pMulti));
451
452 // init right-most point to first object
453 right = fracToInt(pMulti->xPos) + pMulti->width;
454
455 // for all the objects in this multi
456 while ((pMulti = pMulti->pSlave) != NULL) {
457 if (pMulti->hImg != 0) {
458 // non null object part
459
460 if (fracToInt(pMulti->xPos) + pMulti->width > right)
461 // this object is further right
462 right = fracToInt(pMulti->xPos) + pMulti->width;
463 }
464 }
465
466 // return right-most point
467 return right - 1;
468 }
469
470 /**
471 * Returns the highest point of a multi-part object.
472 * @param pMulti Multi-part object
473 */
474
MultiHighest(OBJECT * pMulti)475 int MultiHighest(OBJECT *pMulti) {
476 int highest;
477
478 // validate object pointer
479 assert(isValidObject(pMulti));
480
481 // init highest point to first object
482 highest = fracToInt(pMulti->yPos);
483
484 // for all the objects in this multi
485 while ((pMulti = pMulti->pSlave) != NULL) {
486 if (pMulti->hImg != 0) {
487 // non null object part
488
489 if (fracToInt(pMulti->yPos) < highest)
490 // this object is higher
491 highest = fracToInt(pMulti->yPos);
492 }
493 }
494
495 // return highest point
496 return highest;
497 }
498
499 /**
500 * Returns the lowest point of a multi-part object.
501 * @param pMulti Multi-part object
502 */
503
MultiLowest(OBJECT * pMulti)504 int MultiLowest(OBJECT *pMulti) {
505 int lowest;
506
507 // validate object pointer
508 assert(isValidObject(pMulti));
509
510 // init lowest point to first object
511 lowest = fracToInt(pMulti->yPos) + pMulti->height;
512
513 // for all the objects in this multi
514 while ((pMulti = pMulti->pSlave) != NULL) {
515 if (pMulti->hImg != 0) {
516 // non null object part
517
518 if (fracToInt(pMulti->yPos) + pMulti->height > lowest)
519 // this object is lower
520 lowest = fracToInt(pMulti->yPos) + pMulti->height;
521 }
522 }
523
524 // return lowest point
525 return lowest - 1;
526 }
527
528 /**
529 * Returns TRUE if the object currently has an image.
530 * @param pMulti Multi-part object
531 */
532
MultiHasShape(POBJECT pMulti)533 bool MultiHasShape(POBJECT pMulti) {
534 return (pMulti->hShape != 0);
535 }
536
537 /**
538 * Bodge for text on movies. Makes sure it appears for it's lifetime.
539 * @param pMultiObj Multi-part object to be adjusted
540 */
541
MultiForceRedraw(POBJECT pMultiObj)542 void MultiForceRedraw(POBJECT pMultiObj) {
543 // validate object pointer
544 assert(isValidObject(pMultiObj));
545
546 // for all the objects that make up this multi-part
547 do {
548 // signal a change in the object
549 pMultiObj->flags |= DMA_CHANGED;
550
551 // next obj in list
552 pMultiObj = pMultiObj->pSlave;
553 } while (pMultiObj != NULL);
554 }
555
556 } // End of namespace Tinsel
557