home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Learn 3D Graphics Programming on the PC
/
Learn_3D_Graphics_Programming_on_the_PC_Ferraro.iso
/
rwdos
/
object.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-02-15
|
29KB
|
952 lines
/**********************************************************************
*
* File : object.c
*
* Abstract : Generic object handler. This module handles the depth
* sorting and general control flow for the objects in
* the street.
*
**********************************************************************
*
* This file is a product of Criterion Software Ltd.
*
* This file is provided as is with no warranties of any kind and is
* provided without any obligation on Criterion Software Ltd. or
* Canon Inc. to assist in its use or modification.
*
* Criterion Software Ltd. will not, under any
* circumstances, be liable for any lost revenue or other damages arising
* from the use of this file.
*
* Copyright (c) 1995 Criterion Software Ltd.
* All Rights Reserved.
*
* RenderWare is a trademark of Canon Inc.
*
************************************************************************/
/*--- Include files ---*/
#include "global.h" /* Application general includes */
/*--- Structure Definitions ---*/
/* All Objects: A single global variable of this type is declared and used
* to hold the data for all of the objects currently defined
*/
typedef struct
{
Object **oppObjects;
int nEndObject;
int nAmoObjects;
RwV3d vDeletePos;
int nFirst; /* 0-2 : 0 x 1 y 2 z */
int nSecond;
int nThird;
int (*fpCompare)(const void *,const void *);
} AllObjects;
AllObjects aoGAll;
/*--- Macor and Magic Number definitions */
#define MAX_NUM 20 /* The maximum depth for an object in cyberstreet
any objects that are further away from the camera
than this will automatically be deleted */
/* Patch for floating point */
#ifdef RWFLOAT
#define RETURNINT(A) ((int)((A)*65536.0))
#else
#define RETURNINT(A) (A)
#endif
#define INITIAL_OBJECTS 20 /* Initial number of objects */
#define OBJ_INCREASE 5 /* Allocate space for this many objects
at a time */
/************************************************************************
*
* Function: DefaultRender()
*
* Description: The default object render function. This function
* will be used to render all objects that don't
* explicitly define their own render function
*
* Parameters: opObj - the object to render
*
* Return Value: None
*
************************************************************************/
static void DefaultRender(Object *opObj)
{
if (opObj->cpClump)
{
/* The default render action is just to translate the clump to
its final position and render it */
RwTranslateMatrix(RwScratchMatrix(),
opObj->vPos.x,
opObj->vPos.y,
opObj->vPos.z, rwREPLACE);
RwTransformClump(opObj->cpClump, RwScratchMatrix(), rwREPLACE);
RwRenderClump(opObj->cpClump);
}
}
/************************************************************************
*
* Function: DefaultUpdate()
*
* Description: The default object update function. This function
* will be used to update all objects that don't
* explicitly define their own update function
*
* Parameters: opObj - the object to update
*
* Return Value: None
*
************************************************************************/
static void
DefaultUpdate(Object *opObj)
{
/* Don't do anything for the default object */
opObj = opObj;
}
/************************************************************************
*
* Function: DefaultDestroy()
*
* Description: The default object destroy function. This function
* will be used to destroy all objects that don't
* explicitly define their own destroy function
*
* Parameters: opObj - the object to destroy
*
* Return Value: None
*
************************************************************************/
static void
DefaultDestroy(Object *opObj)
{
/* Destroy the RenderWare clump */
RwDestroyClump(opObj->cpClump);
/* free up the object data */
free(opObj);
}
/************************************************************************
* Object Depth Sorting:
* We make the following assumptions about the objects in the cyberstreet scene.
* 1. If 2 objects occupy the same space then they will be drawn in an
* arbitrary order. We don't want to Z buffer them.
* 2. The objects are small and self contained, therefore a simple depth sort
* using the objects origins is sufficient.
* For these reasons we choose to implement our own scene sorting which because
* of its specific nature will be quicker than the more general RenderWare
* scene sorting which will always try to render an accurate result.
*
* The algorithm that is used is a simple depth sort, where objects are sorted
* such that those furthest from the camera are drawn first. We use the standard
* C library function 'qsort' to perform the sorting.
*
* There are 2 mechanisms that are used to determine how best to sort the scene.
* the implementation of these mechanism varies with camera position.
* 1. We sort the scene by the most significant axis first down to least
* least significant. ie if the camera is looking along the X axis, then
* the x component of an objects position is more important than the y
* component in determining correct ordering. The order of sorting is
* assigned as first, second, third
*
* 2. Depending on the direction of the camera's at vector, the comparison
* mechanism varies. ie A camera looking along the positive X axis would
* sort from maximum X (furthest) to minimum Z (nearest). If the camera
* was looking along the negative X axis then the sort order would be from
* minimum X (furthest) to maximum X (nearest). Given this, we need 8
* comparison functions for qsort which implement all combinations of
* camera orientation in the 3 axis X, Y, and Z
*
*************************************************************************/
/************************************************************************
*
* Function: FMaxSMaxTMax()
*
* Description: qsort comparison function.
*
* Parameters: oppF - first object
* oppS - second object
*
* Return Value: -ve if 2nd object is further away than the first
* 0 if they occupy the same location
* +ve if the 2nd object is nearer that the first
*
************************************************************************/
static int
FMaxSMaxTMax(const Object **oppF, const Object **oppS)
{
RwReal nVal;
/* Compare the position of the 2 objects in the Most Significant Axis */
if (nVal = -((RwReal *)(&((*oppF)->vPos)))[aoGAll.nFirst] +
((RwReal *)(&((*oppS)->vPos)))[aoGAll.nFirst] )
{
return RETURNINT(nVal);
}
/* Most significant Axis comarison was zero so try the next one */
if (nVal = -((RwReal *)(&((*oppF)->vPos)))[aoGAll.nSecond] +
((RwReal *)(&((*oppS)->vPos)))[aoGAll.nSecond] )
{
return RETURNINT(nVal);
}
/* Try the least significant axis */
nVal = -((RwReal *)(&((*oppF)->vPos)))[aoGAll.nThird] +
((RwReal *)(&((*oppS)->vPos)))[aoGAll.nThird];
return RETURNINT(nVal);
}
/************************************************************************
*
* Function: FMinSMaxTMax()
*
* Description: qsort comparison function.
*
* Parameters: oppF - first object
* oppS - second object
*
* Return Value: -ve if 2nd object is further away than the first
* 0 if they occupy the same location
* +ve if the 2nd object is nearer that the first
*
************************************************************************/
static int
FMinSMaxTMax(const Object **oppF, const Object **oppS)
{
RwReal nVal;
/* Compare the position of the 2 objects in the Most Significant Axis */
if (nVal = ((RwReal *)(&((*oppF)->vPos)))[aoGAll.nFirst] -
((RwReal *)(&((*oppS)->vPos)))[aoGAll.nFirst] )
{
return RETURNINT(nVal);
}
/* Most significant Axis comarison was zero so try the next one */
if (nVal = -((RwReal *)(&((*oppF)->vPos)))[aoGAll.nSecond] +
((RwReal *)(&((*oppS)->vPos)))[aoGAll.nSecond] )
{
return RETURNINT(nVal);
}
/* Try the least significant axis */
nVal = -((RwReal *)(&((*oppF)->vPos)))[aoGAll.nThird] +
((RwReal *)(&((*oppS)->vPos)))[aoGAll.nThird];
return RETURNINT(nVal);
}
/************************************************************************
*
* Function: FMinSMinTMax()
*
* Description: qsort comparison function.
*
* Parameters: oppF - first object
* oppS - second object
*
* Return Value: -ve if 2nd object is further away than the first
* 0 if they occupy the same location
* +ve if the 2nd object is nearer that the first
*
************************************************************************/
static int FMinSMinTMax(const Object **oppF,const Object **oppS)
{
RwReal nVal;
/* Compare the position of the 2 objects in the Most Significant Axis */
if (nVal = ((RwReal *)(&((*oppF)->vPos)))[aoGAll.nFirst] -
((RwReal *)(&((*oppS)->vPos)))[aoGAll.nFirst] )
{
return RETURNINT(nVal);
}
/* Most significant Axis comarison was zero so try the next one */
if (nVal = ((RwReal *)(&((*oppF)->vPos)))[aoGAll.nSecond] -
((RwReal *)(&((*oppS)->vPos)))[aoGAll.nSecond] )
{
return RETURNINT(nVal);
}
/* Try the least significant axis */
nVal = -((RwReal *)(&((*oppF)->vPos)))[aoGAll.nThird] +
((RwReal *)(&((*oppS)->vPos)))[aoGAll.nThird];
return RETURNINT(nVal);
}
/************************************************************************
*
* Function: FMaxSMinTMax()
*
* Description: qsort comparison function.
*
* Parameters: oppF - first object
* oppS - second object
*
* Return Value: -ve if 2nd object is further away than the first
* 0 if they occupy the same location
* +ve if the 2nd object is nearer that the first
*
************************************************************************/
static int
FMaxSMinTMax(const Object **oppF, const Object **oppS)
{
RwReal nVal;
/* Compare the position of the 2 objects in the Most Significant Axis */
if (nVal = -((RwReal *)(&((*oppF)->vPos)))[aoGAll.nFirst] +
((RwReal *)(&((*oppS)->vPos)))[aoGAll.nFirst] )
{
return RETURNINT(nVal);
}
/* Most significant Axis comarison was zero so try the next one */
if (nVal = ((RwReal *)(&((*oppF)->vPos)))[aoGAll.nSecond] -
((RwReal *)(&((*oppS)->vPos)))[aoGAll.nSecond] )
{
return RETURNINT(nVal);
}
/* Try the least significant axis */
nVal = -((RwReal *)(&((*oppF)->vPos)))[aoGAll.nThird] +
((RwReal *)(&((*oppS)->vPos)))[aoGAll.nThird];
return RETURNINT(nVal);
}
/************************************************************************
*
* Function: FMaxSMinTMin()
*
* Description: qsort comparison function.
*
* Parameters: oppF - first object
* oppS - second object
*
* Return Value: -ve if 2nd object is further away than the first
* 0 if they occupy the same location
* +ve if the 2nd object is nearer that the first
*
************************************************************************/
int FMaxSMinTMin(const Object **oppF,const Object **oppS)
{
RwReal nVal;
/* Compare the position of the 2 objects in the Most Significant Axis */
if (nVal = -((RwReal *)(&((*oppF)->vPos)))[aoGAll.nFirst] +
((RwReal *)(&((*oppS)->vPos)))[aoGAll.nFirst] )
{
return RETURNINT(nVal);
}
/* Most significant Axis comarison was zero so try the next one */
if (nVal = ((RwReal *)(&((*oppF)->vPos)))[aoGAll.nSecond] -
((RwReal *)(&((*oppS)->vPos)))[aoGAll.nSecond] )
{
return RETURNINT(nVal);
}
/* Try the least significant axis */
nVal = ((RwReal *)(&((*oppF)->vPos)))[aoGAll.nThird] -
((RwReal *)(&((*oppS)->vPos)))[aoGAll.nThird];
return RETURNINT(nVal);
}
/************************************************************************
*
* Function: FMinSMinTMin()
*
* Description: qsort comparison function.
*
* Parameters: oppF - first object
* oppS - second object
*
* Return Value: -ve if 2nd object is further away than the first
* 0 if they occupy the same location
* +ve if the 2nd object is nearer that the first
*
************************************************************************/
static int
FMinSMinTMin(const Object **oppF, const Object **oppS)
{
RwReal nVal;
/* Compare the position of the 2 objects in the Most Significant Axis */
if (nVal = ((RwReal *)(&((*oppF)->vPos)))[aoGAll.nFirst] -
((RwReal *)(&((*oppS)->vPos)))[aoGAll.nFirst] )
{
return RETURNINT(nVal);
}
/* Most significant Axis comarison was zero so try the next one */
if (nVal = ((RwReal *)(&((*oppF)->vPos)))[aoGAll.nSecond] -
((RwReal *)(&((*oppS)->vPos)))[aoGAll.nSecond] )
{
return RETURNINT(nVal);
}
/* Try the least significant axis */
nVal = ((RwReal *)(&((*oppF)->vPos)))[aoGAll.nThird] -
((RwReal *)(&((*oppS)->vPos)))[aoGAll.nThird];
return RETURNINT(nVal);
}
/************************************************************************
*
* Function: FMinSMaxTMin()
*
* Description: qsort comparison function.
*
* Parameters: oppF - first object
* oppS - second object
*
* Return Value: -ve if 2nd object is further away than the first
* 0 if they occupy the same location
* +ve if the 2nd object is nearer that the first
*
************************************************************************/
static int
FMinSMaxTMin(const Object **oppF, const Object **oppS)
{
RwReal nVal;
/* Compare the position of the 2 objects in the Most Significant Axis */
if (nVal = ((RwReal *)(&((*oppF)->vPos)))[aoGAll.nFirst] -
((RwReal *)(&((*oppS)->vPos)))[aoGAll.nFirst] )
{
return RETURNINT(nVal);
}
/* Most significant Axis comarison was zero so try the next one */
if (nVal = -((RwReal *)(&((*oppF)->vPos)))[aoGAll.nSecond] +
((RwReal *)(&((*oppS)->vPos)))[aoGAll.nSecond] )
{
return RETURNINT(nVal);
}
/* Try the least significant axis */
nVal = ((RwReal *)(&((*oppF)->vPos)))[aoGAll.nThird] -
((RwReal *)(&((*oppS)->vPos)))[aoGAll.nThird];
return RETURNINT(nVal);
}
/************************************************************************
*
* Function: FMaxSMaxTMin()
*
* Description: qsort comparison function.
*
* Parameters: oppF - first object
* oppS - second object
*
* Return Value: -ve if 2nd object is further away than the first
* 0 if they occupy the same location
* +ve if the 2nd object is nearer that the first
*
************************************************************************/
static int
FMaxSMaxTMin(const Object **oppF, const Object **oppS)
{
RwReal nVal;
/* Compare the position of the 2 objects in the Most Significant Axis */
if (nVal = -((RwReal *)(&((*oppF)->vPos)))[aoGAll.nFirst] +
((RwReal *)(&((*oppS)->vPos)))[aoGAll.nFirst] )
{
return RETURNINT(nVal);
}
/* Most significant Axis comarison was zero so try the next one */
if (nVal = -((RwReal *)(&((*oppF)->vPos)))[aoGAll.nSecond] +
((RwReal *)(&((*oppS)->vPos)))[aoGAll.nSecond] )
{
return RETURNINT(nVal);
}
/* Try the least significant axis */
nVal = ((RwReal *)(&((*oppF)->vPos)))[aoGAll.nThird] -
((RwReal *)(&((*oppS)->vPos)))[aoGAll.nThird];
return RETURNINT(nVal);
}
/************************************************************************
*
* Function: ObjectDelete()
*
* Description: Delete and object from the cyberstreet scene. Rather
* than remove it from it current place in the scene and
* have to shuffle the list about, we just move it to a
* distant point and then delete all of the objects at
* this point once the list has been reordered on the
* next render.
*
* Parameters: opObj - object to delete
*
* Return Value: None
*
************************************************************************/
void ObjectDelete(Object *opObj)
{
opObj->vPos = aoGAll.vDeletePos;
}
/************************************************************************
*
* Function: ObjectSetup()
*
* Description: Initialise an objects data structure.
*
* Parameters: opObj - object to set up
* x, y, z - Initial position for the object
* cpClump - The RenderWare clump data for the object
*
* Return Value: None
*
************************************************************************/
void
ObjectSetup(Object *opObj, RwReal x, RwReal y, RwReal z, RwClump *cpClump)
{
/* define the functions that will be used to render, update and
* destroy the object. Not these functions may be overloaded with
* an object specific routine
*/
opObj->fpRender = DefaultRender;
opObj->fpUpdate = DefaultUpdate;
opObj->fpDestroy = DefaultDestroy;
/* Initialise the objects position
*/
opObj->vPos.x = x;
opObj->vPos.y = y;
opObj->vPos.z = z;
/* The object has no extra information initially. This value may
* be overloaded later
*/
opObj->pExtra = NULL;
/* Define the objects clump
*/
opObj->cpClump = cpClump;
}
/************************************************************************
*
* Function: AllObjectsUpdate()
*
* Description: Update the position of all of the objects
*
* Parameters: None
*
* Return Value: None
*
************************************************************************/
void
AllObjectsUpdate(void)
{
int nCount; /* Temporary loop control variable */
Object **oppObj; /* Object pointer used in loop iteration */
RwV3d vAt; /* The camera look at vector */
RwV3d vSize; /* The absolute x, y, and z for the camera look at
vector */
/* Get the camera's look at vector */
RwGetCameraLookAt(cpGCamera,&vAt);
/* based on the camera's look at vector, determine the position that
* will be used as the 'delete position' for this frame. Any objects
* that are moved to this position will be deleted after the scene
* has been sorted.
*/
if (vAt.x < CREAL(0.0))
{
aoGAll.vDeletePos.x = CREAL(+MAX_NUM);
vSize.x = -vAt.x;
}
else
{
aoGAll.vDeletePos.x = CREAL(-MAX_NUM);
vSize.x = +vAt.x;
}
if (vAt.y < CREAL(0.0))
{
aoGAll.vDeletePos.y = CREAL(+MAX_NUM);
vSize.y = -vAt.y;
}
else
{
aoGAll.vDeletePos.y = CREAL(-MAX_NUM);
vSize.y = +vAt.y;
}
if (vAt.z < CREAL(0.0))
{
aoGAll.vDeletePos.z = CREAL(+MAX_NUM);
vSize.z = -vAt.z;
}
else
{
aoGAll.vDeletePos.z = CREAL(-MAX_NUM);
vSize.z = +vAt.z;
}
/* Determine the order that the axis will be compared in when performing
* the depth sort.
*/
if (vSize.x > vSize.y)
{
if (vSize.y > vSize.z)
{
/* x > y > z */
aoGAll.nFirst = 0;
aoGAll.nSecond = 1;
aoGAll.nThird = 2;
}
else
{
/* y smallest */
aoGAll.nThird = 1;
if (vSize.x > vSize.z)
{
/* x > z > y */
aoGAll.nFirst = 0;
aoGAll.nSecond = 2;
}
else
{
/* z > x > y */
aoGAll.nFirst = 2;
aoGAll.nSecond = 0;
}
}
}
else
{
/* y > x */
if (vSize.y > vSize.z)
{
/* y largest */
aoGAll.nFirst = 1;
if (vSize.x > vSize.z)
{
/* y > x > z */
aoGAll.nSecond = 0;
aoGAll.nThird = 2;
}
else
{
/* y > z > x */
aoGAll.nSecond = 2;
aoGAll.nThird = 0;
}
}
else
{
/* z > y > x */
aoGAll.nFirst = 2;
aoGAll.nSecond = 1;
aoGAll.nThird = 0;
}
}
/* Determine the sort function that we will use based on the cameras
* at vector
*/
if (((RwReal *)&vAt)[aoGAll.nFirst] > CREAL(0.0))
{
/* Max1 */
if (((RwReal *)&vAt)[aoGAll.nSecond]>CREAL(0.0))
{
/* Max2 */
if (((RwReal *)&vAt)[aoGAll.nThird]>CREAL(0.0))
{
/* Max 3*/
aoGAll.fpCompare = FMaxSMaxTMax;
}
else
{
/* Min 3 */
aoGAll.fpCompare = FMaxSMaxTMin;
}
}
else
{
/* Min2 */
if (((RwReal *)&vAt)[aoGAll.nThird] > CREAL(0.0))
{
/* Max 3*/
aoGAll.fpCompare = FMaxSMinTMax;
}
else
{
/* Min 3 */
aoGAll.fpCompare = FMaxSMinTMin;
}
}
}
else
{
/* Min 1 */
if (((RwReal *)&vAt)[aoGAll.nSecond]>CREAL(0.0))
{
/* Max2 */
if (((RwReal *)&vAt)[aoGAll.nThird]>CREAL(0.0))
{
/* Max 3*/
aoGAll.fpCompare = FMinSMaxTMax;
}
else
{
/* Min 3 */
aoGAll.fpCompare = FMinSMaxTMin;
}
}
else
{
/* Min2 */
if (((RwReal *)&vAt)[aoGAll.nThird]>CREAL(0.0))
{
/* Max 3*/
aoGAll.fpCompare = FMinSMinTMax;
}
else
{
/* Min 3 */
aoGAll.fpCompare = FMinSMinTMin;
}
}
}
/* Call the object update function for all of the objects in the street */
oppObj = aoGAll.oppObjects;
for (nCount=0; nCount < aoGAll.nEndObject; nCount++, oppObj++)
{
(*oppObj)->fpUpdate(*oppObj);
}
}
/************************************************************************
*
* Function: AllObjectsSetup()
*
* Description: Initialise the global object data structure
*
* Parameters: None
*
* Return Value: None
*
************************************************************************/
int AllObjectsSetup(void)
{
aoGAll.oppObjects = (Object **) malloc(sizeof(Object *)*INITIAL_OBJECTS);
aoGAll.nAmoObjects = INITIAL_OBJECTS;
aoGAll.nEndObject = 0;
return TRUE;
}
/************************************************************************
*
* Function: AllObjectsAddObject()
*
* Description: Add an object to the list of global objects
*
* Parameters: opObj - the object to add to the global list
*
* Return Value: None
*
************************************************************************/
void AllObjectsAddObject(Object *opObj)
{
if (aoGAll.nEndObject == aoGAll.nAmoObjects)
{
/* The object list is full. Grow it a bit */
aoGAll.oppObjects = realloc(aoGAll.oppObjects,
sizeof(Object *) * (aoGAll.nAmoObjects + OBJ_INCREASE));
aoGAll.nAmoObjects += OBJ_INCREASE;
}
/* Add the object to the list */
aoGAll.oppObjects[aoGAll.nEndObject++] = opObj;
}
/************************************************************************
*
* Function: AllObjectsDestroy()
*
* Description: Destroy the global object data structure
*
* Parameters: None
*
* Return Value: None
*
************************************************************************/
void
AllObjectsDestroy(void)
{
int nCount;
Object **oppObj;
/* Destroy all of the objects first */
oppObj = aoGAll.oppObjects;
for (nCount=0; nCount < aoGAll.nEndObject; nCount++, oppObj++)
{
(*oppObj)->fpDestroy(*oppObj);
}
/* Destroy the All Object structure */
free(aoGAll.oppObjects);
}
/************************************************************************
*
* Function: AllObjectsRender()
*
* Description: Sort the objects in the scene and then render them
* from furthest to nearest
*
* Parameters: None
*
* Return Value: None
*
************************************************************************/
void
AllObjectsRender(void)
{
int nCount; /* temporary loop control variable */
int nNewEnd; /* the last object that was rendered */
Object **oppObj;
/* Order all of the objects */
qsort(aoGAll.oppObjects, aoGAll.nEndObject, sizeof(Object *),
aoGAll.fpCompare);
/* Render each object using its own render function. We don't
* attempt to render objects that are at the delete position
*/
nCount = 0;
oppObj = aoGAll.oppObjects;
while ((nCount < aoGAll.nEndObject) &&
((*oppObj)->vPos.x != CREAL(MAX_NUM)) &&
((*oppObj)->vPos.x != CREAL(-MAX_NUM)) )
{
(*oppObj)->fpRender(*oppObj);
oppObj++;
nCount++;
}
/* Delete all the unwanted objects */
nNewEnd = nCount;
while (nCount < aoGAll.nEndObject)
{
(*oppObj)->fpDestroy(*oppObj);
oppObj++;
nCount++;
}
/* This is the last object now */
aoGAll.nEndObject = nNewEnd;
}
/************************************************************************
*
* Function: AddStaticObject()
*
* Description: Read a clump and position it at a fixed location
* in the scene
*
* Parameters: x, y, z - fixed position for the object
* name - the RenderWare script file name
*
* Return Value: None
*
************************************************************************/
int
AddStaticObject(RwReal x, RwReal y, RwReal z, char *name)
{
Object *opObj;
RwClump *cpClump;
if (!(cpClump = DoRwReadShape(name)))
{
return FALSE;
}
/* Create the object data structure */
opObj = malloc(sizeof(Object));
/* Setup the object and add it to the list of global objects */
ObjectSetup(opObj, x, y, z, cpClump);
AllObjectsAddObject(opObj);
return TRUE;
}