/*
@Copyright Looking Glass Studios, Inc.
1996,1997,1998,1999,2000 Unpublished Work.
*/

/* objects.h
**
** The object system
**
** $Header: r:/prj/cam/libsrc/eos/RCS/objects.h 1.8 1997/05/16 16:22:40 kcobb Exp $
** $Log: objects.h $
 * Revision 1.8  1997/05/16  16:22:40  kcobb
 * Made changes preparing for phase III of db changes.
 * 
 * Revision 1.7  1996/12/26  23:57:55  mahk
 * fixed parenthisization.
 * 
 * Revision 1.6  1996/12/26  22:02:04  mahk
 * Changes for the negative object capable property enabled object system fo the future.
 * 
 * Revision 1.5  1996/12/06  17:12:26  mahk
 * Initial revision
 * 
 * Revision 1.4  1996/09/11  11:49:41  DFAN
 * New objects.h regime
 * Plus ObjActive typo
 * 
 * Revision 1.3  1996/07/24  12:39:01  DFAN
 * Reorg
 * 
 * Revision 1.2  1996/07/19  20:56:42  DFAN
 * Changed ibool to BOOL
 * Added pos pointer
 * 
 * Revision 1.1  1996/07/10  17:58:55  DFAN
 * Initial revision
 * 
*/

// IMPORTANT!!
//
// You should not include this file directly from an application!
//
// Make a .h file that #defines NUM_REF_SYSTEMS to be the number of
// RefSystems your app uses and POSITION to be the WorldRep typedef
// for a position (for the only wr.h as of this writing, this #define
// should be "Position").  For example:
//
// #define NUM_REF_SYSTEMS 2
// #define POSITION        Position
//
// That .h file must also #include <wr.h> before <objects.h>.
//
// Then have your app's file include that .h file instead of this one.

#ifndef _OBJECTS_H
#define _OBJECTS_H

#include <lg.h>
#include <objtype.h>

#ifdef I_AM_PART_OF_EOS
# define POSITION void
# define NUM_REF_SYSTEMS /**/
#else
# if !defined (POSITION)
#  error POSITION must be defined
# endif
# if !defined (NUM_REF_SYSTEMS)
#  error NUM_REF_SYSTEMS must be defined
# endif
#endif

// An object is classified by its "phylum" and "genus".  (In the previous
// version of the object system, these were "class" and "subclass".)
// Every object of a given phylum has the same size, and should be
// accessed by similar methods; the genus then serves to distinguish
// objects of the same phylum.  In Terra Nova, the phyla were
//
//   STATIC        (rocks, trees)
//   PBA
//   VEHICLE
//   AIRCRAFT
//   INSTALLATION  (buildings)
//   WEAPON
//   SFX           (special effects like smoke)
//   EXPLOSION     (special physics objects generated by grenades)
//
// In contrast to Terra Nova's object system, objects of a given phylum
// are not segregated into a separate array (therefore, there is no
// longer a SpecID concept).  Many objects of all sorts of sizes
// coexist throughout memory.  An ObjID is no longer an index into
// an array of Objs; it's just a handle which can point to any
// location in memory.

struct Obj
{
   Phylum     phylum;           // high-level classification of object
   Genus      genus;            // within-level classification
   ObjID      next;             // next active object
   ObjID      prev;             // prev active object
   ObjID      next_of_phylum;   // next object of same phylum
   ObjID      prev_of_phylum;   // prev object of same phylum
   POSITION  *pos;              // where is it?  Stored separately
   uchar      to_be_deleted:1;  // scheduled for deletion at end of frame?
   uchar      delete_reasons:7; // and why is it being deleted?
#ifdef NUM_REF_SYSTEMS
   ObjRefID   refs[NUM_REF_SYSTEMS]; // one for each RefSystem
#else
   ObjRefID   refs[];           // one for each RefSystem
#endif
   /* ... class specific stuff that only the app cares about ... */
};

typedef struct
{
   union
   {
      Obj   *obj;               // The actual object, or...
      ObjID  next;              // Next free object ID
   };
}
ObjInfo;                        // indexed by object handle

// How do we know whether a given ObjID exists?  We look it up in the
// ObjActiveArray.

#define ObjActiveSize ((gMaxObjs+7)/8)

#define ObjActiveMask(obj) (1 << ((obj) % 8))
#define ObjActiveIdx(obj) ((obj)/8)
#define ObjActiveElem(obj) (ObjActiveArray[ObjActiveIdx(obj)])

#define ObjDeactivateAll() \
   do {memset (ObjActiveArray, 0, ObjActiveSize);} while (0)

#define ObjActivate(obj) \
   do {ObjActiveElem(obj) |= ObjActiveMask(obj);} while (0)
      
#define ObjDeactivate(obj) \
   do {ObjActiveElem(obj) &= ~ObjActiveMask(obj);} while (0)

// Returns non-zero, not necessarily 1, if true
#define ObjActive(obj) \
   (ObjActiveElem(obj) & ObjActiveMask(obj))


// Variables defined in objects.c

EXTERN int      mNumPhyla;      // number of phyla
EXTERN ObjID    mObjFirstFree;  // first free ObjID in chain
EXTERN int     *mPhylumSizes;   // size of each phylum


// Variables that you, the application, must define!

EXTERN int      gMaxObjs;          // maximum number of objects allowed
EXTERN ObjInfo*  ObjInfos;        // object information array , gMaxObjs big
EXTERN ubyte*    ObjActiveArray;  // bitarray for whether objects are
                                   // active, ObjActiveSize big

// Important information about iteration:
//
// You can traverse all used objects by starting with ObjID 0's next
// field, and following next fields until you get back to 0.  You can
// use the prev field to go backwards.
//
// You can traverse all objects of phylum p by starting with ObjID p's
// next_of_phylum field, and following next_of_phylum fields until you
// get back to p.  You can use the prev_of_phylum to go backwards.
// It's kind of confusing that you never hit a 0, but this way we can
// share ID space without everything going nuts.

typedef BOOL (*ObjMoveFunc)(void* buf, int len);

EXTERN void  ObjsInit         (int num_phyla, int *phylum_sizes, int pos_size);
EXTERN void  ObjsTerm         (void);
EXTERN ObjID ObjGrab          (Phylum phylum);
EXTERN BOOL  ObjDel           (ObjID obj, uchar reasons);
EXTERN BOOL  ObjSysOkay       (void);
EXTERN ObjID ObjFirstOfPhylum (Phylum phylum);
EXTERN void  ObjSysEndOfFrame (void);
EXTERN BOOL  ObjUpdateLocs    (ObjID obj);
EXTERN void  ObjsClear        (void);
EXTERN BOOL  ObjsSave         (ObjMoveFunc writefunc, int beginRange, int endRange);
EXTERN BOOL  ObjsLoad         (ObjMoveFunc readfunc);

#define OBJID_TO_PTR_RAW(o) (ObjInfos[o].obj)
#define OBJID_TO_PTR_SAFE(o) \
   ((o) < mNumPhyla || (o) >= gMaxObjs || !ObjActive(o) ? NULL \
                                                    : ObjInfos[o].obj)
#define OBJID_TO_PTR(o) OBJID_TO_PTR_SAFE(o)

#endif

/*
Local Variables:
typedefs:("BOOL" "Genus" "Obj" "ObjID" "ObjInfo" "ObjRefID" "POSITION" "Phylum" "ubyte" "uchar" "ushort")
End:
*/
