aboutsummaryrefslogtreecommitdiff
path: root/engines/tinsel/object.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/tinsel/object.cpp')
-rw-r--r--engines/tinsel/object.cpp530
1 files changed, 530 insertions, 0 deletions
diff --git a/engines/tinsel/object.cpp b/engines/tinsel/object.cpp
new file mode 100644
index 0000000000..709fa4fad9
--- /dev/null
+++ b/engines/tinsel/object.cpp
@@ -0,0 +1,530 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ * This file contains the Object Manager code.
+ */
+
+#include "tinsel/object.h"
+#include "tinsel/background.h"
+#include "tinsel/cliprect.h" // object clip rect defs
+#include "tinsel/graphics.h" // low level interface
+#include "tinsel/handle.h"
+
+#define OID_EFFECTS 0x2000 // generic special effects object id
+
+namespace Tinsel {
+
+/** screen clipping rectangle */
+static const Common::Rect rcScreen(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+
+// list of all objects
+OBJECT *objectList = 0;
+
+// pointer to free object list
+static OBJECT *pFreeObjects = 0;
+
+#ifdef DEBUG
+// diagnostic object counters
+static int numObj = 0;
+static int maxObj = 0;
+#endif
+
+void FreeObjectList(void) {
+ if (objectList) {
+ free(objectList);
+ objectList = NULL;
+ }
+}
+
+/**
+ * Kills all objects and places them on the free list.
+ */
+
+void KillAllObjects(void) {
+ int i;
+
+#ifdef DEBUG
+ // clear number of objects in use
+ numObj = 0;
+#endif
+
+ if (objectList == NULL) {
+ // first time - allocate memory for object list
+ objectList = (OBJECT *)calloc(NUM_OBJECTS, sizeof(OBJECT));
+
+ // make sure memory allocated
+ if (objectList == NULL) {
+ error("Cannot allocate memory for object data");
+ }
+ }
+
+ // place first object on free list
+ pFreeObjects = objectList;
+
+ // link all other objects after first
+ for (i = 1; i < NUM_OBJECTS; i++) {
+ objectList[i - 1].pNext = objectList + i;
+ }
+
+ // null the last object
+ objectList[NUM_OBJECTS - 1].pNext = NULL;
+}
+
+
+#ifdef DEBUG
+/**
+ * Shows the maximum number of objects used at once.
+ */
+
+void ObjectStats(void) {
+ printf("%i objects of %i used.\n", maxObj, NUM_OBJECTS);
+}
+#endif
+
+/**
+ * Allocate a object from the free list.
+ */
+OBJECT *AllocObject(void) {
+ OBJECT *pObj = pFreeObjects; // get a free object
+
+ // check for no free objects
+ assert(pObj != NULL);
+
+ // a free object exists
+
+ // get link to next free object
+ pFreeObjects = pObj->pNext;
+
+ // clear out object
+ memset(pObj, 0, sizeof(OBJECT));
+
+ // set default drawing mode and set changed bit
+ pObj->flags = DMA_WNZ | DMA_CHANGED;
+
+#ifdef DEBUG
+ // one more object in use
+ if (++numObj > maxObj)
+ maxObj = numObj;
+#endif
+
+ // return new object
+ return pObj;
+}
+
+/**
+ * Copy one object to another.
+ * @param pDest Destination object
+ * @param pSrc Source object
+ */
+void CopyObject(OBJECT *pDest, OBJECT *pSrc) {
+ // save previous dimensions etc.
+ Common::Rect rcSave = pDest->rcPrev;
+
+ // make a copy
+ memcpy(pDest, pSrc, sizeof(OBJECT));
+
+ // restore previous dimensions etc.
+ pDest->rcPrev = rcSave;
+
+ // set changed flag in destination
+ pDest->flags |= DMA_CHANGED;
+
+ // null the links
+ pDest->pNext = pDest->pSlave = NULL;
+}
+
+/**
+ * Inserts an object onto the specified object list. The object
+ * lists are sorted in Z Y order.
+ * @param pObjList List to insert object onto
+ * @param pInsObj Object to insert
+ */
+
+void InsertObject(OBJECT *pObjList, OBJECT *pInsObj) {
+ OBJECT *pPrev, *pObj; // object list traversal pointers
+
+ // validate object pointer
+ assert(pInsObj >= objectList && pInsObj <= objectList + NUM_OBJECTS - 1);
+
+ for (pPrev = pObjList, pObj = pObjList->pNext; pObj != NULL; pPrev = pObj, pObj = pObj->pNext) {
+ // check Z order
+ if (pInsObj->zPos < pObj->zPos) {
+ // object Z is lower than list Z - insert here
+ break;
+ } else if (pInsObj->zPos == pObj->zPos) {
+ // Z values are the same - sort on Y
+ if (fracToDouble(pInsObj->yPos) <= fracToDouble(pObj->yPos)) {
+ // object Y is lower than or same as list Y - insert here
+ break;
+ }
+ }
+ }
+
+ // insert obj between pPrev and pObj
+ pInsObj->pNext = pObj;
+ pPrev->pNext = pInsObj;
+}
+
+
+/**
+ * Deletes an object from the specified object list and places it
+ * on the free list.
+ * @param pObjList List to delete object from
+ * @param pDelObj Object to delete
+ */
+void DelObject(OBJECT *pObjList, OBJECT *pDelObj) {
+ OBJECT *pPrev, *pObj; // object list traversal pointers
+
+ // validate object pointer
+ assert(pDelObj >= objectList && pDelObj <= objectList + NUM_OBJECTS - 1);
+
+#ifdef DEBUG
+ // one less object in use
+ --numObj;
+ assert(numObj >= 0);
+#endif
+
+ for (pPrev = pObjList, pObj = pObjList->pNext; pObj != NULL; pPrev = pObj, pObj = pObj->pNext) {
+ if (pObj == pDelObj) {
+ // found object to delete
+
+ if (IntersectRectangle(pDelObj->rcPrev, pDelObj->rcPrev, rcScreen)) {
+ // allocate a clipping rect for objects previous pos
+ AddClipRect(pDelObj->rcPrev);
+ }
+
+ // make PREV next = OBJ next - removes OBJ from list
+ pPrev->pNext = pObj->pNext;
+
+ // place free list in OBJ next
+ pObj->pNext = pFreeObjects;
+
+ // add OBJ to top of free list
+ pFreeObjects = pObj;
+
+ // delete objects palette
+ if (pObj->pPal)
+ FreePalette(pObj->pPal);
+
+ // quit
+ return;
+ }
+ }
+
+ // if we get to here - object has not been found on the list
+ error("DelObject(): formally 'assert(0)!'");
+}
+
+
+/**
+ * Sort the specified object list in Z Y order.
+ * @param pObjList List to sort
+ */
+void SortObjectList(OBJECT *pObjList) {
+ OBJECT *pPrev, *pObj; // object list traversal pointers
+ OBJECT head; // temporary head of list - because pObjList is not usually a OBJECT
+
+ // put at head of list
+ head.pNext = pObjList->pNext;
+
+ // set head of list dummy OBJ Z Y values to lowest possible
+ head.yPos = intToFrac(MIN_INT16);
+ head.zPos = MIN_INT;
+
+ for (pPrev = &head, pObj = head.pNext; pObj != NULL; pPrev = pObj, pObj = pObj->pNext) {
+ // check Z order
+ if (pObj->zPos < pPrev->zPos) {
+ // object Z is lower than previous Z
+
+ // remove object from list
+ pPrev->pNext = pObj->pNext;
+
+ // re-insert object on list
+ InsertObject(pObjList, pObj);
+
+ // back to beginning of list
+ pPrev = &head;
+ pObj = head.pNext;
+ } else if (pObj->zPos == pPrev->zPos) {
+ // Z values are the same - sort on Y
+ if (fracToDouble(pObj->yPos) < fracToDouble(pPrev->yPos)) {
+ // object Y is lower than previous Y
+
+ // remove object from list
+ pPrev->pNext = pObj->pNext;
+
+ // re-insert object on list
+ InsertObject(pObjList, pObj);
+
+ // back to beginning of list
+ pPrev = &head;
+ pObj = head.pNext;
+ }
+ }
+ }
+}
+
+/**
+ * Returns the animation offsets of a image, dependent on the
+ * images orientation flags.
+ * @param hImg Iimage to get animation offset of
+ * @param flags Images current flags
+ * @param pAniX Gets set to new X animation offset
+ * @param pAniY Gets set to new Y animation offset
+ */
+void GetAniOffset(SCNHANDLE hImg, int flags, int *pAniX, int *pAniY) {
+ if (hImg) {
+ const IMAGE *pImg = (const IMAGE *)LockMem(hImg);
+
+ // set ani X
+ *pAniX = (int16) FROM_LE_16(pImg->anioffX);
+
+ // set ani Y
+ *pAniY = (int16) FROM_LE_16(pImg->anioffY);
+
+ if (flags & DMA_FLIPH) {
+ // we are flipped horizontally
+
+ // set ani X = -ani X + width - 1
+ *pAniX = -*pAniX + FROM_LE_16(pImg->imgWidth) - 1;
+ }
+
+ if (flags & DMA_FLIPV) {
+ // we are flipped vertically
+
+ // set ani Y = -ani Y + height - 1
+ *pAniY = -*pAniY + FROM_LE_16(pImg->imgHeight) - 1;
+ }
+ } else
+ // null image
+ *pAniX = *pAniY = 0;
+}
+
+
+/**
+ * Returns the x,y position of an objects animation point.
+ * @param pObj Pointer to object
+ * @param pPosX Gets set to objects X animation position
+ * @param pPosY Gets set to objects Y animation position
+ */
+void GetAniPosition(OBJECT *pObj, int *pPosX, int *pPosY) {
+ // validate object pointer
+ assert(pObj >= objectList && pObj <= objectList + NUM_OBJECTS - 1);
+
+ // get the animation offset of the object
+ GetAniOffset(pObj->hImg, pObj->flags, pPosX, pPosY);
+
+ // from animation offset and objects position - determine objects animation point
+ *pPosX += fracToInt(pObj->xPos);
+ *pPosY += fracToInt(pObj->yPos);
+}
+
+/**
+ * Initialise a object using a OBJ_INIT structure to supply parameters.
+ * @param pInitTbl Pointer to object initialisation table
+ */
+OBJECT *InitObject(const OBJ_INIT *pInitTbl) {
+ // allocate a new object
+ OBJECT *pObj = AllocObject();
+
+ // make sure object created
+ assert(pObj != NULL);
+
+ // set objects shape
+ pObj->hImg = pInitTbl->hObjImg;
+
+ // set objects ID
+ pObj->oid = pInitTbl->objID;
+
+ // set objects flags
+ pObj->flags = DMA_CHANGED | pInitTbl->objFlags;
+
+ // set objects Z position
+ pObj->zPos = pInitTbl->objZ;
+
+ // get pointer to image
+ if (pInitTbl->hObjImg) {
+ int aniX, aniY; // objects animation offsets
+ PALQ *pPalQ; // palette queue pointer
+ const IMAGE *pImg = (const IMAGE *)LockMem(pInitTbl->hObjImg); // handle to image
+
+ // allocate a palette for this object
+ pPalQ = AllocPalette(FROM_LE_32(pImg->hImgPal));
+
+ // make sure palette allocated
+ assert(pPalQ != NULL);
+
+ // assign palette to object
+ pObj->pPal = pPalQ;
+
+ // set objects size
+ pObj->width = FROM_LE_16(pImg->imgWidth);
+ pObj->height = FROM_LE_16(pImg->imgHeight);
+
+ // set objects bitmap definition
+ pObj->hBits = FROM_LE_32(pImg->hImgBits);
+
+ // get animation offset of object
+ GetAniOffset(pObj->hImg, pInitTbl->objFlags, &aniX, &aniY);
+
+ // set objects X position - subtract ani offset
+ pObj->xPos = intToFrac(pInitTbl->objX - aniX);
+
+ // set objects Y position - subtract ani offset
+ pObj->yPos = intToFrac(pInitTbl->objY - aniY);
+ } else { // no image handle - null image
+
+ // set objects X position
+ pObj->xPos = intToFrac(pInitTbl->objX);
+
+ // set objects Y position
+ pObj->yPos = intToFrac(pInitTbl->objY);
+ }
+
+ // return new object
+ return pObj;
+}
+
+/**
+ * Give a object a new image and new orientation flags.
+ * @param pAniObj Object to be updated
+ * @param newflags Objects new flags
+ * @param hNewImg Objects new image
+ */
+void AnimateObjectFlags(OBJECT *pAniObj, int newflags, SCNHANDLE hNewImg) {
+ // validate object pointer
+ assert(pAniObj >= objectList && pAniObj <= objectList + NUM_OBJECTS - 1);
+
+ if (pAniObj->hImg != hNewImg
+ || (pAniObj->flags & DMA_HARDFLAGS) != (newflags & DMA_HARDFLAGS)) {
+ // something has changed
+
+ int oldAniX, oldAniY; // objects old animation offsets
+ int newAniX, newAniY; // objects new animation offsets
+
+ // get objects old animation offsets
+ GetAniOffset(pAniObj->hImg, pAniObj->flags, &oldAniX, &oldAniY);
+
+ // get objects new animation offsets
+ GetAniOffset(hNewImg, newflags, &newAniX, &newAniY);
+
+ if (hNewImg) {
+ // get pointer to image
+ const IMAGE *pNewImg = (IMAGE *)LockMem(hNewImg);
+
+ // setup new shape
+ pAniObj->width = FROM_LE_16(pNewImg->imgWidth);
+ pAniObj->height = FROM_LE_16(pNewImg->imgHeight);
+
+ // set objects bitmap definition
+ pAniObj->hBits = FROM_LE_32(pNewImg->hImgBits);
+ } else { // null image
+ pAniObj->width = 0;
+ pAniObj->height = 0;
+ pAniObj->hBits = 0;
+ }
+
+ // set objects flags and signal a change
+ pAniObj->flags = newflags | DMA_CHANGED;
+
+ // set objects image
+ pAniObj->hImg = hNewImg;
+
+ // adjust objects position - subtract new from old for difference
+ pAniObj->xPos += intToFrac(oldAniX - newAniX);
+ pAniObj->yPos += intToFrac(oldAniY - newAniY);
+ }
+}
+
+/**
+ * Give an object a new image.
+ * @param pAniObj Object to animate
+ * @param hNewImg Objects new image
+ */
+void AnimateObject(OBJECT *pAniObj, SCNHANDLE hNewImg) {
+ // dont change the objects flags
+ AnimateObjectFlags(pAniObj, pAniObj->flags, hNewImg);
+}
+
+/**
+ * Creates a rectangle object of the given dimensions and returns
+ * a pointer to the object.
+ * @param hPal Palette for the rectangle object
+ * @param colour Which colour offset from the above palette
+ * @param width Width of rectangle
+ * @param height Height of rectangle
+ */
+OBJECT *RectangleObject(SCNHANDLE hPal, int colour, int width, int height) {
+ // template for initialising the rectangle object
+ static const OBJ_INIT rectObj = {0, DMA_CONST, OID_EFFECTS, 0, 0, 0};
+ PALQ *pPalQ; // palette queue pointer
+
+ // allocate and init a new object
+ OBJECT *pRect = InitObject(&rectObj);
+
+ // allocate a palette for this object
+ pPalQ = AllocPalette(hPal);
+
+ // make sure palette allocated
+ assert(pPalQ != NULL);
+
+ // assign palette to object
+ pRect->pPal = pPalQ;
+
+ // set colour in the palette
+ pRect->constant = colour;
+
+ // set rectangle width
+ pRect->width = width;
+
+ // set rectangle height
+ pRect->height = height;
+
+ // return pointer to rectangle object
+ return pRect;
+}
+
+/**
+ * Creates a translucent rectangle object of the given dimensions
+ * and returns a pointer to the object.
+ * @param width Width of rectangle
+ * @param height Height of rectangle
+ */
+OBJECT *TranslucentObject(int width, int height) {
+ // template for initialising the rectangle object
+ static const OBJ_INIT rectObj = {0, DMA_TRANS, OID_EFFECTS, 0, 0, 0};
+
+ // allocate and init a new object
+ OBJECT *pRect = InitObject(&rectObj);
+
+ // set rectangle width
+ pRect->width = width;
+
+ // set rectangle height
+ pRect->height = height;
+
+ // return pointer to rectangle object
+ return pRect;
+}
+
+} // end of namespace Tinsel