PageRenderTime 100ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/engines/tinsel/object.cpp

http://github.com/scummvm/scummvm
C++ | 541 lines | 223 code | 118 blank | 200 comment | 43 complexity | 22f33403c4736b454d2707a951993217 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, GPL-2.0
  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 the Object Manager code.
  22. */
  23. #include "tinsel/object.h"
  24. #include "tinsel/background.h"
  25. #include "tinsel/cliprect.h" // object clip rect defs
  26. #include "tinsel/graphics.h" // low level interface
  27. #include "tinsel/handle.h"
  28. #include "tinsel/text.h"
  29. #include "tinsel/tinsel.h"
  30. #include "common/textconsole.h"
  31. #define OID_EFFECTS 0x2000 // generic special effects object id
  32. namespace Tinsel {
  33. // FIXME: Avoid non-const global vars
  34. // list of all objects
  35. static OBJECT *objectList = 0;
  36. // pointer to free object list
  37. static OBJECT *pFreeObjects = 0;
  38. #ifdef DEBUG
  39. // diagnostic object counters
  40. static int numObj = 0;
  41. static int maxObj = 0;
  42. #endif
  43. void FreeObjectList() {
  44. free(objectList);
  45. objectList= nullptr;
  46. }
  47. /**
  48. * Kills all objects and places them on the free list.
  49. */
  50. void KillAllObjects() {
  51. int i;
  52. #ifdef DEBUG
  53. // clear number of objects in use
  54. numObj = 0;
  55. #endif
  56. if (objectList == NULL) {
  57. // first time - allocate memory for object list
  58. objectList = (OBJECT *)calloc(NUM_OBJECTS, sizeof(OBJECT));
  59. // make sure memory allocated
  60. if (objectList == NULL) {
  61. error("Cannot allocate memory for object data");
  62. }
  63. }
  64. // place first object on free list
  65. pFreeObjects = objectList;
  66. // link all other objects after first
  67. for (i = 1; i < NUM_OBJECTS; i++) {
  68. objectList[i - 1].pNext = objectList + i;
  69. }
  70. // null the last object
  71. objectList[NUM_OBJECTS - 1].pNext= nullptr;
  72. }
  73. #ifdef DEBUG
  74. /**
  75. * Shows the maximum number of objects used at once.
  76. */
  77. void ObjectStats() {
  78. debug("%i objects of %i used", maxObj, NUM_OBJECTS);
  79. }
  80. #endif
  81. /**
  82. * Allocate a object from the free list.
  83. */
  84. OBJECT *AllocObject() {
  85. OBJECT *pObj = pFreeObjects; // get a free object
  86. // check for no free objects
  87. assert(pObj != NULL);
  88. // a free object exists
  89. // get link to next free object
  90. pFreeObjects = pObj->pNext;
  91. // clear out object
  92. pObj->reset();
  93. // set default drawing mode and set changed bit
  94. pObj->flags = DMA_WNZ | DMA_CHANGED;
  95. #ifdef DEBUG
  96. // one more object in use
  97. if (++numObj > maxObj)
  98. maxObj = numObj;
  99. #endif
  100. // return new object
  101. return pObj;
  102. }
  103. bool isValidObject(OBJECT *obj) {
  104. return (obj >= objectList && obj <= objectList + NUM_OBJECTS - 1);
  105. }
  106. /**
  107. * Copy one object to another.
  108. * @param pDest Destination object
  109. * @param pSrc Source object
  110. */
  111. void CopyObject(OBJECT *pDest, OBJECT *pSrc) {
  112. // save previous dimensions etc.
  113. Common::Rect rcSave = pDest->rcPrev;
  114. // make a copy
  115. memcpy(pDest, pSrc, sizeof(OBJECT));
  116. // restore previous dimensions etc.
  117. pDest->rcPrev = rcSave;
  118. // set changed flag in destination
  119. pDest->flags |= DMA_CHANGED;
  120. // null the links
  121. pDest->pNext = pDest->pSlave= nullptr;
  122. }
  123. /**
  124. * Inserts an object onto the specified object list. The object
  125. * lists are sorted in Z Y order.
  126. * @param pObjList List to insert object onto
  127. * @param pInsObj Object to insert
  128. */
  129. void InsertObject(OBJECT **pObjList, OBJECT *pInsObj) {
  130. OBJECT **pAnchor, *pObj; // object list traversal pointers
  131. // validate object pointer
  132. assert(isValidObject(pInsObj));
  133. for (pAnchor = pObjList, pObj = *pAnchor; pObj != NULL; pAnchor = &pObj->pNext, pObj = *pAnchor) {
  134. // check Z order
  135. if (pInsObj->zPos < pObj->zPos) {
  136. // object Z is lower than list Z - insert here
  137. break;
  138. } else if (pInsObj->zPos == pObj->zPos) {
  139. // Z values are the same - sort on Y
  140. if (fracToDouble(pInsObj->yPos) <= fracToDouble(pObj->yPos)) {
  141. // object Y is lower than or same as list Y - insert here
  142. break;
  143. }
  144. }
  145. }
  146. // insert obj between pAnchor and pObj
  147. pInsObj->pNext = pObj;
  148. *pAnchor = pInsObj;
  149. }
  150. /**
  151. * Deletes an object from the specified object list and places it
  152. * on the free list.
  153. * @param pObjList List to delete object from
  154. * @param pDelObj Object to delete
  155. */
  156. void DelObject(OBJECT **pObjList, OBJECT *pDelObj) {
  157. OBJECT **pAnchor, *pObj; // object list traversal pointers
  158. const Common::Rect rcScreen(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
  159. // validate object pointer
  160. assert(isValidObject(pDelObj));
  161. #ifdef DEBUG
  162. // one less object in use
  163. --numObj;
  164. assert(numObj >= 0);
  165. #endif
  166. for (pAnchor = pObjList, pObj = *pAnchor; pObj != NULL; pAnchor = &pObj->pNext, pObj = *pAnchor) {
  167. if (pObj == pDelObj) {
  168. // found object to delete
  169. if (IntersectRectangle(pDelObj->rcPrev, pDelObj->rcPrev, rcScreen)) {
  170. // allocate a clipping rect for objects previous pos
  171. AddClipRect(pDelObj->rcPrev);
  172. }
  173. // make PREV next = OBJ next - removes OBJ from list
  174. *pAnchor = pObj->pNext;
  175. // place free list in OBJ next
  176. pObj->pNext = pFreeObjects;
  177. // add OBJ to top of free list
  178. pFreeObjects = pObj;
  179. // delete objects palette
  180. if (pObj->pPal)
  181. FreePalette(pObj->pPal);
  182. // quit
  183. return;
  184. }
  185. }
  186. // if we get to here - object has not been found on the list
  187. // This can be triggered in Act 3 in DW1 while talking to the guard,
  188. // so this has been turned to a warning instead of an error
  189. warning("DelObject(): formally 'assert(0)!'");
  190. }
  191. /**
  192. * Sort the specified object list in Z Y order.
  193. * @param pObjList List to sort
  194. */
  195. void SortObjectList(OBJECT **pObjList) {
  196. OBJECT *pPrev, *pObj; // object list traversal pointers
  197. OBJECT head; // temporary head of list - because pObjList is not usually a OBJECT
  198. // put at head of list
  199. head.pNext = *pObjList;
  200. // set head of list dummy OBJ Z Y values to lowest possible
  201. head.yPos = intToFrac(MIN_INT16);
  202. head.zPos = MIN_INT;
  203. for (pPrev = &head, pObj = head.pNext; pObj != NULL; pPrev = pObj, pObj = pObj->pNext) {
  204. // check Z order
  205. if (pObj->zPos < pPrev->zPos) {
  206. // object Z is lower than previous Z
  207. // remove object from list
  208. pPrev->pNext = pObj->pNext;
  209. // re-insert object on list
  210. InsertObject(pObjList, pObj);
  211. // back to beginning of list
  212. pPrev = &head;
  213. pObj = head.pNext;
  214. } else if (pObj->zPos == pPrev->zPos) {
  215. // Z values are the same - sort on Y
  216. if (fracToDouble(pObj->yPos) < fracToDouble(pPrev->yPos)) {
  217. // object Y is lower than previous Y
  218. // remove object from list
  219. pPrev->pNext = pObj->pNext;
  220. // re-insert object on list
  221. InsertObject(pObjList, pObj);
  222. // back to beginning of list
  223. pPrev = &head;
  224. pObj = head.pNext;
  225. }
  226. }
  227. }
  228. }
  229. /**
  230. * Returns the animation offsets of a image, dependent on the
  231. * images orientation flags.
  232. * @param hImg Iimage to get animation offset of
  233. * @param flags Images current flags
  234. * @param pAniX Gets set to new X animation offset
  235. * @param pAniY Gets set to new Y animation offset
  236. */
  237. void GetAniOffset(SCNHANDLE hImg, int flags, int *pAniX, int *pAniY) {
  238. if (hImg) {
  239. const IMAGE *pImg = (const IMAGE *)LockMem(hImg);
  240. // set ani X
  241. *pAniX = (int16) FROM_16(pImg->anioffX);
  242. // set ani Y
  243. *pAniY = (int16) FROM_16(pImg->anioffY);
  244. if (flags & DMA_FLIPH) {
  245. // we are flipped horizontally
  246. // set ani X = -ani X + width - 1
  247. *pAniX = -*pAniX + FROM_16(pImg->imgWidth) - 1;
  248. }
  249. if (flags & DMA_FLIPV) {
  250. // we are flipped vertically
  251. // set ani Y = -ani Y + height - 1
  252. *pAniY = -*pAniY + (FROM_16(pImg->imgHeight) & ~C16_FLAG_MASK) - 1;
  253. }
  254. } else
  255. // null image
  256. *pAniX = *pAniY = 0;
  257. }
  258. /**
  259. * Returns the x,y position of an objects animation point.
  260. * @param pObj Pointer to object
  261. * @param pPosX Gets set to objects X animation position
  262. * @param pPosY Gets set to objects Y animation position
  263. */
  264. void GetAniPosition(OBJECT *pObj, int *pPosX, int *pPosY) {
  265. // validate object pointer
  266. assert(isValidObject(pObj));
  267. // get the animation offset of the object
  268. GetAniOffset(pObj->hImg, pObj->flags, pPosX, pPosY);
  269. // from animation offset and objects position - determine objects animation point
  270. *pPosX += fracToInt(pObj->xPos);
  271. *pPosY += fracToInt(pObj->yPos);
  272. }
  273. /**
  274. * Initialize a object using a OBJ_INIT structure to supply parameters.
  275. * @param pInitTbl Pointer to object initialisation table
  276. */
  277. OBJECT *InitObject(const OBJ_INIT *pInitTbl) {
  278. // allocate a new object
  279. OBJECT *pObj = AllocObject();
  280. // make sure object created
  281. assert(pObj != NULL);
  282. // set objects shape
  283. pObj->hImg = pInitTbl->hObjImg;
  284. // set objects ID
  285. pObj->oid = pInitTbl->objID;
  286. // set objects flags
  287. pObj->flags = DMA_CHANGED | pInitTbl->objFlags;
  288. // set objects Z position
  289. pObj->zPos = pInitTbl->objZ;
  290. // get pointer to image
  291. if (pInitTbl->hObjImg) {
  292. int aniX, aniY; // objects animation offsets
  293. PALQ *pPalQ= nullptr; // palette queue pointer
  294. const IMAGE *pImg = (const IMAGE *)LockMem(pInitTbl->hObjImg); // handle to image
  295. if (pImg->hImgPal) {
  296. // allocate a palette for this object
  297. pPalQ = AllocPalette(FROM_32(pImg->hImgPal));
  298. // make sure palette allocated
  299. assert(pPalQ != NULL);
  300. }
  301. // assign palette to object
  302. pObj->pPal = pPalQ;
  303. // set objects size
  304. pObj->width = FROM_16(pImg->imgWidth);
  305. pObj->height = FROM_16(pImg->imgHeight) & ~C16_FLAG_MASK;
  306. pObj->flags &= ~C16_FLAG_MASK;
  307. pObj->flags |= FROM_16(pImg->imgHeight) & C16_FLAG_MASK;
  308. // set objects bitmap definition
  309. pObj->hBits = FROM_32(pImg->hImgBits);
  310. // get animation offset of object
  311. GetAniOffset(pObj->hImg, pInitTbl->objFlags, &aniX, &aniY);
  312. // set objects X position - subtract ani offset
  313. pObj->xPos = intToFrac(pInitTbl->objX - aniX);
  314. // set objects Y position - subtract ani offset
  315. pObj->yPos = intToFrac(pInitTbl->objY - aniY);
  316. } else { // no image handle - null image
  317. // set objects X position
  318. pObj->xPos = intToFrac(pInitTbl->objX);
  319. // set objects Y position
  320. pObj->yPos = intToFrac(pInitTbl->objY);
  321. }
  322. // return new object
  323. return pObj;
  324. }
  325. /**
  326. * Give a object a new image and new orientation flags.
  327. * @param pAniObj Object to be updated
  328. * @param newflags Objects new flags
  329. * @param hNewImg Objects new image
  330. */
  331. void AnimateObjectFlags(OBJECT *pAniObj, int newflags, SCNHANDLE hNewImg) {
  332. // validate object pointer
  333. assert(isValidObject(pAniObj));
  334. if (pAniObj->hImg != hNewImg
  335. || (pAniObj->flags & DMA_HARDFLAGS) != (newflags & DMA_HARDFLAGS)) {
  336. // something has changed
  337. int oldAniX, oldAniY; // objects old animation offsets
  338. int newAniX, newAniY; // objects new animation offsets
  339. // get objects old animation offsets
  340. GetAniOffset(pAniObj->hImg, pAniObj->flags, &oldAniX, &oldAniY);
  341. // get objects new animation offsets
  342. GetAniOffset(hNewImg, newflags, &newAniX, &newAniY);
  343. if (hNewImg) {
  344. // get pointer to image
  345. const IMAGE *pNewImg = (IMAGE *)LockMem(hNewImg);
  346. // setup new shape
  347. pAniObj->width = FROM_16(pNewImg->imgWidth);
  348. pAniObj->height = FROM_16(pNewImg->imgHeight) & ~C16_FLAG_MASK;
  349. newflags &= ~C16_FLAG_MASK;
  350. newflags |= FROM_16(pNewImg->imgHeight) & C16_FLAG_MASK;
  351. // set objects bitmap definition
  352. pAniObj->hBits = FROM_32(pNewImg->hImgBits);
  353. } else { // null image
  354. pAniObj->width = 0;
  355. pAniObj->height = 0;
  356. pAniObj->hBits = 0;
  357. }
  358. // set objects flags and signal a change
  359. pAniObj->flags = newflags | DMA_CHANGED;
  360. // set objects image
  361. pAniObj->hImg = hNewImg;
  362. // adjust objects position - subtract new from old for difference
  363. pAniObj->xPos += intToFrac(oldAniX - newAniX);
  364. pAniObj->yPos += intToFrac(oldAniY - newAniY);
  365. }
  366. }
  367. /**
  368. * Give an object a new image.
  369. * @param pAniObj Object to animate
  370. * @param hNewImg Objects new image
  371. */
  372. void AnimateObject(OBJECT *pAniObj, SCNHANDLE hNewImg) {
  373. // dont change the objects flags
  374. AnimateObjectFlags(pAniObj, pAniObj->flags, hNewImg);
  375. }
  376. /**
  377. * Creates a rectangle object of the given dimensions and returns
  378. * a pointer to the object.
  379. * @param hPal Palette for the rectangle object
  380. * @param color Which color offset from the above palette
  381. * @param width Width of rectangle
  382. * @param height Height of rectangle
  383. */
  384. OBJECT *RectangleObject(SCNHANDLE hPal, int color, int width, int height) {
  385. // template for initializing the rectangle object
  386. static const OBJ_INIT rectObj = {0, DMA_CONST, OID_EFFECTS, 0, 0, 0};
  387. PALQ *pPalQ; // palette queue pointer
  388. // allocate and init a new object
  389. OBJECT *pRect = InitObject(&rectObj);
  390. // allocate a palette for this object
  391. pPalQ = AllocPalette(hPal);
  392. // make sure palette allocated
  393. assert(pPalQ != NULL);
  394. // assign palette to object
  395. pRect->pPal = pPalQ;
  396. // set color in the palette
  397. pRect->constant = color;
  398. // set rectangle width
  399. pRect->width = width;
  400. // set rectangle height
  401. pRect->height = height;
  402. // return pointer to rectangle object
  403. return pRect;
  404. }
  405. /**
  406. * Creates a translucent rectangle object of the given dimensions
  407. * and returns a pointer to the object.
  408. * @param width Width of rectangle
  409. * @param height Height of rectangle
  410. */
  411. OBJECT *TranslucentObject(int width, int height) {
  412. // template for initializing the rectangle object
  413. static const OBJ_INIT rectObj = {0, DMA_TRANS, OID_EFFECTS, 0, 0, 0};
  414. // allocate and init a new object
  415. OBJECT *pRect = InitObject(&rectObj);
  416. // set rectangle width
  417. pRect->width = width;
  418. // set rectangle height
  419. pRect->height = height;
  420. // return pointer to rectangle object
  421. return pRect;
  422. }
  423. } // End of namespace Tinsel