/* ************************ Copyright Terrain Experts Inc. Terrain Experts Inc (TERREX) reserves all rights to this source code unless otherwise specified in writing by the President of TERREX. This copyright may be updated in the future, in which case that version supercedes this one. ------------------- Terrex Experts Inc. 4400 East Broadway #314 Tucson, AZ 85711 info@terrex.com Tel: (520) 323-7990 ************************ */ #ifndef _trpage_managers_h_ #define _trpage_managers_h_ #include /* This file contains class definitions for managers that help you keep track of data related to paging. For instance, which tiles to load in at any given time and what textures you need to read for a given tile. */ class trpgPageManager; // Grid and file location of a tile struct TileLocationInfo { TileLocationInfo(): x(-1), y(-1), lod(-1) {} TileLocationInfo(int gx, int gy, int glod, const trpgwAppAddress& gaddr): x(gx), y(gy), lod(glod), addr(gaddr) {} int x, y, lod; trpgwAppAddress addr; }; /* Managed Tiles are used by the trpgPageManager to keep track of which tiles are loaded and what textures (and models) they need loaded into memory with them. */ TX_EXDECL class TX_CLDECL trpgManagedTile { friend class trpgPageManager; public: trpgManagedTile(void); // Called to clear any info out of this tile void Reset(void); /* Call this when you hit a tile header in your own Scene parser callback. The managed tile can then keep track of which textures and models go with this tile. */ bool ParseTileHeader(trpgReadBuffer &); // Check if the tile is loaded (e.g. the header read in) bool IsLoaded(void); /* Set the tile location. This resets any internal state we may be keeping. */ bool SetTileLoc(int x,int y,int lod); // Get the tile location bool GetTileLoc(int &x,int &y,int &lod) const; // In version 2.1 we no longer have the tile table to // find the tiles, only by traversing the parent can it be // found. So when we have this info, this is were to save it. void SetTileAddress(const trpgwAppAddress& gAddr); void SetTileAddress(int32 file, int32 offset); const trpgwAppAddress& GetTileAddress() const; // Return a pointer to the tile header const trpgTileHeader *GetTileHead(void); /* Return a pointer to the list of locally defined materials. As soon as the tile header is read by ParseTileHeader (which you call) you'll want to get this list and load the pageable textures. You can use SetMatData to keep track of our internal texture structures. */ const std::vector *GetLocMatList(void) const; /* Returns a pointer to a single local material, if within the valid range of local materials for this tile. */ const trpgLocalMaterial *GetLocMaterial(int id) const; /* Set Local Data for managed tile. The local data would probably be a pointer to the top of the scene graph you're using to represent just this tile. */ void SetLocalData(void *); /* Returns the local data you set with SetLocalData. */ void *GetLocalData(void) const; /* Associates a void * with one of the materials referenced within this tile. The idea here is that you'll want to load the texture for a given local material and then pass your own internal texture structure into here as a void *. That way, the trpgPageManager will keep track of which textures you should unload when this tile goes out of range. */ bool SetMatData(int id,void *); /* Gets the void * data you associated with a given local material index. See SetMatData for more information. */ void *GetMatData(int id) const; /* Add Group ID to this tile. This is called by the page manager to keep track of which group IDs belong to this tile. We use this information to NULL out the appropriate positions in the group map help by the page manager. */ void AddGroupID(int id); /* Retrieve the list of group IDs for this tile. */ const std::vector *GetGroupIDs(void) const; /* Print the current status and information about this managed Tile. */ void Print(trpgPrintBuffer &); // Children info, will throw exception if child index is out of bound unsigned int GetNbChildren() const { return (unsigned int)childLocationInfo.size(); } bool SetChildLocationInfo(int childIdx, int x, int y, const trpgwAppAddress& addr); bool SetChildLocationInfo(int childIdx, const TileLocationInfo& info); const TileLocationInfo& GetChildLocationInfo(int childIdx) const; bool GetChildTileLoc(int childIdx, int &x,int &y,int &lod) const; const trpgwAppAddress& GetChildTileAddress(int childIdx) const; protected: // Set if a tile is currently loaded bool isLoaded; // Tile location info TileLocationInfo location; // Tile Header associated with this tile trpgTileHeader tileHead; // Data to keep associated with each individual local material index std::vector localMatData; // Used to keep track of group IDs in this tile std::vector groupIDs; // Local data (probably the top of the local scene graph) void *localData; // What are the children: this to be used for version 2.1 and up. // Both vector should have the same size std::vector childLocationInfo; // Note: Should do models too if anyone wanted them. }; /* The Page Manager is a helper class that can be used to keep track of: (1) which tiles need to be loaded into memory for a given viewer position, (2) which tiles are currently loaded and (3) which tiles need to be unloaded when the viewer position moves. The tile list this class generates is guaranteed to be in the right order for loading. You would use this class if you're implementing a TerraPage reader for your visual run-time system. */ TX_EXDECL class TX_CLDECL trpgPageManager { public: trpgPageManager(void); virtual ~trpgPageManager(void); // Initialize with an archive virtual void Init(trpgr_Archive *); virtual void Init(trpgr_Archive *inArch, int maxLod); /* Set Paging Distance This is the extra distance outside the visible range we want to page. The defaults will be valid. You would set this if you want to pull tiles in earlier. Be sure to call it before you call Init(), however. */ virtual bool SetPageDistFactor(double); /* Updates the current location for paging purposes. Returns true if any load or unloads need to happen. */ virtual bool SetLocation(trpg2dPoint &); /* Get next tile to load. The paging manager is keeping track of which tiles need to be loaded and in what order. This method returns a pointer to the next one. The user is expected to call AckLoad() after the tile is loaded. */ virtual trpgManagedTile *GetNextLoad(void); /* Acknowledge Tile Load. This method should be called when a tile has been loaded by the caller. This method is used in conjunction with GetNextLoad(). Version 2.1 and over supports variable lod so that we cannot know from the tile table if a tile exist or not. So to manage this the user must parse the loaded tile and extract its list of children and pass it on to AckLoad() which will add to the appropriate lod list the children info. If this is not done then only lod 0 will be pageable. */ virtual void AckLoad(std::vector const& children); // Using this call with version 2.1 and over will only page lod 0 tiles virtual void AckLoad(); /* Add Group ID to map. This should be called when the user encounters a group-like object while processing the scene graph data from a tile. The groupId is given by TerraPage and the data should be the corresponding group object that the user creates in their own scenegraph toolkit. This information can then be retrieved later by GetGroupData(). */ virtual void AddGroupID(trpgManagedTile *,int groupID,void *data); /* Get Group Data fetches the data cached by the user and associated with the given groupID. This would be used in conjunction with trpgAttach nodes to implement geometry paging. */ virtual void *GetGroupData(int groupID); /* Get next tile to unload. The paging manager keeps track of which tiles need to be unloaded based on a change of location. It's best if you unload tiles before loading them, but that's really up to you. */ virtual trpgManagedTile *GetNextUnload(void); /* Acknowledge a tile unload. You should call this after you've "unloaded" a tile and all its associated textures. */ virtual void AckUnload(void); /* Stop paging entirely. Call this right before you want to shut down paging. Everything active will wind up on the unload lists. Then you can unload those tiles and move on. */ virtual bool Stop(void); // Print current status and content information virtual void Print(trpgPrintBuffer &); protected: trpgr_Archive *archive; // Center of paging trpg2dPoint pagePt; /* Information associated with each terrain level of detail as related to paging. */ TX_EXDECL class TX_CLDECL LodPageInfo { friend class trpgPageManager; public: LodPageInfo(void); virtual ~LodPageInfo(void); /* Initializes the class with its current LOD. It figures out all the rest. */ virtual bool Init(trpgr_Archive *, int myLod, double scale, int freeListDivider = 1); /* Reset the location. This forces a recalculation of what to load and unload if the cell has changed or if this is the first SetLocation. The location passed in must be relative to the southwest corner of the TerraPage archive. */ virtual bool SetLocation(trpg2dPoint &); // Return the next tile to load for this terrain lod virtual trpgManagedTile *GetNextLoad(void); // Acknowledge the load. Move the active tile to the // loaded list. virtual void AckLoad(); // Get the lsit of //bool GetLoadedTile // Return the next tile to unload for this terrain lod virtual trpgManagedTile *GetNextUnload(void); // Acknowledge the unload. Move the active tile to the // free list. virtual void AckUnload(void); // Called to stop paging. Everything active is dumped on // the unload list. virtual bool Stop(void); // Print current status and content information virtual void Print(trpgPrintBuffer &); const trpg2iPoint& GetLodSize() const { return lodSize; } int GetLod() const { return lod; } double GetPageDistance() const { return pageDist; } const trpg2dPoint& GetCellSize() const { return cellSize; } // The unit are cellSize const trpg2iPoint& GetAreaOfInterest() const { return aoiSize; } // The middle of this cell correspond to our paging // location const trpg2iPoint& GetCellPagingLocation() const { return cell; } protected: virtual void Clean(void); virtual void Update(void); // Add to the load list the given tile if it is within the proper // bound bool AddToLoadList(int x, int y, const trpgwAppAddress& addr); // Add the children of the given parent list // to the load list if it it not already loaded // or if it is not already in the list void AddChildrenToLoadList(std::vector& parentList); // Check if the given tile is within the area we care about bool isWithin(trpgManagedTile *,trpg2iPoint &sw,trpg2iPoint &ne); // Get the list of currently loaded tiles that fall within // the region calculated from the given paging distance. void GetLoadedTileWithin(double pagingDistance, std::vector& tileList); bool valid; // Terrain LOD we're responsible for int lod; /* Adjusted (e.g. paranoid) distance outward from which to page this terrain LOD. This takes into account the distance in the header as well as any factor the user may have added. */ double pageDist; /* Max tiles we could have loaded in at any given time. This is just a guess because it's up to the user to load (and, more importantly) unload. */ int maxNumTiles; // Size of a single cell. Copied from the archive. trpg2dPoint cellSize; // Number of tiles (cells) in each direction trpg2iPoint lodSize; /* Area of interest size in cells This is a linear distance "ahead" of the center cell. */ trpg2iPoint aoiSize; /* Our effective paging location sits at the middle of this cell. We don't recalculate unless the cell changes. */ trpg2iPoint cell; // List of tiles to load std::deque load; // List of tiles to unload std::deque unload; // List of currently loaded tiles std::deque current; // Used by Update. Here because we want to avoid memory allocs, if possible. std::vector tmpCurrent; // Set if a load is in progress // Load w/o ACK bool activeLoad; // Set if an unload is in progress // Unload w/o ACK bool activeUnload; // List of tile pointers we can reuse std::deque freeList; // TerraPage version int majorVersion, minorVersion; const trpgTileTable *tileTable; }; // Per terrain lod paging information std::vector pageInfo; // Enumerated type for lastLoad typedef enum {Load,Unload,None} LoadType; /* Information about what the pending load/unload operation is. It's up to the user to complete and acknowledge it. */ LoadType lastLoad; // LOD for the pending load/unload requested operation int lastLod; // Tile to be loaded/unloaded trpgManagedTile *lastTile; // Optional scaling factor double scale; // Mapping from group IDs to user defined data typedef std::map ManageGroupMap; ManageGroupMap groupMap; // Terrapge Version int majorVersion, minorVersion; bool valid; }; // For Version 2.1 an over, the tile table only contains // tiles of lod 0. To get access the other tiles, parent tile // must be parsed to get at trpgChildRef nodes that will contain // location info about the children. This callback can be use to // parse the tile data. After parsing the callback object will contain // the list of trpgChildRef nodes found. TX_EXDECL class TX_CLDECL trpgr_ChildRefCB : public trpgr_Callback { public: void *Parse(trpgToken tok, trpgReadBuffer& rbuf); // After parsing this will return the number of trpgChildRef node found. unsigned int GetNbChildren() const; // This will return the trpgChildRef node associated with the index. // Will throw an exception if the index is out of bound const trpgChildRef& GetChildRef(unsigned int idx) const; // Clear the children list void Reset(); protected: // typedef std::vector ChildList; // The const in the template parameter was removed because it causes GCC to // freak out. I am of the opinion that const doesn't make sense in a template // parameter for std::vector anyway... const prevents you from changing the // value, so what exactly is the point? How does one add entries to the vector // without giving them a value? -ADS typedef std::vector ChildList; ChildList childList; }; /* Page Manager Tester. This class tests a given paging manager by applying likely */ TX_EXDECL class TX_CLDECL trpgPageManageTester { public: trpgPageManageTester(); virtual ~trpgPageManageTester(); /* Initialize the tester with a paging manager and an archive. */ void Init(trpgPrintBuffer *,trpgPageManager *,trpgr_Archive *); /* Feeds the paging manager coordinates starting from the lower left to upper right of the database in the given increment. */ void Fly_LL_to_UR(double dist=100.0); /* Jumps around randomly within the archive loading and unloading as needed. */ void RandomTest(int no=100,int seed=-1); protected: // Does the work of "load" and "unloading" void ProcessChanges(); trpgPageManager *manager; trpgr_Archive *archive; trpgPrintBuffer *printBuf; trpgr_ChildRefCB childRefCB; trpgr_Parser tileParser; // TerraPage version int majorVersion, minorVersion; }; #endif