/************************************************************ * * * object.c * * * * * LPGE 1997 * * * * Copyright (C) 1996 Sony Computer Entertainment Inc. * * All Rights Reserved * * * ***********************************************************/ // vital to keep separate the overall object-handling list // (an array of pointers) from the actual objects themselves; // this way we can keep object-handling code unchanged, while // introducing new sub-arrays, e.g. TheShuttles, TheShips, etc; // enables us to refer to objects either by the global handling-list // or more directly, by 'the 3rd shuttle' i.e. TheShuttles[2] #include "object.h" #include "vector.h" #include "camera.h" // the array of object references ObjectHandler* ObjectArray[MAX_OBJECTS]; // macros #define ALL_ONES 0xffffffff u_long onlyNthBitOn, onlyNthBitOffMask; #define TURN_NTH_BIT_OFF(argument, sizeInBits, N) \ { \ onlyNthBitOn = 1 << (N); \ onlyNthBitOffMask = ALL_ONES ^ onlyNthBitOn; \ argument &= onlyNthBitOffMask; \ } /*************** first section: class functions *************************/ void InitialiseObjectClass (void) { int i; for (i = 0; i < MAX_OBJECTS; i++) { ObjectArray[i] = NULL; } } // find id of first existing object with lower id int FindNextLowestObjectID (int objectID) { int nextLowestID; nextLowestID = objectID-1; for (;;) { if (nextLowestID < 0) nextLowestID = MAX_OBJECTS-1; if (ObjectArray[nextLowestID] != NULL) { if (ObjectArray[nextLowestID]->alive == TRUE) break; } nextLowestID--; } return nextLowestID; } // find id of first existing object with higher id int FindNextHighestObjectID (int objectID) { int nextHighestID; nextHighestID = objectID+1; for (;;) { if (nextHighestID >= MAX_OBJECTS) nextHighestID = 0; if (ObjectArray[nextHighestID] != NULL) { if (ObjectArray[nextHighestID]->alive == TRUE) break; } nextHighestID++; } return nextHighestID; } int FindNextUnusedObjectID (void) { int id = -1; int i; for (i = 0; i < MAX_OBJECTS; i++) { if (ObjectArray[i] == NULL) { id = i; break; } } return id; } int CountNumberOfLivingObjects (void) { int count = 0; int i; for (i = 0; i < MAX_OBJECTS; i++) { if (ObjectArray[i] != NULL) { if (ObjectArray[i]->alive == TRUE) count++; } } return count; } int CountNumberOfLivingTypedObjects (int type) { int count = 0; int i; for (i = 0; i < MAX_OBJECTS; i++) { if (ObjectArray[i] != NULL) { if (ObjectArray[i]->alive == TRUE && ObjectArray[i]->type == type) { count++; } } } return count; } // all objects must be set up and registered in global array // before this function is called void LinkAllObjectsToModelsOrSprites (void) { ObjectHandler* object; int i; for (i = 0; i < MAX_OBJECTS; i++) { if (ObjectArray[i] != NULL) { if (ObjectArray[i]->alive == TRUE) { if (ObjectArray[i]->displayFlag == TMD) { object = ObjectArray[i]; LinkObjectHandlerToTmdObject( &(object->handler), object->whichModel, object->modelAddress); } else if (ObjectArray[i]->displayFlag == SPRITE) { object = ObjectArray[i]; LinkSpriteToImageInfo ( &object->sprite, object->imageInfo); } } } } } // all objects must be set up and registered in global array // before this function is called void LinkAllObjectsToTheirCoordinateSystems (void) { ObjectHandler* object; int superCoordinateObjectID; int i; for (i = 0; i < MAX_OBJECTS; i++) { if (ObjectArray[i] != NULL) { if (ObjectArray[i]->alive == TRUE) { object = ObjectArray[i]; superCoordinateObjectID = object->superCoordinateObjectID; if (superCoordinateObjectID == NONE) // set to own coord system { object->handler.coord2 = &(object->coord); } else if (superCoordinateObjectID == THE_WORLD) { object->handler.coord2 = WORLD; } else { object->handler.coord2 = &(ObjectArray[superCoordinateObjectID]->coord); } } } } } /*************** second section: individual object functions ***********************/ void BringObjectToLife (ObjectHandler* object, int type, u_long modelAddress, int whichModel, int superCoordinateObjectID) { object->alive = TRUE; object->type = type; object->modelAddress = modelAddress; object->whichModel = whichModel; // note: use NONE for own independent coordinate system object->superCoordinateObjectID = superCoordinateObjectID; } void KillAnObject (ObjectHandler* object) { object->alive = FALSE; } void RegisterObjectIntoObjectArray (ObjectHandler* object) { int nextFreeID; nextFreeID = FindNextUnusedObjectID(); assert(nextFreeID != -1); assert(nextFreeID >= 0); assert(nextFreeID < MAX_OBJECTS); assert(ObjectArray[nextFreeID] == NULL); ObjectArray[nextFreeID] = object; object->id = nextFreeID; } void RemoveObjectFromObjectArray (ObjectHandler* object) { int objectID; objectID = object->id; assert(objectID >= 0); assert(objectID < MAX_OBJECTS); assert(ObjectArray[objectID] != NULL); ObjectArray[objectID] = NULL; object->id = NONE; } void InitSingleObject (ObjectHandler* object) { int i; object->id = NONE; object->alive = FALSE; object->type = NONE; strcpy( object->name, "NO_NAME"); object->shipType = -1; object->controllerResponsiveFlag = TRUE; object->interactivityFlag = TRUE; object->displayFlag = TMD; // by default object->imageInfo = NULL; InitGsSprite( &object->sprite); object->scaleX = ONE; object->scaleY = ONE; object->handler.attribute = 0; object->handler.coord2 = WORLD; object->handler.tmd = NULL; object->handler.id = 0; object->modelAddress = 0; object->whichModel = NONE; object->modelFlag = TMD_RIGHT_WAY; object->viewMode = VIEW_FIXED_BEHIND_ABOVE_OBJECT; object->storedViewMode = VIEW_FIXED_BEHIND_ABOVE_OBJECT; object->scalingFlag = FALSE; object->scalingVector.vx = ONE; object->scalingVector.vy = ONE; object->scalingVector.vz = ONE; // start off stationary with no momentum object->position.vx = 0; object->position.vy = 0; object->position.vz = 0; object->velocity.vx = 0; object->velocity.vy = 0; object->velocity.vz = 0; object->movementMomentumFlag = FALSE; object->accelerationSpeed = 0; object->brakingSpeed = 0; object->maximumSpeed = -1; object->movementFrictionCoefficient = -1; object->specialMovementFlag = -1; object->rotationType = -1; object->rotate.vx = 0; object->rotate.vy = 0; object->rotate.vz = 0; object->twist.vx = 0; object->twist.vy = 0; object->twist.vz = 0; object->rotationMomentumFlag = FALSE; setVECTOR( &object->rotationPower, 0, 0, 0); object->rotationFrictionCoefficient = -1; object->angle = -1; object->tilt = -1; object->a = -1; object->b = -1; object->c = -1; object->collisionWithTunnelCoefficient = -1; object->collisionWithOtherShipsCoefficient = -1; // this for initialisation, rather than link to WORLD coords GsInitCoordinate2(WORLD, &(object->coord) ); object->handler.coord2 = &(object->coord); object->superCoordinateObjectID = NONE; object->matrix.m[0][0] = ONE; object->matrix.m[0][1] = 0; object->matrix.m[0][2] = 0; object->matrix.m[1][0] = 0; object->matrix.m[1][1] = ONE; object->matrix.m[1][2] = 0; object->matrix.m[2][0] = 0; object->matrix.m[2][1] = 0; object->matrix.m[2][2] = ONE; object->matrix.t[0] = 0; object->matrix.t[1] = 0; object->matrix.t[2] = 0; object->lifeTime = 0; object->specialTimeLimit = 0; object->framesSinceLastViewFlip = 0; object->framesSinceLastLookBehind = 0; object->lookBehindFlag = FALSE; object->collisionRadius = -1; object->tunnelCollisionTreatmentFlag = -1; object->shipCollisionTreatmentFlag = -1; object->tunnelSection = -1; object->racingFlag = FALSE; object->furthestLap = -1; object->lapProgressFlag = FALSE; object->furthestSection = -1; object->advancedFlag = FALSE; object->placeInRace = -1; for (i = 0; i < MAX_LAPS_PER_OBJECT+1; i++) { object->framesWhenLapsEnd[i] = 0; } object->bestLapTime = -1; object->properMovementFlag = TRUE; object->speedFactor = -1; object->discreteSpeed = -1; object->startFrame = -1; object->currentPositionIndex = -1; object->speedControlFlag = -1; object->speedControlPeriod = -1; object->playbackFrameIndex = -1; object->pad0 = 0; object->pad1 = 0; object->pad2 = 0; object->pad3 = 0; } // set axis-wise scaling parameters // ONE is normal (no-scale) size // this is RELATIVE scaling only void SetObjectScaling (ObjectHandler* object, int scaleX, int scaleY, int scaleZ) { object->scalingFlag = TRUE; object->scalingVector.vx = scaleX; object->scalingVector.vy = scaleY; object->scalingVector.vz = scaleZ; } /**** scale object in 3 ways NOTE: with a hierarchical coordinate system, any scaling of object X will affect all objects whose coord. systems are children of X's coordinate systems ****/ void SortObjectSize (ObjectHandler* object) { if (object->scalingFlag == FALSE) return; ScaleMatrix(&object->coord.coord, &object->scalingVector); // tell graphics system that coordinate system is changed object->coord.flg = 0; } // quicker to directly assign to attribute // but would lose all other attribute effects void SetObjectSubdivision (ObjectHandler* object, int setting) { TURN_NTH_BIT_OFF(object->handler.attribute, 32, 9); TURN_NTH_BIT_OFF(object->handler.attribute, 32, 10); TURN_NTH_BIT_OFF(object->handler.attribute, 32, 11); switch (setting) { case 0: break; case 1: object->handler.attribute |= GsDIV1; break; case 2: object->handler.attribute |= GsDIV2; break; case 3: object->handler.attribute |= GsDIV3; break; case 4: object->handler.attribute |= GsDIV4; break; case 5: object->handler.attribute |= GsDIV5; break; default: assert(FALSE); } } void DumpObject (ObjectHandler *object) { assert(object != NULL); printf("id %d\n", object->id); printf("id %d\n", object->alive); printf("id %d\n", object->type); printf("name %s\n", object->name); printf("shipType %d\n", object->shipType); printf("controllerResponsiveFlag %d\n", object->controllerResponsiveFlag); printf("displayFlag %d\n", object->displayFlag); dumpOBJ2( &object->handler); printf("modelAddress %d\n", (int)object->modelAddress); printf("whichModel %d\n", object->whichModel); printf("modelFlag %d\n", object->modelFlag); printf("scalingFlag %d\n", object->scalingFlag); printf("scalingVector: "); dumpVECTOR( &object->scalingVector); printf("position: "); dumpVECTOR( &object->position); printf("velocity: "); dumpVECTOR( &object->velocity); }