3634 lines
173 KiB
C++
3634 lines
173 KiB
C++
/*
|
|
** Command & Conquer Renegade(tm)
|
|
** Copyright 2025 Electronic Arts Inc.
|
|
**
|
|
** 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/***********************************************************************************************
|
|
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
|
|
***********************************************************************************************
|
|
* *
|
|
* Project Name : WW3D *
|
|
* *
|
|
* $Archive:: /VSS_Sync/ww3d2/hlod.cpp $*
|
|
* *
|
|
* Author:: Greg Hjelstrom *
|
|
* *
|
|
* $Modtime:: 8/29/01 7:29p $*
|
|
* *
|
|
* $Revision:: 10 $*
|
|
* *
|
|
*---------------------------------------------------------------------------------------------*
|
|
* Functions: *
|
|
* HLodLoaderClass::Load_W3D -- Loads an HlodDef from a W3D file *
|
|
* HLodPrototypeClass::Create -- Creates an HLod from an HLodDef *
|
|
* HLodDefClass::HLodDefClass -- Constructor *
|
|
* HLodDefClass::HLodDefClass -- Copy Constructor *
|
|
* HLodDefClass::~HLodDefClass -- Destructor *
|
|
* HLodDefClass::Free -- releases all resources being used *
|
|
* HLodDefClass::Initialize -- init this def from an HLod *
|
|
* HLodDefClass::Save -- save this HLodDef *
|
|
* HLodDefClass::Save_Header -- writes the HLodDef header *
|
|
* HLodDefClass::Save_Lod_Array -- Saves the lod array *
|
|
* HLodDefClass::Save_Aggregate_Array -- Save the array of aggregate models *
|
|
* HLodDefClass::Load_W3D -- Loads this HLodDef from a W3d File *
|
|
* HLodDefClass::read_header -- loads the HLodDef header from a W3d file *
|
|
* HLodDefClass::read_proxy_array -- load the proxy names *
|
|
* HLodDefClass::SubObjectArrayClass::SubObjectArrayClass -- LodArray constructor *
|
|
* HLodDefClass::SubObjectArrayClass::~SubObjectArrayClass -- LodArray destructor *
|
|
* HLodDefClass::SubObjectArrayClass::Save_W3D -- saves a w3d file for this HLodDef *
|
|
* HLodDefClass::SubObjectArrayClass::Load_W3D -- LodArray load function *
|
|
* HLodDefClass::SubObjectArrayClass::Reset -- release the contents of this array *
|
|
* HLodClass::HLodClass -- Constructor *
|
|
* HLodClass::HLodClass -- copy constructor *
|
|
* HLodClass::HLodClass -- Constructor *
|
|
* HLodClass::HLodClass -- Constructs an HLod from an HLodDef *
|
|
* HLodClass::HLodClass -- Constructs an HLod from an HModelDef *
|
|
* HLodClass::operator -- assignment operator *
|
|
* HLodClass::~HLodClass -- Destructor *
|
|
* HLodClass::Free -- releases all resources *
|
|
* HLodClass::Clone -- virtual copy constructor *
|
|
* HLodClass::Set_Max_Screen_Size -- Set max-screen-size for an LOD *
|
|
* HLodClass::Get_Max_Screen_Size -- get max-screen-size for an LOD *
|
|
* HLodClass::Get_Lod_Count -- returns number of levels of detail *
|
|
* HLodClass::Get_Lod_Model_Count -- number of sub-objs in a given level of detail *
|
|
* HLodClass::Peek_Lod_Model -- returns pointer to a model in one of the LODs *
|
|
* HLodClass::Get_Lod_Model -- returns a pointer to a model in one of the LODs *
|
|
* HLodClass::Get_Lod_Model_Bone -- returns the bone index of a model *
|
|
* HLodClass::Get_Additional_Model_Count -- number of additional sub-objs *
|
|
* HLodClass::Peek_Additional_Model -- returns pointer to an additional model *
|
|
* HLodClass::Get_Additional_Model -- returns pointer to an additional model *
|
|
* HLodClass::Get_Additional_Model_Bone -- returns the bone index of an additional model *
|
|
* HLodClass::Is_NULL_Lod_Included -- does this HLod have NULL as its lowest LOD *
|
|
* HLodClass::Include_NULL_Lod -- Add NULL as the lowest LOD *
|
|
* HLodClass::Get_Num_Polys -- returns polycount of the current LOD *
|
|
* HLodClass::Render -- render this HLod *
|
|
* HLodClass::Special_Render -- Special_Render for HLod *
|
|
* HLodClass::Set_Transform -- Sets the transform *
|
|
* HLodClass::Set_Position -- Sets the position *
|
|
* HLodClass::Notify_Added -- callback notifies subobjs that they were added *
|
|
* HLodClass::Notify_Removed -- notifies subobjs that they were removed *
|
|
* HLodClass::Get_Num_Sub_Objects -- returns total number of sub-objects *
|
|
* HLodClass::Get_Sub_Object -- returns a pointer to specified sub-object *
|
|
* HLodClass::Add_Sub_Object -- add a sub-object to this HLod *
|
|
* HLodClass::Remove_Sub_Object -- remove a sub-object from this HLod *
|
|
* HLodClass::Get_Num_Sub_Objects_On_Bone -- returns the number of objects on the given bone *
|
|
* HLodClass::Get_Sub_Object_On_Bone -- returns obj on the given bone *
|
|
* HLodClass::Get_Sub_Object_Bone_Index -- returns bone index of given object *
|
|
* HLodClass::Add_Sub_Object_To_Bone -- adds a sub-object to a bone *
|
|
* HLodClass::Set_Animation -- set animation state to the base-pose *
|
|
* HLodClass::Set_Animation -- set animation state to an animation frame *
|
|
* HLodClass::Set_Animation -- set animation state to a blend of two animations *
|
|
* HLodClass::Set_Animation -- set animation state to a combination of anims *
|
|
* HLodClass::Cast_Ray -- cast a ray against this HLod *
|
|
* HLodClass::Cast_AABox -- Cast a swept AABox against this HLod *
|
|
* HLodClass::Cast_OBBox -- Cast a swept OBBox against this HLod *
|
|
* HLodClass::Intersect_AABox -- Intersect an AABox with this HLod *
|
|
* HLodClass::Intersect_OBBox -- Intersect an OBBox with this HLod *
|
|
* HLodClass::Prepare_LOD -- Prepare for LOD processing *
|
|
* HLodClass::Recalculate_Static_LOD_Factors -- compute lod factors *
|
|
* HLodClass::Increment_LOD -- move to next lod *
|
|
* HLodClass::Decrement_LOD -- move to previous lod *
|
|
* HLodClass::Get_Cost -- returns the cost of this LOD *
|
|
* HLodClass::Get_Value -- returns the value of this LOD *
|
|
* HLodClass::Get_Post_Increment_Value -- returns the post increment value *
|
|
* HLodClass::Set_LOD_Level -- set the current lod level *
|
|
* HLodClass::Get_LOD_Level -- returns the current LOD level *
|
|
* HLodClass::Get_LOD_Count -- returns the number of levels of detail *
|
|
* HLodClass::Calculate_Cost_Value_Arrays -- computes the cost-value arrays *
|
|
* HLodClass::Get_Current_LOD -- returns a render object which represents the current LOD *
|
|
* HLodClass::Set_Texture_Reduction_Factor -- resizeable texture support *
|
|
* HLodClass::Scale -- scale this HLod model *
|
|
* HLodClass::Get_Num_Snap_Points -- returns the number of snap points in this model *
|
|
* HLodClass::Get_Snap_Point -- returns specified snap-point *
|
|
* HLodClass::Update_Sub_Object_Transforms -- updates transforms of all sub-objects *
|
|
* HLodClass::Update_Obj_Space_Bounding_Volumes -- update object-space bounding volumes *
|
|
* HLodClass::add_lod_model -- adds a model to one of the lods *
|
|
* HLodClass::Create_Decal -- create a decal on this HLod *
|
|
* HLodClass::Delete_Decal -- remove a decal from this HLod *
|
|
* HLodClass::Set_HTree -- replace the hierarchy tree *
|
|
* HLodClass::Get_Proxy_Count -- Returns the number of proxy objects *
|
|
* HLodClass::Get_Proxy -- returns the information for the i'th proxy *
|
|
* HLodClass::Set_Hidden -- Propogates the hidden bit to particle emitters. *
|
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
|
|
|
|
#include "hlod.h"
|
|
#include "assetmgr.h"
|
|
#include "hmdldef.h"
|
|
#include "w3derr.h"
|
|
#include "chunkio.h"
|
|
#include "predlod.h"
|
|
#include "rinfo.h"
|
|
#include <string.h>
|
|
#include <win.h>
|
|
#include "sphere.h"
|
|
#include "boxrobj.h"
|
|
|
|
|
|
/*
|
|
** Loader Instance
|
|
*/
|
|
HLodLoaderClass _HLodLoader;
|
|
|
|
|
|
/**
|
|
** ProxyRecordClass
|
|
** This is a structure that contains the data describing a single "proxy" object. These
|
|
** are used for application purposes and simply provide a way for the assets to associate
|
|
** a string with a bone index.
|
|
*/
|
|
class ProxyRecordClass
|
|
{
|
|
public:
|
|
ProxyRecordClass(void) : BoneIndex(0)
|
|
{
|
|
memset(Name,0,sizeof(Name));
|
|
}
|
|
|
|
bool operator == (const ProxyRecordClass & that) { return false; }
|
|
bool operator != (const ProxyRecordClass & that) { return !(*this == that); }
|
|
|
|
void Init(const W3dHLodSubObjectStruct & w3d_data)
|
|
{
|
|
BoneIndex = w3d_data.BoneIndex;
|
|
strncpy(Name,w3d_data.Name,sizeof(Name));
|
|
}
|
|
|
|
int Get_Bone_Index(void) { return BoneIndex; }
|
|
const char * Get_Name(void) { return Name; }
|
|
|
|
protected:
|
|
|
|
int BoneIndex;
|
|
char Name[2*W3D_NAME_LEN];
|
|
|
|
};
|
|
|
|
/**
|
|
** ProxyArrayClass
|
|
** This is a ref-counted list of proxy objects. It is generated whenever an HLODdef contains
|
|
** proxies. Each instantiated HLOD simply add-refs a pointer to the single list.
|
|
*/
|
|
class ProxyArrayClass : public VectorClass<ProxyRecordClass>, public RefCountClass
|
|
{
|
|
public:
|
|
ProxyArrayClass(int size) : VectorClass<ProxyRecordClass>(size)
|
|
{
|
|
}
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
** The HLod Loader Implementation
|
|
*/
|
|
|
|
/***********************************************************************************************
|
|
* HLodLoaderClass::Load_W3D -- Loads an HlodDef from a W3D file *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
PrototypeClass *HLodLoaderClass::Load_W3D( ChunkLoadClass &cload )
|
|
{
|
|
HLodDefClass * def = new HLodDefClass;
|
|
|
|
if (def == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (def->Load_W3D(cload) != WW3D_ERROR_OK) {
|
|
// load failed, delete the model and return an error
|
|
delete def;
|
|
return NULL;
|
|
} else {
|
|
// ok, accept this model!
|
|
HLodPrototypeClass *proto = new HLodPrototypeClass(def);
|
|
return proto;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
** HLod Prototype Implementation
|
|
*/
|
|
|
|
/***********************************************************************************************
|
|
* HLodPrototypeClass::Create -- Creates an HLod from an HLodDef *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
RenderObjClass * HLodPrototypeClass::Create(void)
|
|
{
|
|
HLodClass * hlod = NEW_REF( HLodClass , ( *Definition ) );
|
|
return hlod;
|
|
}
|
|
|
|
|
|
/*
|
|
** HLodDef Implementation
|
|
*/
|
|
|
|
/***********************************************************************************************
|
|
* HLodDefClass::HLodDefClass -- Constructor *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
*=============================================================================================*/
|
|
HLodDefClass::HLodDefClass(void) :
|
|
Name(NULL),
|
|
HierarchyTreeName(NULL),
|
|
LodCount(0),
|
|
Lod(NULL),
|
|
ProxyArray(NULL)
|
|
{
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodDefClass::HLodDefClass -- Copy Constructor *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
HLodDefClass::HLodDefClass(HLodClass &src_lod) :
|
|
Name(NULL),
|
|
HierarchyTreeName(NULL),
|
|
LodCount(0),
|
|
Lod(NULL),
|
|
ProxyArray(NULL)
|
|
{
|
|
Initialize (src_lod);
|
|
return ;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodDefClass::~HLodDefClass -- Destructor *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
HLodDefClass::~HLodDefClass(void)
|
|
{
|
|
Free ();
|
|
return ;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodDefClass::Free -- releases all resources being used *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodDefClass::Free(void)
|
|
{
|
|
if (Name) {
|
|
::free(Name);
|
|
Name = NULL;
|
|
}
|
|
|
|
if (HierarchyTreeName) {
|
|
::free(HierarchyTreeName);
|
|
HierarchyTreeName = NULL;
|
|
}
|
|
|
|
if (Lod) {
|
|
delete[] Lod;
|
|
Lod = NULL;
|
|
}
|
|
LodCount = 0;
|
|
|
|
REF_PTR_RELEASE(ProxyArray);
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodDefClass::Initialize -- init this def from an HLod *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodDefClass::Initialize(HLodClass &src_lod)
|
|
{
|
|
// Start with a fresh set of data
|
|
Free ();
|
|
|
|
// Copy the name and hierarcy name from the source object
|
|
Name = ::strdup (src_lod.Get_Name ());
|
|
const HTreeClass *phtree = src_lod.Get_HTree ();
|
|
if (phtree != NULL) {
|
|
HierarchyTreeName = ::strdup (phtree->Get_Name ());
|
|
}
|
|
|
|
// Determine the number of LODs in the src object
|
|
LodCount = src_lod.Get_LOD_Count ();
|
|
WWASSERT (LodCount > 0);
|
|
if (LodCount > 0) {
|
|
|
|
// Allocate an array large enough to hold all the LODs and
|
|
// loop through each LOD.
|
|
Lod = new SubObjectArrayClass[LodCount];
|
|
for (int index = 0; index < LodCount; index ++) {
|
|
|
|
// Fill in the maximum screen size for this LOD
|
|
Lod[index].MaxScreenSize = src_lod.Get_Max_Screen_Size (index);
|
|
Lod[index].ModelCount = src_lod.Get_Lod_Model_Count (index);
|
|
|
|
// Loop through all the models that compose this LOD and generate a
|
|
// list of model's and the bones they live on
|
|
char **model_names = new char *[Lod[index].ModelCount];
|
|
int *bone_indicies = new int[Lod[index].ModelCount];
|
|
for (int model_index = 0; model_index < Lod[index].ModelCount; model_index ++) {
|
|
|
|
// Record information about this model (if possible)
|
|
RenderObjClass *prender_obj = src_lod.Peek_Lod_Model (index, model_index);
|
|
if (prender_obj != NULL) {
|
|
model_names[model_index] = ::strdup (prender_obj->Get_Name ());
|
|
bone_indicies[model_index] = src_lod.Get_Lod_Model_Bone (index, model_index);
|
|
} else {
|
|
model_names[model_index] = NULL;
|
|
bone_indicies[model_index] = 0;
|
|
}
|
|
}
|
|
|
|
// Pass these arrays of information onto our internal data
|
|
Lod[index].ModelName = model_names;
|
|
Lod[index].BoneIndex = bone_indicies;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodDefClass::Save -- save this HLodDef *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
WW3DErrorType HLodDefClass::Save(ChunkSaveClass & csave)
|
|
{
|
|
// Assume error
|
|
WW3DErrorType ret_val = WW3D_ERROR_SAVE_FAILED;
|
|
|
|
// Begin a chunk that identifies an aggregate
|
|
if (csave.Begin_Chunk (W3D_CHUNK_HLOD) == TRUE) {
|
|
|
|
// Attempt to save the different sections of the aggregate definition
|
|
if ((Save_Header (csave) == WW3D_ERROR_OK) &&
|
|
(Save_Lod_Array (csave) == WW3D_ERROR_OK)) {
|
|
|
|
// Success!
|
|
ret_val = WW3D_ERROR_OK;
|
|
}
|
|
|
|
// Close the aggregate chunk
|
|
csave.End_Chunk ();
|
|
}
|
|
|
|
// Return the WW3DErrorType return code
|
|
return ret_val;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodDefClass::Save_Header -- writes the HLodDef header *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
WW3DErrorType HLodDefClass::Save_Header(ChunkSaveClass &csave)
|
|
{
|
|
// Assume error
|
|
WW3DErrorType ret_val = WW3D_ERROR_SAVE_FAILED;
|
|
|
|
// Begin a chunk that identifies the aggregate
|
|
if (csave.Begin_Chunk (W3D_CHUNK_HLOD_HEADER) == TRUE) {
|
|
|
|
// Fill the header structure
|
|
W3dHLodHeaderStruct header = { 0 };
|
|
header.Version = W3D_CURRENT_HLOD_VERSION;
|
|
header.LodCount = LodCount;
|
|
|
|
// Copy the name to the header
|
|
::lstrcpyn (header.Name, Name, sizeof (header.Name));
|
|
header.Name[sizeof (header.Name) - 1] = 0;
|
|
|
|
// Copy the hierarchy tree name to the header
|
|
::lstrcpyn (header.HierarchyName, HierarchyTreeName, sizeof (header.HierarchyName));
|
|
header.HierarchyName[sizeof (header.HierarchyName) - 1] = 0;
|
|
|
|
// Write the header out to the chunk
|
|
if (csave.Write (&header, sizeof (header)) == sizeof (header)) {
|
|
|
|
// Success!
|
|
ret_val = WW3D_ERROR_OK;
|
|
}
|
|
|
|
// End the header chunk
|
|
csave.End_Chunk ();
|
|
}
|
|
|
|
// Return the WW3DErrorType return code
|
|
return ret_val;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodDefClass::Save_Lod_Array -- Saves the lod array *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
WW3DErrorType HLodDefClass::Save_Lod_Array(ChunkSaveClass &csave)
|
|
{
|
|
// Loop through all the LODs and save their model array to the chunk
|
|
bool success = true;
|
|
for (int lod_index = 0;
|
|
(lod_index < LodCount) && success;
|
|
lod_index ++) {
|
|
success = Lod[lod_index].Save_W3D (csave);
|
|
}
|
|
|
|
// Return the WW3DErrorType return code
|
|
return success ? WW3D_ERROR_OK : WW3D_ERROR_SAVE_FAILED;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodDefClass::Save_Aggregate_Array -- Save the array of aggregate models *
|
|
* *
|
|
* aggregate models are ones that are attached as "additional" models. *
|
|
* *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 10/25/2000 gth : Created. *
|
|
*=============================================================================================*/
|
|
WW3DErrorType HLodDefClass::Save_Aggregate_Array(ChunkSaveClass & csave)
|
|
{
|
|
if (Aggregates.ModelCount > 0) {
|
|
csave.Begin_Chunk(W3D_CHUNK_HLOD_AGGREGATE_ARRAY);
|
|
Aggregates.Save_W3D(csave);
|
|
csave.End_Chunk();
|
|
}
|
|
return WW3D_ERROR_OK;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodDefClass::Load_W3D -- Loads this HLodDef from a W3d File *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
WW3DErrorType HLodDefClass::Load_W3D(ChunkLoadClass & cload)
|
|
{
|
|
/*
|
|
** First make sure we release any memory in use
|
|
*/
|
|
Free();
|
|
|
|
if (read_header(cload) == FALSE) {
|
|
return WW3D_ERROR_LOAD_FAILED;
|
|
}
|
|
|
|
/*
|
|
** Loop through all the LODs and read the info from its chunk
|
|
*/
|
|
for (int iLOD = 0; iLOD < LodCount; iLOD ++) {
|
|
|
|
/*
|
|
** Open the next chunk, it should be a LOD struct
|
|
*/
|
|
if (!cload.Open_Chunk()) return WW3D_ERROR_LOAD_FAILED;
|
|
|
|
if (cload.Cur_Chunk_ID() != W3D_CHUNK_HLOD_LOD_ARRAY) {
|
|
// ERROR: Expected LOD struct!
|
|
return WW3D_ERROR_LOAD_FAILED;
|
|
}
|
|
|
|
Lod[iLOD].Load_W3D(cload);
|
|
|
|
// Close-out the chunk
|
|
cload.Close_Chunk();
|
|
}
|
|
|
|
/*
|
|
** Parse the rest of the chunks
|
|
*/
|
|
while (cload.Open_Chunk()) {
|
|
switch(cload.Cur_Chunk_ID())
|
|
{
|
|
case W3D_CHUNK_HLOD_AGGREGATE_ARRAY:
|
|
Aggregates.Load_W3D(cload);
|
|
break;
|
|
case W3D_CHUNK_HLOD_PROXY_ARRAY:
|
|
read_proxy_array(cload);
|
|
break;
|
|
}
|
|
cload.Close_Chunk();
|
|
}
|
|
|
|
return WW3D_ERROR_OK;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodDefClass::read_header -- loads the HLodDef header from a W3d file *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
bool HLodDefClass::read_header(ChunkLoadClass & cload)
|
|
{
|
|
/*
|
|
** Open the first chunk, it should be the LOD header
|
|
*/
|
|
if (!cload.Open_Chunk()) return false;
|
|
|
|
if (cload.Cur_Chunk_ID() != W3D_CHUNK_HLOD_HEADER) {
|
|
// ERROR: Expected HLOD Header!
|
|
return false;
|
|
}
|
|
|
|
W3dHLodHeaderStruct header;
|
|
if (cload.Read(&header,sizeof(header)) != sizeof(header)) {
|
|
return false;
|
|
}
|
|
cload.Close_Chunk();
|
|
|
|
// Copy the name into our internal variable
|
|
Name = ::_strdup(header.Name);
|
|
HierarchyTreeName = ::strdup(header.HierarchyName);
|
|
LodCount = header.LodCount;
|
|
Lod = new SubObjectArrayClass[LodCount];
|
|
return true;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodDefClass::read_proxy_array -- load the proxy names *
|
|
* *
|
|
* This function is coded separately from SubObjectArrayClass::Load because we are going *
|
|
* to store the proxies in a shared data structure. Because all of the proxy data is *
|
|
* constant, each instanced HLOD can just add-ref a pointer to its proxy array. *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 10/27/2000 gth : Created. *
|
|
*=============================================================================================*/
|
|
bool HLodDefClass::read_proxy_array(ChunkLoadClass & cload)
|
|
{
|
|
REF_PTR_RELEASE(ProxyArray);
|
|
|
|
/*
|
|
** Open the first chunk, it should be a Lod Array Header
|
|
*/
|
|
if (!cload.Open_Chunk()) return false;
|
|
if (cload.Cur_Chunk_ID() != W3D_CHUNK_HLOD_SUB_OBJECT_ARRAY_HEADER) return false;
|
|
|
|
W3dHLodArrayHeaderStruct header;
|
|
if (cload.Read(&header,sizeof(header)) != sizeof(header)) return false;
|
|
|
|
if (!cload.Close_Chunk()) return false;
|
|
|
|
ProxyArray = NEW_REF(ProxyArrayClass,(header.ModelCount));
|
|
|
|
/*
|
|
** Read each sub object definition
|
|
*/
|
|
for (int imodel=0; imodel<ProxyArray->Length(); ++imodel) {
|
|
if (!cload.Open_Chunk()) return false;
|
|
if (cload.Cur_Chunk_ID() != W3D_CHUNK_HLOD_SUB_OBJECT) return false;
|
|
|
|
W3dHLodSubObjectStruct subobjdef;
|
|
if (cload.Read(&subobjdef,sizeof(subobjdef)) != sizeof(subobjdef)) return false;
|
|
if (!cload.Close_Chunk()) return false;
|
|
|
|
(*ProxyArray)[imodel].Init(subobjdef);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodDefClass::SubObjectArrayClass::SubObjectArrayClass -- LodArray constructor *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
*=============================================================================================*/
|
|
HLodDefClass::SubObjectArrayClass::SubObjectArrayClass(void) :
|
|
MaxScreenSize(NO_MAX_SCREEN_SIZE),
|
|
ModelCount(0),
|
|
ModelName(NULL),
|
|
BoneIndex(NULL)
|
|
{
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodDefClass::SubObjectArrayClass::~SubObjectArrayClass -- LodArray destructor *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
HLodDefClass::SubObjectArrayClass::~SubObjectArrayClass(void)
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodDefClass::SubObjectArrayClass::Reset -- release the contents of this array *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 10/25/2000 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodDefClass::SubObjectArrayClass::Reset(void)
|
|
{
|
|
MaxScreenSize = NO_MAX_SCREEN_SIZE;
|
|
|
|
if (ModelName != NULL) {
|
|
for (int imodel=0; imodel<ModelCount;imodel++) {
|
|
free(ModelName[imodel]);
|
|
}
|
|
delete[] ModelName;
|
|
ModelName = NULL;
|
|
}
|
|
if (BoneIndex != NULL) {
|
|
delete[] BoneIndex;
|
|
BoneIndex = NULL;
|
|
}
|
|
|
|
ModelCount = 0;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodDefClass::SubObjectArrayClass::Load_W3D -- LodArray load function *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
bool HLodDefClass::SubObjectArrayClass::Load_W3D(ChunkLoadClass & cload)
|
|
{
|
|
/*
|
|
** Open the first chunk, it should be a Lod Array Header
|
|
*/
|
|
if (!cload.Open_Chunk()) return false;
|
|
if (cload.Cur_Chunk_ID() != W3D_CHUNK_HLOD_SUB_OBJECT_ARRAY_HEADER) return false;
|
|
|
|
W3dHLodArrayHeaderStruct header;
|
|
if (cload.Read(&header,sizeof(header)) != sizeof(header)) return false;
|
|
|
|
if (!cload.Close_Chunk()) return false;
|
|
|
|
ModelCount = header.ModelCount;
|
|
MaxScreenSize = header.MaxScreenSize;
|
|
ModelName = new char * [ModelCount];
|
|
BoneIndex = new int [ModelCount];
|
|
|
|
/*
|
|
** Read each sub object definition
|
|
*/
|
|
for (int imodel=0; imodel<ModelCount; ++imodel) {
|
|
if (!cload.Open_Chunk()) return false;
|
|
if (cload.Cur_Chunk_ID() != W3D_CHUNK_HLOD_SUB_OBJECT) return false;
|
|
|
|
W3dHLodSubObjectStruct subobjdef;
|
|
if (cload.Read(&subobjdef,sizeof(subobjdef)) != sizeof(subobjdef)) return false;
|
|
|
|
if (!cload.Close_Chunk()) return false;
|
|
|
|
ModelName[imodel] = strdup(subobjdef.Name);
|
|
BoneIndex[imodel] = subobjdef.BoneIndex;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/***********************************************************************************************
|
|
* HLodDefClass::SubObjectArrayClass::Save_W3D -- saves a w3d file for this HLodDef *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
bool HLodDefClass::SubObjectArrayClass::Save_W3D(ChunkSaveClass &csave)
|
|
{
|
|
// Assume error
|
|
bool ret_val = false;
|
|
|
|
// Begin a chunk that identifies the LOD array
|
|
if (csave.Begin_Chunk (W3D_CHUNK_HLOD_LOD_ARRAY) == TRUE) {
|
|
|
|
// Begin a chunk that identifies the LOD header
|
|
if (csave.Begin_Chunk (W3D_CHUNK_HLOD_SUB_OBJECT_ARRAY_HEADER) == TRUE) {
|
|
|
|
W3dHLodArrayHeaderStruct header = { 0 };
|
|
header.ModelCount = ModelCount;
|
|
header.MaxScreenSize = MaxScreenSize;
|
|
|
|
// Write the LOD header structure out to the chunk
|
|
ret_val = (csave.Write (&header, sizeof (header)) == sizeof (header));
|
|
|
|
// End the header chunk
|
|
csave.End_Chunk ();
|
|
}
|
|
|
|
if (ret_val) {
|
|
|
|
// Write all of this LOD's models to the file
|
|
for (int index = 0;
|
|
(index < ModelCount) && ret_val;
|
|
index ++) {
|
|
|
|
// Save this LOD sub-obj to the chunk
|
|
ret_val &= (csave.Begin_Chunk (W3D_CHUNK_HLOD_SUB_OBJECT) == TRUE);
|
|
if (ret_val) {
|
|
|
|
W3dHLodSubObjectStruct info = { 0 };
|
|
info.BoneIndex = BoneIndex[index];
|
|
|
|
// Copy this model name into the structure
|
|
::lstrcpyn (info.Name, ModelName[index], sizeof (info.Name));
|
|
info.Name[sizeof (info.Name) - 1] = 0;
|
|
|
|
// Write the LOD sub-obj structure out to the chunk
|
|
ret_val &= (csave.Write (&info, sizeof (info)) == sizeof (info));
|
|
|
|
// End the sub-obj chunk
|
|
csave.End_Chunk ();
|
|
}
|
|
}
|
|
}
|
|
|
|
// End the HLOD-Array chunk
|
|
csave.End_Chunk ();
|
|
}
|
|
|
|
// Return the true/false result code
|
|
return ret_val;
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::HLodClass -- Constructor *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
*=============================================================================================*/
|
|
HLodClass::HLodClass(void) :
|
|
Animatable3DObjClass(NULL),
|
|
LodCount(0),
|
|
CurLod(0),
|
|
Lod(NULL),
|
|
BoundingBoxIndex(-1),
|
|
Cost(NULL),
|
|
Value(NULL),
|
|
AdditionalModels(),
|
|
SnapPoints(NULL),
|
|
ProxyArray(NULL),
|
|
LODBias(1.0f)
|
|
{
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::HLodClass -- copy constructor *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
HLodClass::HLodClass(const HLodClass & src) :
|
|
Animatable3DObjClass(src),
|
|
LodCount(0),
|
|
CurLod(0),
|
|
Lod(NULL),
|
|
BoundingBoxIndex(-1),
|
|
Cost(NULL),
|
|
Value(NULL),
|
|
AdditionalModels(),
|
|
SnapPoints(NULL),
|
|
ProxyArray(NULL),
|
|
LODBias(1.0f)
|
|
{
|
|
*this = src;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::HLodClass -- Constructor *
|
|
* *
|
|
* Creates an HLodClass from an array of render objects. Each render object is assumed to *
|
|
* be an alternate level of detail. *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
HLodClass::HLodClass(const char * name,RenderObjClass ** lods,int count) :
|
|
Animatable3DObjClass(NULL),
|
|
LodCount(0),
|
|
CurLod(0),
|
|
Lod(NULL),
|
|
BoundingBoxIndex(-1),
|
|
Cost(NULL),
|
|
Value(NULL),
|
|
AdditionalModels(),
|
|
SnapPoints(NULL),
|
|
ProxyArray(NULL),
|
|
LODBias(1.0f)
|
|
{
|
|
// enforce parameters
|
|
WWASSERT(name != NULL);
|
|
WWASSERT(lods != NULL);
|
|
WWASSERT((count > 0) && (count < 256));
|
|
|
|
// Set the name
|
|
Set_Name(name);
|
|
|
|
LodCount = count;
|
|
WWASSERT(LodCount >= 1);
|
|
Lod = new ModelArrayClass[LodCount];
|
|
WWASSERT(Lod);
|
|
Cost = new float[LodCount];
|
|
WWASSERT(Cost);
|
|
// Value has LodCount + 1 entries so PostIncrementValue can always use
|
|
// Value[CurLod + 1] (the last entry wil be AT_MAX_LOD).
|
|
Value = new float[LodCount + 1];
|
|
WWASSERT(Value);
|
|
|
|
// Create our HTree from the highest LOD if it is an HModel
|
|
// Otherwise, create a single node tree
|
|
const HTreeClass * tree = lods[count-1]->Get_HTree();
|
|
if (tree != NULL) {
|
|
HTree = new HTreeClass(*tree);
|
|
} else {
|
|
HTree = new HTreeClass();
|
|
HTree->Init_Default();
|
|
}
|
|
|
|
// Ok, now suck the sub-objects out of each LOD model and place them into this HLOD.
|
|
for (int lod_index=0; lod_index < LodCount; lod_index++) {
|
|
RenderObjClass * lod_obj = lods[lod_index];
|
|
WWASSERT(lod_obj);
|
|
|
|
if ( (lod_obj->Class_ID() == RenderObjClass::CLASSID_HMODEL) ||
|
|
(lod_obj->Class_ID() == RenderObjClass::CLASSID_HLOD) ||
|
|
(lod_obj->Get_Num_Sub_Objects() > 1) ) {
|
|
|
|
// here we insert all sub-objects of this render object into the current LOD array
|
|
while (lod_obj->Get_Num_Sub_Objects() > 0) {
|
|
|
|
RenderObjClass * sub_obj = lod_obj->Get_Sub_Object(0);
|
|
int boneindex = lod_obj->Get_Sub_Object_Bone_Index(sub_obj);
|
|
lod_obj->Remove_Sub_Object(sub_obj);
|
|
|
|
add_lod_model(lod_index,sub_obj,boneindex);
|
|
|
|
sub_obj->Release_Ref();
|
|
}
|
|
|
|
} else {
|
|
|
|
// just insert the render object as the sole member of the current LOD array. This
|
|
// case happens if this level of detail is a simple object such as a mesh or NullRenderObj
|
|
add_lod_model(lod_index,lod_obj,0);
|
|
}
|
|
}
|
|
|
|
Recalculate_Static_LOD_Factors();
|
|
|
|
// So that the object is ready for use after construction, we will
|
|
// complete its initialization by initializing its cost and value arrays
|
|
// according to a screen area of 1 pixel.
|
|
int minlod = Calculate_Cost_Value_Arrays(1.0f, Value, Cost);
|
|
|
|
// Ensure lod is no less than minimum allowed
|
|
if (CurLod < minlod) Set_LOD_Level(minlod);
|
|
|
|
// Flag our sub-objects as having dirty transforms
|
|
Set_Sub_Object_Transforms_Dirty(true);
|
|
|
|
// Normal render object processing whenever sub-objects are added or removed:
|
|
Update_Sub_Object_Bits();
|
|
Update_Obj_Space_Bounding_Volumes();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::HLodClass -- Constructs an HLod from an HLodDef *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
HLodClass::HLodClass(const HLodDefClass & def) :
|
|
Animatable3DObjClass(def.HierarchyTreeName),
|
|
LodCount(0),
|
|
CurLod(0),
|
|
Lod(NULL),
|
|
BoundingBoxIndex(-1),
|
|
Cost(NULL),
|
|
Value(NULL),
|
|
AdditionalModels(),
|
|
SnapPoints(NULL),
|
|
ProxyArray(NULL),
|
|
LODBias(1.0f)
|
|
{
|
|
// Set the name
|
|
Set_Name(def.Get_Name());
|
|
|
|
// Number of LODs comes from the distlod
|
|
LodCount = def.LodCount;
|
|
WWASSERT(LodCount >= 1);
|
|
Lod = new ModelArrayClass[LodCount];
|
|
WWASSERT(Lod);
|
|
Cost = new float[LodCount];
|
|
WWASSERT(Cost);
|
|
// Value has LodCount + 1 entries so PostIncrementValue can always use
|
|
// Value[CurLod + 1] (the last entry wil be AT_MAX_LOD).
|
|
Value = new float[LodCount + 1];
|
|
WWASSERT(Value);
|
|
|
|
// Add Models to the ModelArrays
|
|
for (int ilod=0; ilod < def.LodCount; ilod++) {
|
|
|
|
Lod[ilod].MaxScreenSize = def.Lod[ilod].MaxScreenSize;
|
|
|
|
for (int imodel=0; imodel < def.Lod[ilod].ModelCount; imodel++) {
|
|
|
|
RenderObjClass * robj = WW3DAssetManager::Get_Instance()->Create_Render_Obj(def.Lod[ilod].ModelName[imodel]);
|
|
int boneindex = def.Lod[ilod].BoneIndex[imodel];
|
|
if (robj != NULL) {
|
|
add_lod_model(ilod,robj,boneindex);
|
|
robj->Release_Ref();
|
|
}
|
|
}
|
|
}
|
|
|
|
Recalculate_Static_LOD_Factors();
|
|
|
|
// Add aggregates to this model
|
|
for (int iagg=0; iagg<def.Aggregates.ModelCount; iagg++) {
|
|
RenderObjClass * robj = WW3DAssetManager::Get_Instance()->Create_Render_Obj(def.Aggregates.ModelName[iagg]);
|
|
int boneindex = def.Aggregates.BoneIndex[iagg];
|
|
if (robj != NULL) {
|
|
Add_Sub_Object_To_Bone(robj,boneindex);
|
|
robj->Release_Ref();
|
|
}
|
|
}
|
|
|
|
// Add a reference to the proxy array
|
|
REF_PTR_SET(ProxyArray,def.ProxyArray);
|
|
|
|
// So that the object is ready for use after construction, we will
|
|
// complete its initialization by initializing its cost and value arrays
|
|
// according to a screen area of 1 pixel.
|
|
int minlod = Calculate_Cost_Value_Arrays(1.0f, Value, Cost);
|
|
|
|
// Ensure lod is no less than minimum allowed
|
|
if (CurLod < minlod) Set_LOD_Level(minlod);
|
|
|
|
// Flag our sub-objects as having dirty transforms
|
|
Set_Sub_Object_Transforms_Dirty(true);
|
|
|
|
Update_Sub_Object_Bits();
|
|
Update_Obj_Space_Bounding_Volumes();
|
|
return ;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::HLodClass -- Constructs an HLod from an HModelDef *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
HLodClass::HLodClass(const HModelDefClass & def) :
|
|
Animatable3DObjClass(def.BasePoseName),
|
|
LodCount(0),
|
|
CurLod(0),
|
|
Lod(NULL),
|
|
BoundingBoxIndex(-1),
|
|
Cost(NULL),
|
|
Value(NULL),
|
|
AdditionalModels(),
|
|
SnapPoints(NULL),
|
|
ProxyArray(NULL),
|
|
LODBias(1.0f)
|
|
{
|
|
// Set the name
|
|
Set_Name(def.Get_Name());
|
|
|
|
// This is a "simple" HLod, only one LOD
|
|
LodCount = 1;
|
|
Lod = new ModelArrayClass[1];
|
|
WWASSERT(Lod);
|
|
Cost = new float[1];
|
|
WWASSERT(Cost);
|
|
// Value has LodCount + 1 entries so PostIncrementValue can always use
|
|
// Value[CurLod + 1] (the last entry wil be AT_MAX_LOD).
|
|
Value = new float[2];
|
|
WWASSERT(Value);
|
|
|
|
// no lod size clamping
|
|
Lod[0].MaxScreenSize = NO_MAX_SCREEN_SIZE;
|
|
|
|
// create the sub-objects
|
|
int imodel;
|
|
for (imodel=0; imodel < def.SubObjectCount; ++imodel) {
|
|
RenderObjClass * robj = WW3DAssetManager::Get_Instance()->Create_Render_Obj(def.SubObjects[imodel].RenderObjName);
|
|
if (robj) {
|
|
int boneindex = def.SubObjects[imodel].PivotID;
|
|
add_lod_model(0,robj,boneindex);
|
|
robj->Release_Ref();
|
|
}
|
|
}
|
|
|
|
Recalculate_Static_LOD_Factors();
|
|
|
|
// So that the object is ready for use after construction, we will
|
|
// complete its initialization by initializing its cost and value arrays
|
|
// according to a screen area of 1 pixel.
|
|
int minlod = Calculate_Cost_Value_Arrays(1.0f, Value, Cost);
|
|
|
|
// Ensure lod is no less than minimum allowed
|
|
if (CurLod < minlod) Set_LOD_Level(minlod);
|
|
|
|
// Flag our sub-objects as having dirty transforms
|
|
Set_Sub_Object_Transforms_Dirty(true);
|
|
|
|
Update_Sub_Object_Bits();
|
|
Update_Obj_Space_Bounding_Volumes();
|
|
return ;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::operator -- assignment operator *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
HLodClass & HLodClass::operator = (const HLodClass & that)
|
|
{
|
|
int lod,model;
|
|
|
|
if (this != &that) {
|
|
Free();
|
|
Animatable3DObjClass::operator = (that);
|
|
BoundingBoxIndex = that.BoundingBoxIndex;
|
|
|
|
LodCount = that.LodCount;
|
|
WWASSERT(LodCount >= 1);
|
|
|
|
Lod = new ModelArrayClass[LodCount];
|
|
WWASSERT(Lod != NULL);
|
|
Cost = new float[LodCount];
|
|
WWASSERT(Cost);
|
|
// Value has LodCount + 1 entries so PostIncrementValue can always use
|
|
// Value[CurLod + 1] (the last entry wil be AT_MAX_LOD).
|
|
Value = new float[LodCount + 1];
|
|
WWASSERT(Value);
|
|
|
|
for (lod=0; lod<LodCount;lod++) {
|
|
Lod[lod].Resize(that.Lod[lod].Count());
|
|
Lod[lod].MaxScreenSize = that.Lod[lod].MaxScreenSize;
|
|
|
|
for (model = 0; model < that.Lod[lod].Count(); model++) {
|
|
|
|
ModelNodeClass newnode;
|
|
newnode.Model = that.Lod[lod][model].Model->Clone();
|
|
newnode.BoneIndex = that.Lod[lod][model].BoneIndex;
|
|
newnode.Model->Set_Container(this);
|
|
if (Is_In_Scene()) {
|
|
newnode.Model->Notify_Added(Scene);
|
|
}
|
|
|
|
Lod[lod].Add(newnode);
|
|
}
|
|
}
|
|
|
|
AdditionalModels.Resize(that.AdditionalModels.Count());
|
|
for (model = 0; model < that.AdditionalModels.Count(); model++) {
|
|
|
|
ModelNodeClass newnode;
|
|
newnode.Model = that.AdditionalModels[model].Model->Clone();
|
|
newnode.BoneIndex = that.AdditionalModels[model].BoneIndex;
|
|
newnode.Model->Set_Container(this);
|
|
if (Is_In_Scene()) {
|
|
newnode.Model->Notify_Added(Scene);
|
|
}
|
|
|
|
AdditionalModels.Add(newnode);
|
|
}
|
|
|
|
LODBias = that.LODBias;
|
|
}
|
|
|
|
Recalculate_Static_LOD_Factors();
|
|
|
|
|
|
// So that the object is ready for use after construction, we will
|
|
// complete its initialization by initializing its cost and value arrays
|
|
// according to a screen area of 1 pixel.
|
|
int minlod = Calculate_Cost_Value_Arrays(1.0f, Value, Cost);
|
|
|
|
// Ensure lod is no less than minimum allowed
|
|
if (CurLod < minlod) Set_LOD_Level(minlod);
|
|
|
|
// Flag our sub-objects as having dirty transforms
|
|
Set_Sub_Object_Transforms_Dirty(true);
|
|
|
|
Update_Sub_Object_Bits();
|
|
Update_Obj_Space_Bounding_Volumes();
|
|
return *this;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::~HLodClass -- Destructor *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
HLodClass::~HLodClass(void)
|
|
{
|
|
Free();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Free -- releases all resources *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Free(void)
|
|
{
|
|
int lod,model;
|
|
|
|
for (lod = 0; lod < LodCount; lod++) {
|
|
for (model = 0; model < Lod[lod].Count(); model++) {
|
|
|
|
RenderObjClass * robj = Lod[lod][model].Model;
|
|
Lod[lod][model].Model = NULL;
|
|
|
|
WWASSERT(robj);
|
|
robj->Set_Container(NULL);
|
|
robj->Release_Ref();
|
|
|
|
}
|
|
|
|
Lod[lod].Delete_All();
|
|
}
|
|
if (Lod != NULL) {
|
|
delete[] Lod;
|
|
Lod = NULL;
|
|
}
|
|
LodCount = 0;
|
|
|
|
if (Cost != NULL) {
|
|
delete[] Cost;
|
|
Cost = NULL;
|
|
}
|
|
if (Value != NULL) {
|
|
delete[] Value;
|
|
Value = NULL;
|
|
}
|
|
|
|
for (model = 0; model < AdditionalModels.Count(); model++) {
|
|
RenderObjClass * robj = AdditionalModels[model].Model;
|
|
AdditionalModels[model].Model = NULL;
|
|
|
|
WWASSERT(robj);
|
|
robj->Set_Container(NULL);
|
|
robj->Release_Ref();
|
|
}
|
|
AdditionalModels.Delete_All();
|
|
|
|
REF_PTR_RELEASE(SnapPoints);
|
|
REF_PTR_RELEASE(ProxyArray);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Clone -- virtual copy constructor *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
RenderObjClass * HLodClass::Clone(void) const
|
|
{
|
|
return new HLodClass(*this);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Get_Obj_Space_Bounding_Box -- Return the bounding box mesh if we have one. *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 4/13/00 pds : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Get_Obj_Space_Bounding_Box(AABoxClass & box) const
|
|
{
|
|
//
|
|
// Do we have a bounding box mesh?
|
|
//
|
|
int count = Lod[LodCount - 1].Count ();
|
|
if (BoundingBoxIndex >= 0 && BoundingBoxIndex < count) {
|
|
|
|
RenderObjClass *mesh = Lod[LodCount - 1][BoundingBoxIndex].Model;
|
|
if (mesh != NULL && mesh->Class_ID () == RenderObjClass::CLASSID_OBBOX) {
|
|
|
|
OBBoxRenderObjClass *obbox_mesh = (OBBoxRenderObjClass *)mesh;
|
|
|
|
//
|
|
// Determine what the box's transform 'should' be this frame.
|
|
// Note: We do this because some animation types don't update
|
|
// unless they are visible.
|
|
//
|
|
Matrix3D box_tm;
|
|
Simple_Evaluate_Bone (Lod[LodCount - 1][BoundingBoxIndex].BoneIndex, &box_tm);
|
|
|
|
//
|
|
// Convert the OBBox from its coordinate system to the coordinate
|
|
// system of the HLOD.
|
|
//
|
|
Matrix3D world_to_hlod_tm;
|
|
Matrix3D box_to_hlod_tm;
|
|
|
|
Get_Transform ().Get_Orthogonal_Inverse (world_to_hlod_tm);
|
|
Matrix3D::Multiply(world_to_hlod_tm,box_tm,&box_to_hlod_tm);
|
|
|
|
box_to_hlod_tm.Transform_Center_Extent_AABox( obbox_mesh->Get_Local_Center(),
|
|
obbox_mesh->Get_Local_Extent(),
|
|
&box.Center,&box.Extent);
|
|
}
|
|
|
|
} else {
|
|
Animatable3DObjClass::Get_Obj_Space_Bounding_Box (box);
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Get_Obj_Space_Bounding_Sphere -- Use the bounding box mesh to calculate a sphere.*
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 4/13/00 pds : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const
|
|
{
|
|
AABoxClass box;
|
|
Get_Obj_Space_Bounding_Box(box);
|
|
sphere.Center = box.Center;
|
|
sphere.Radius = box.Extent.Length();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Get_Obj_Space_Bounding_Sphere -- Use the bounding box mesh to calculate a sphere.*
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 4/13/00 pds : Created. *
|
|
*=============================================================================================*/
|
|
const SphereClass &HLodClass::Get_Bounding_Sphere(void) const
|
|
{
|
|
if (BoundingBoxIndex >= 0) {
|
|
//
|
|
// Get the bounding sphere in local coordinates
|
|
//
|
|
SphereClass sphere;
|
|
Get_Obj_Space_Bounding_Sphere (sphere);
|
|
|
|
//
|
|
// Transform the sphere into world coords and return the sphere
|
|
//
|
|
CachedBoundingSphere.Center = Get_Transform () * sphere.Center;
|
|
CachedBoundingSphere.Radius = sphere.Radius;
|
|
} else {
|
|
Animatable3DObjClass::Get_Bounding_Sphere ();
|
|
}
|
|
|
|
return CachedBoundingSphere;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Get_Obj_Space_Bounding_Box -- Return the bounding box mesh if we have one. *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 4/13/00 pds : Created. *
|
|
*=============================================================================================*/
|
|
const AABoxClass &HLodClass::Get_Bounding_Box(void) const
|
|
{
|
|
if (BoundingBoxIndex >= 0) {
|
|
|
|
//
|
|
// Get the bounding box in local coordinates
|
|
//
|
|
AABoxClass box;
|
|
Get_Obj_Space_Bounding_Box (box);
|
|
|
|
//
|
|
// Transform the bounding box to world coordinates
|
|
//
|
|
Get_Transform().Transform_Center_Extent_AABox( box.Center,
|
|
box.Extent,
|
|
&CachedBoundingBox.Center,
|
|
&CachedBoundingBox.Extent );
|
|
} else {
|
|
Animatable3DObjClass::Get_Bounding_Box ();
|
|
}
|
|
|
|
return CachedBoundingBox;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Set_Max_Screen_Size -- Set max-screen-size for an LOD *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Set_Max_Screen_Size(int lod_index, float size)
|
|
{
|
|
// Params valid?
|
|
WWASSERT(lod_index >= 0);
|
|
WWASSERT(lod_index < LodCount);
|
|
if ((lod_index >= 0) && (lod_index < LodCount)) {
|
|
|
|
// Set the new screen size for this LOD
|
|
Lod[lod_index].MaxScreenSize = size;
|
|
|
|
Recalculate_Static_LOD_Factors();
|
|
|
|
// So that the object is ready for use after construction, we will
|
|
// complete its initialization by initializing its cost and value arrays
|
|
// according to a screen area of 1 pixel.
|
|
int minlod = Calculate_Cost_Value_Arrays(1.0f, Value, Cost);
|
|
|
|
// Ensure lod is no less than minimum allowed
|
|
if (CurLod < minlod) Set_LOD_Level(minlod);
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Get_Max_Screen_Size -- get max-screen-size for an LOD *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
float HLodClass::Get_Max_Screen_Size(int lod_index) const
|
|
{
|
|
float size = NO_MAX_SCREEN_SIZE;
|
|
|
|
// Params valid?
|
|
WWASSERT(lod_index >= 0);
|
|
WWASSERT(lod_index < LodCount);
|
|
if ((lod_index >= 0) && (lod_index < LodCount)) {
|
|
|
|
// Get the screen size for this LOD
|
|
size = Lod[lod_index].MaxScreenSize;
|
|
}
|
|
|
|
// Return the LOD's screen size to the caller
|
|
return size;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Get_Lod_Count -- returns number of levels of detail *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
int HLodClass::Get_Lod_Count(void) const
|
|
{
|
|
return LodCount;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Set_LOD_Bias -- sets LOD bias *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 2/08/00 nh : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Set_LOD_Bias(float bias)
|
|
{
|
|
assert(bias > 0.0f);
|
|
bias = MAX(bias, 0.0f);
|
|
LODBias = bias;
|
|
|
|
int additional_count = AdditionalModels.Count();
|
|
for (int i = 0; i < additional_count; i++) {
|
|
AdditionalModels[i].Model->Set_LOD_Bias(bias);
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Get_Lod_Model_Count -- number of sub-objs in a given level of detail *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
int HLodClass::Get_Lod_Model_Count(int lod_index) const
|
|
{
|
|
int count = 0;
|
|
|
|
// Params valid?
|
|
WWASSERT(lod_index >= 0);
|
|
WWASSERT(lod_index < LodCount);
|
|
if ((lod_index >= 0) && (lod_index < LodCount)) {
|
|
|
|
// Get the number of models in this Lod
|
|
count = Lod[lod_index].Count ();
|
|
}
|
|
|
|
// Return the number of models that compose this Lod
|
|
return count;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Peek_Lod_Model -- returns pointer to a model in one of the LODs *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
RenderObjClass *HLodClass::Peek_Lod_Model(int lod_index, int model_index) const
|
|
{
|
|
RenderObjClass *pmodel = NULL;
|
|
|
|
// Params valid?
|
|
WWASSERT(lod_index >= 0);
|
|
WWASSERT(lod_index < LodCount);
|
|
if ((lod_index >= 0) &&
|
|
(lod_index < LodCount) &&
|
|
(model_index < Lod[lod_index].Count ())) {
|
|
|
|
// Get a pointer to the requested model
|
|
pmodel = Lod[lod_index][model_index].Model;
|
|
}
|
|
|
|
// Return a pointer to the requested model
|
|
return pmodel;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Get_Lod_Model -- returns a pointer to a model in one of the LODs *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
RenderObjClass *HLodClass::Get_Lod_Model(int lod_index, int model_index) const
|
|
{
|
|
RenderObjClass *pmodel = NULL;
|
|
|
|
// Params valid?
|
|
WWASSERT(lod_index >= 0);
|
|
WWASSERT(lod_index < LodCount);
|
|
if ((lod_index >= 0) &&
|
|
(lod_index < LodCount) &&
|
|
(model_index < Lod[lod_index].Count ())) {
|
|
|
|
// Get a pointer to the requested model
|
|
pmodel = Lod[lod_index][model_index].Model;
|
|
if (pmodel != NULL) {
|
|
pmodel->Add_Ref ();
|
|
}
|
|
}
|
|
|
|
// Return the number of models that compose this Lod
|
|
return pmodel;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Get_Lod_Model_Bone -- returns the bone index of a model *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
int HLodClass::Get_Lod_Model_Bone(int lod_index, int model_index) const
|
|
{
|
|
int bone_index = 0;
|
|
|
|
// Params valid?
|
|
WWASSERT(lod_index >= 0);
|
|
WWASSERT(lod_index < LodCount);
|
|
if ((lod_index >= 0) &&
|
|
(lod_index < LodCount) &&
|
|
(model_index < Lod[lod_index].Count ())) {
|
|
|
|
// Get the bone that this model resides on
|
|
bone_index = Lod[lod_index][model_index].BoneIndex;
|
|
}
|
|
|
|
// Return the bone that this model resides on
|
|
return bone_index;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Get_Additional_Model_Count -- number of additional sub-objs *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 8/23/00 NH : Created. *
|
|
*=============================================================================================*/
|
|
int HLodClass::Get_Additional_Model_Count(void) const
|
|
{
|
|
return AdditionalModels.Count();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Peek_Additional_Model -- returns pointer to an additional model *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 8/23/00 NH : Created. *
|
|
*=============================================================================================*/
|
|
RenderObjClass * HLodClass::Peek_Additional_Model (int model_index) const
|
|
{
|
|
RenderObjClass *pmodel = NULL;
|
|
|
|
// Param valid?
|
|
WWASSERT(model_index >= 0);
|
|
WWASSERT(model_index < AdditionalModels.Count());
|
|
if ((model_index >= 0) &&
|
|
(model_index < AdditionalModels.Count())) {
|
|
|
|
// Get a pointer to the requested model
|
|
pmodel = AdditionalModels[model_index].Model;
|
|
}
|
|
|
|
// Return a pointer to the requested model
|
|
return pmodel;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Get_Additional_Model -- returns pointer to an additional model *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 8/23/00 NH : Created. *
|
|
*=============================================================================================*/
|
|
RenderObjClass * HLodClass::Get_Additional_Model (int model_index) const
|
|
{
|
|
RenderObjClass *pmodel = NULL;
|
|
|
|
// Param valid?
|
|
WWASSERT(model_index >= 0);
|
|
WWASSERT(model_index < AdditionalModels.Count());
|
|
if ((model_index >= 0) &&
|
|
(model_index < AdditionalModels.Count())) {
|
|
|
|
// Get a pointer to the requested model
|
|
pmodel = AdditionalModels[model_index].Model;
|
|
if (pmodel != NULL) {
|
|
pmodel->Add_Ref ();
|
|
}
|
|
}
|
|
|
|
// Return a pointer to the requested model
|
|
return pmodel;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Get_Additional_Model_Bone -- returns the bone index of an additional model *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 8/23/00 NH : Created. *
|
|
*=============================================================================================*/
|
|
int HLodClass::Get_Additional_Model_Bone (int model_index) const
|
|
{
|
|
int bone_index = 0;
|
|
|
|
// Params valid?
|
|
WWASSERT(model_index >= 0);
|
|
WWASSERT(model_index < AdditionalModels.Count());
|
|
if ((model_index >= 0) &&
|
|
(model_index < AdditionalModels.Count())) {
|
|
|
|
// Get the bone that this model resides on
|
|
bone_index = AdditionalModels[model_index].BoneIndex;
|
|
}
|
|
|
|
// Return the bone that this model resides on
|
|
return bone_index;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Is_NULL_Lod_Included -- does this HLod have NULL as its lowest LOD *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
bool HLodClass::Is_NULL_Lod_Included(void) const
|
|
{
|
|
bool included = false;
|
|
|
|
// Determine if the lowest-level LOD is the null render object or not...
|
|
if ((LodCount > 0) && (Lod[0][0].Model != NULL)) {
|
|
included = (Lod[0][0].Model->Class_ID () == RenderObjClass::CLASSID_NULL);
|
|
}
|
|
|
|
// Return the true/false result code
|
|
return included;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Include_NULL_Lod -- Add NULL as the lowest LOD *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Include_NULL_Lod(bool include)
|
|
{
|
|
if ((include == false) && Is_NULL_Lod_Included ()) {
|
|
|
|
// Free the 'NULL' object's stored information
|
|
int index = 0;
|
|
for (int model = 0; model < Lod[index].Count (); model++) {
|
|
|
|
RenderObjClass * robj = Lod[index][model].Model;
|
|
Lod[index][model].Model = NULL;
|
|
|
|
WWASSERT(robj);
|
|
robj->Set_Container (NULL);
|
|
robj->Release_Ref ();
|
|
}
|
|
|
|
// Resize the lod array
|
|
LodCount -= 1;
|
|
Lod[index].Delete_All ();
|
|
ModelArrayClass *temp_lods = new ModelArrayClass[LodCount];
|
|
for (index = 0; index < LodCount; index ++) {
|
|
temp_lods[index] = Lod[index + 1];
|
|
}
|
|
|
|
// Now resize the value and cost arrays
|
|
float *temp_cost = new float[LodCount];
|
|
float *temp_value = new float[LodCount + 1];
|
|
::memcpy (temp_cost, &Cost[1], sizeof (float) * LodCount);
|
|
::memcpy (temp_value, &Value[1], sizeof (float) * (LodCount + 1));
|
|
|
|
delete [] Lod;
|
|
delete [] Value;
|
|
delete [] Cost;
|
|
Lod = temp_lods;
|
|
Value = temp_value;
|
|
Cost = temp_cost;
|
|
CurLod = (CurLod >= LodCount) ? (LodCount - 1) : CurLod;
|
|
|
|
} else if (include && (Is_NULL_Lod_Included () == false)) {
|
|
|
|
// Tag the NULL render object onto the end
|
|
RenderObjClass *null_object = WW3DAssetManager::Get_Instance ()->Create_Render_Obj ("NULL");
|
|
WWASSERT (null_object != NULL);
|
|
if (null_object != NULL) {
|
|
|
|
// Resize the lod array
|
|
ModelArrayClass *temp_lods = new ModelArrayClass[LodCount + 1];
|
|
for (int index = 0; index < LodCount; index ++) {
|
|
temp_lods[index + 1] = Lod[index];
|
|
}
|
|
|
|
// Now resize the value and cost arrays
|
|
float *temp_cost = new float[LodCount + 1];
|
|
float *temp_value = new float[LodCount + 2];
|
|
::memcpy (&temp_cost[1], Cost, sizeof (float) * LodCount);
|
|
::memcpy (&temp_value[1], Value, sizeof (float) * (LodCount + 1));
|
|
|
|
delete [] Lod;
|
|
delete [] Value;
|
|
delete [] Cost;
|
|
Lod = temp_lods;
|
|
Value = temp_value;
|
|
Cost = temp_cost;
|
|
LodCount ++;
|
|
|
|
// Add this NULL object to the start of the lod list
|
|
add_lod_model (0, null_object, 0);
|
|
null_object->Release_Ref ();
|
|
}
|
|
}
|
|
|
|
// recalculate cost/value arrays and ensure the current LOD is still valid.
|
|
int minlod = Calculate_Cost_Value_Arrays(1.0f, Value, Cost);
|
|
|
|
// Ensure lod is no less than minimum allowed
|
|
if (CurLod < minlod) Set_LOD_Level(minlod);
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Get_Proxy_Count -- Returns the number of proxy records *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 10/27/2000 gth : Created. *
|
|
*=============================================================================================*/
|
|
int HLodClass::Get_Proxy_Count(void) const
|
|
{
|
|
if (ProxyArray != NULL) {
|
|
return ProxyArray->Length();
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Get_Proxy -- returns the information for the i'th proxy *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 10/27/2000 gth : Created. *
|
|
*=============================================================================================*/
|
|
bool HLodClass::Get_Proxy (int index, ProxyClass &proxy) const
|
|
{
|
|
bool retval = false;
|
|
|
|
if (ProxyArray != NULL) {
|
|
|
|
//
|
|
// Lookup the proxy's transform
|
|
//
|
|
HTree->Base_Update(Get_Transform());
|
|
Matrix3D transform = HTree->Get_Transform((*ProxyArray)[index].Get_Bone_Index());
|
|
Set_Hierarchy_Valid(false);
|
|
|
|
//
|
|
// Pass the data onto the proxy object
|
|
//
|
|
proxy.Set_Transform(transform);
|
|
proxy.Set_Name((*ProxyArray)[index].Get_Name());
|
|
retval = true;
|
|
|
|
} else {
|
|
proxy.Set_Name ("");
|
|
proxy.Set_Transform (Matrix3D (1));
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Get_Num_Polys -- returns polycount of the current LOD *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
int HLodClass::Get_Num_Polys(void) const
|
|
{
|
|
int polycount = 0;
|
|
int i;
|
|
int model_count = Lod[CurLod].Count();
|
|
for (i = 0; i < model_count; i++) {
|
|
if (Lod[CurLod][i].Model->Is_Not_Hidden_At_All()) {
|
|
polycount += Lod[CurLod][i].Model->Get_Num_Polys();
|
|
}
|
|
}
|
|
|
|
int additional_count = AdditionalModels.Count();
|
|
for (i = 0; i < additional_count; i++) {
|
|
if (AdditionalModels[i].Model->Is_Not_Hidden_At_All()) {
|
|
polycount += AdditionalModels[i].Model->Get_Num_Polys();
|
|
}
|
|
}
|
|
|
|
return polycount;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Render -- render this HLod *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Render(RenderInfoClass & rinfo)
|
|
{
|
|
int i;
|
|
|
|
if (Is_Not_Hidden_At_All() == false) {
|
|
return;
|
|
}
|
|
|
|
Animatable3DObjClass::Render(rinfo);
|
|
|
|
for (i = 0; i < Lod[CurLod].Count(); i++) {
|
|
Lod[CurLod][i].Model->Render(rinfo);
|
|
}
|
|
|
|
if (Is_Sub_Objects_Match_LOD_Enabled()) {
|
|
for (i = 0; i < AdditionalModels.Count(); i++) {
|
|
AdditionalModels[i].Model->Set_LOD_Level(Get_LOD_Level());
|
|
AdditionalModels[i].Model->Render(rinfo);
|
|
}
|
|
} else {
|
|
for (i = 0; i < AdditionalModels.Count(); i++) {
|
|
AdditionalModels[i].Model->Render(rinfo);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Special_Render -- Special_Render for HLod *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Special_Render(SpecialRenderInfoClass & rinfo)
|
|
{
|
|
int i;
|
|
if (Is_Not_Hidden_At_All() == false) {
|
|
return;
|
|
}
|
|
|
|
Animatable3DObjClass::Special_Render(rinfo);
|
|
|
|
int lod_index = CurLod;
|
|
if (rinfo.RenderType == SpecialRenderInfoClass::RENDER_SHADOW) { // (gth) HACK HACK! yikes
|
|
lod_index = LodCount-1;
|
|
}
|
|
|
|
for (i = 0; i < Lod[lod_index].Count(); i++) {
|
|
Lod[lod_index][i].Model->Special_Render(rinfo);
|
|
}
|
|
|
|
for (i = 0; i < AdditionalModels.Count(); i++) {
|
|
AdditionalModels[i].Model->Special_Render(rinfo);
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Set_Transform -- Sets the transform *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Set_Transform(const Matrix3D &m)
|
|
{
|
|
Animatable3DObjClass::Set_Transform(m);
|
|
Set_Sub_Object_Transforms_Dirty(true);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Set_Position -- Sets the position *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Set_Position(const Vector3 &v)
|
|
{
|
|
Animatable3DObjClass::Set_Position(v);
|
|
Set_Sub_Object_Transforms_Dirty(true);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Notify_Added -- callback notifies subobjs that they were added *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Notify_Added(SceneClass * scene)
|
|
{
|
|
RenderObjClass::Notify_Added(scene);
|
|
int i;
|
|
int model_count = Lod[CurLod].Count();
|
|
for (i = 0; i < model_count; i++) {
|
|
Lod[CurLod][i].Model->Notify_Added(scene);
|
|
}
|
|
|
|
int additional_count = AdditionalModels.Count();
|
|
for (i = 0; i < additional_count; i++) {
|
|
AdditionalModels[i].Model->Notify_Added(scene);
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Notify_Removed -- notifies subobjs that they were removed *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Notify_Removed(SceneClass * scene)
|
|
{
|
|
int i;
|
|
int model_count = Lod[CurLod].Count();
|
|
for (i = 0; i < model_count; i++) {
|
|
Lod[CurLod][i].Model->Notify_Removed(scene);
|
|
}
|
|
|
|
int additional_count = AdditionalModels.Count();
|
|
for (i = 0; i < additional_count; i++) {
|
|
AdditionalModels[i].Model->Notify_Removed(scene);
|
|
}
|
|
RenderObjClass::Notify_Removed(scene);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Get_Num_Sub_Objects -- returns total number of sub-objects *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
int HLodClass::Get_Num_Sub_Objects(void) const
|
|
{
|
|
int count = 0;
|
|
for (int lod=0; lod<LodCount;lod++) {
|
|
count += Lod[lod].Count();
|
|
}
|
|
count += AdditionalModels.Count();
|
|
return count;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Get_Sub_Object -- returns a pointer to specified sub-object *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
RenderObjClass * HLodClass::Get_Sub_Object(int index) const
|
|
{
|
|
WWASSERT(index >= 0);
|
|
for (int lod=0; lod<LodCount; lod++) {
|
|
if (index < Lod[lod].Count()) {
|
|
Lod[lod][index].Model->Add_Ref();
|
|
return Lod[lod][index].Model;
|
|
}
|
|
index -= Lod[lod].Count();
|
|
}
|
|
WWASSERT(index < AdditionalModels.Count());
|
|
AdditionalModels[index].Model->Add_Ref();
|
|
return AdditionalModels[index].Model;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Add_Sub_Object -- add a sub-object to this HLod *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
int HLodClass::Add_Sub_Object(RenderObjClass * subobj)
|
|
{
|
|
return Add_Sub_Object_To_Bone(subobj,0);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Remove_Sub_Object -- remove a sub-object from this HLod *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
int HLodClass::Remove_Sub_Object(RenderObjClass * removeme)
|
|
{
|
|
// no object given?
|
|
if (removeme == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
// find the sub-object
|
|
bool found = false;
|
|
bool iscurrent = false;
|
|
|
|
for (int lod = 0; (lod < LodCount) && (!found); lod++) {
|
|
for (int model = 0; (model < Lod[lod].Count()) && (!found); model++) {
|
|
|
|
if (Lod[lod][model].Model == removeme) {
|
|
|
|
// remove the model from the array.
|
|
Lod[lod].Delete(model);
|
|
|
|
// record that we found it
|
|
found = true;
|
|
|
|
if (lod == CurLod) {
|
|
iscurrent = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int model = 0; (model < AdditionalModels.Count()) && (!found); model++) {
|
|
if (AdditionalModels[model].Model == removeme) {
|
|
AdditionalModels.Delete(model);
|
|
found = true;
|
|
iscurrent = true;
|
|
}
|
|
}
|
|
|
|
if (found) {
|
|
|
|
// clear the object's container pointer
|
|
removeme->Set_Container(NULL);
|
|
|
|
// let him know in case he is removed from the scene as a result of this
|
|
// this is the combination of this HLod being in the scene and and this model
|
|
// either being in the current LOD or being in the additional model list...
|
|
if (iscurrent && Is_In_Scene()) {
|
|
removeme->Notify_Removed(Scene);
|
|
}
|
|
|
|
// release our reference to this render object
|
|
// object may delete itself here...
|
|
removeme->Release_Ref();
|
|
|
|
Update_Sub_Object_Bits();
|
|
Update_Obj_Space_Bounding_Volumes();
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Get_Num_Sub_Objects_On_Bone -- returns the number of objects on the given bone *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
int HLodClass::Get_Num_Sub_Objects_On_Bone(int boneindex) const
|
|
{
|
|
int count = 0;
|
|
|
|
for (int lod = 0; lod < LodCount; lod++) {
|
|
for (int model = 0; model < Lod[lod].Count(); model++) {
|
|
if (Lod[lod][model].BoneIndex == boneindex) count++;
|
|
}
|
|
}
|
|
for (int model = 0; model < AdditionalModels.Count(); model++) {
|
|
if (AdditionalModels[model].BoneIndex == boneindex) count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Get_Sub_Object_On_Bone -- returns obj on the given bone *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
RenderObjClass * HLodClass::Get_Sub_Object_On_Bone(int index,int boneindex) const
|
|
{
|
|
int count = 0;
|
|
for (int lod = 0; lod < LodCount; lod++) {
|
|
for (int model = 0; model < Lod[lod].Count(); model++) {
|
|
if (Lod[lod][model].BoneIndex == boneindex) {
|
|
if (count == index) {
|
|
Lod[lod][model].Model->Add_Ref();
|
|
return Lod[lod][model].Model;
|
|
}
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
for (int model = 0; model < AdditionalModels.Count(); model++) {
|
|
if (AdditionalModels[model].BoneIndex == boneindex) {
|
|
if (count == index) {
|
|
AdditionalModels[model].Model->Add_Ref();
|
|
return AdditionalModels[model].Model;
|
|
}
|
|
count++;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Get_Sub_Object_Bone_Index -- returns bone index of given object *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
int HLodClass::Get_Sub_Object_Bone_Index(RenderObjClass * subobj) const
|
|
{
|
|
for (int lod = 0; lod < LodCount; lod++) {
|
|
for (int model = 0; model < Lod[lod].Count(); model++) {
|
|
if (Lod[lod][model].Model == subobj) {
|
|
return Lod[lod][model].BoneIndex;
|
|
}
|
|
}
|
|
}
|
|
for (int model = 0; model < AdditionalModels.Count(); model++) {
|
|
if (AdditionalModels[model].Model == subobj) {
|
|
return AdditionalModels[model].BoneIndex;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Add_Sub_Object_To_Bone -- adds a sub-object to a bone *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
int HLodClass::Add_Sub_Object_To_Bone(RenderObjClass * subobj,int boneindex)
|
|
{
|
|
WWASSERT(subobj);
|
|
if ((boneindex < 0) || (boneindex >= HTree->Num_Pivots())) return 0;
|
|
|
|
subobj->Set_LOD_Bias(LODBias);
|
|
|
|
ModelNodeClass newnode;
|
|
newnode.Model = subobj;
|
|
newnode.Model->Add_Ref();
|
|
newnode.Model->Set_Container(this);
|
|
newnode.Model->Set_Animation_Hidden(HTree->Get_Visibility (boneindex) == false);
|
|
newnode.BoneIndex = boneindex;
|
|
|
|
int result = AdditionalModels.Add(newnode);
|
|
|
|
Update_Sub_Object_Bits();
|
|
Update_Obj_Space_Bounding_Volumes();
|
|
Set_Hierarchy_Valid (false);
|
|
Set_Sub_Object_Transforms_Dirty(true);
|
|
|
|
if (Is_In_Scene()) {
|
|
subobj->Notify_Added(Scene);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Set_Animation -- set animation state to the base-pose *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Set_Animation(void)
|
|
{
|
|
Animatable3DObjClass::Set_Animation();
|
|
Set_Sub_Object_Transforms_Dirty(true);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Set_Animation -- set animation state to an animation frame *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Set_Animation(HAnimClass * motion,float frame,int mode)
|
|
{
|
|
Animatable3DObjClass::Set_Animation(motion,frame,mode);
|
|
Set_Sub_Object_Transforms_Dirty(true);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Set_Animation -- set animation state to a blend of two animations *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Set_Animation
|
|
(
|
|
HAnimClass * motion0,
|
|
float frame0,
|
|
HAnimClass * motion1,
|
|
float frame1,
|
|
float percentage
|
|
)
|
|
{
|
|
Animatable3DObjClass::Set_Animation(motion0,frame0,motion1,frame1,percentage);
|
|
Set_Sub_Object_Transforms_Dirty(true);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Set_Animation -- set animation state to a combination of anims *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Set_Animation(HAnimComboClass * anim_combo)
|
|
{
|
|
Animatable3DObjClass::Set_Animation(anim_combo);
|
|
Set_Sub_Object_Transforms_Dirty(true);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Cast_Ray -- cast a ray against this HLod *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
bool HLodClass::Cast_Ray(RayCollisionTestClass & raytest)
|
|
{
|
|
if (Are_Sub_Object_Transforms_Dirty ()) {
|
|
Update_Sub_Object_Transforms ();
|
|
}
|
|
|
|
bool res = false;
|
|
int i;
|
|
|
|
// collide against the top LOD
|
|
int top = LodCount-1;
|
|
for (i = 0; i < Lod[top].Count(); i++) {
|
|
res |= Lod[top][i].Model->Cast_Ray(raytest);
|
|
}
|
|
|
|
for (i = 0; i < AdditionalModels.Count(); i++) {
|
|
res |= AdditionalModels[i].Model->Cast_Ray(raytest);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Cast_AABox -- Cast a swept AABox against this HLod *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
bool HLodClass::Cast_AABox(AABoxCollisionTestClass & boxtest)
|
|
{
|
|
if (Are_Sub_Object_Transforms_Dirty ()) {
|
|
Update_Sub_Object_Transforms ();
|
|
}
|
|
|
|
bool res = false;
|
|
int i;
|
|
|
|
// collide against the top LOD
|
|
int top = LodCount-1;
|
|
for (i = 0; i < Lod[top].Count(); i++) {
|
|
res |= Lod[top][i].Model->Cast_AABox(boxtest);
|
|
}
|
|
|
|
for (i = 0; i < AdditionalModels.Count(); i++) {
|
|
res |= AdditionalModels[i].Model->Cast_AABox(boxtest);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Cast_OBBox -- Cast a swept OBBox against this HLod *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
bool HLodClass::Cast_OBBox(OBBoxCollisionTestClass & boxtest)
|
|
{
|
|
if (Are_Sub_Object_Transforms_Dirty ()) {
|
|
Update_Sub_Object_Transforms ();
|
|
}
|
|
|
|
bool res = false;
|
|
int i;
|
|
|
|
// collide against the top LOD
|
|
int top = LodCount-1;
|
|
for (i = 0; i < Lod[top].Count(); i++) {
|
|
res |= Lod[top][i].Model->Cast_OBBox(boxtest);
|
|
}
|
|
|
|
for (i = 0; i < AdditionalModels.Count(); i++) {
|
|
res |= AdditionalModels[i].Model->Cast_OBBox(boxtest);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Intersect_AABox -- Intersect an AABox with this HLod *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
bool HLodClass::Intersect_AABox(AABoxIntersectionTestClass & boxtest)
|
|
{
|
|
if (Are_Sub_Object_Transforms_Dirty ()) {
|
|
Update_Sub_Object_Transforms ();
|
|
}
|
|
|
|
bool res = false;
|
|
int i;
|
|
|
|
// collide against the top LOD
|
|
int top = LodCount-1;
|
|
for (i = 0; i < Lod[top].Count(); i++) {
|
|
res |= Lod[top][i].Model->Intersect_AABox(boxtest);
|
|
}
|
|
|
|
for (i = 0; i < AdditionalModels.Count(); i++) {
|
|
res |= AdditionalModels[i].Model->Intersect_AABox(boxtest);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Intersect_OBBox -- Intersect an OBBox with this HLod *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
bool HLodClass::Intersect_OBBox(OBBoxIntersectionTestClass & boxtest)
|
|
{
|
|
if (Are_Sub_Object_Transforms_Dirty ()) {
|
|
Update_Sub_Object_Transforms ();
|
|
}
|
|
|
|
bool res = false;
|
|
int i;
|
|
|
|
// collide against the top LOD
|
|
int top = LodCount-1;
|
|
for (i = 0; i < Lod[top].Count(); i++) {
|
|
res |= Lod[top][i].Model->Intersect_OBBox(boxtest);
|
|
}
|
|
|
|
for (i = 0; i < AdditionalModels.Count(); i++) {
|
|
res |= AdditionalModels[i].Model->Intersect_OBBox(boxtest);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Prepare_LOD -- Prepare for LOD processing *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Prepare_LOD(CameraClass &camera)
|
|
{
|
|
if (Is_Not_Hidden_At_All() == false) {
|
|
return;
|
|
}
|
|
|
|
// Find the maximum screen dimension of the object in pixels
|
|
float norm_area = Get_Screen_Size(camera);
|
|
|
|
/*
|
|
** Set texture reduction factor for the (non-additional) subobjects:
|
|
*/
|
|
// Texture reduction system broken, don't call!
|
|
// Set_Texture_Reduction_Factor(Calculate_Texture_Reduction_Factor(norm_area));
|
|
|
|
// Prepare LOD processing if this object has more than one LOD:
|
|
if (LodCount > 1) {
|
|
/*
|
|
** Prepare cost and value arrays (and ensure current LOD doesn't violate clamping):
|
|
*/
|
|
int minlod = Calculate_Cost_Value_Arrays(norm_area, Value, Cost);
|
|
if (CurLod < minlod) Set_LOD_Level(minlod);
|
|
|
|
|
|
/*
|
|
** Add myself to the LOD optimizer:
|
|
*/
|
|
PredictiveLODOptimizerClass::Add_Object(this);
|
|
|
|
} else {
|
|
|
|
// Not added to optimizer, need to add cost
|
|
PredictiveLODOptimizerClass::Add_Cost(Get_Cost());
|
|
|
|
}
|
|
|
|
/*
|
|
** Recursively call for the additional objects:
|
|
*/
|
|
int additional_count = AdditionalModels.Count();
|
|
for (int i = 0; i < additional_count; i++) {
|
|
if (AdditionalModels[i].Model->Is_Not_Hidden_At_All()) {
|
|
AdditionalModels[i].Model->Prepare_LOD(camera);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Recalculate_Static_LOD_Factors -- compute lod factors *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Recalculate_Static_LOD_Factors(void)
|
|
{
|
|
/*
|
|
** Calculate NonPixelCost, PixelCostPerArea, BenefitFactor for all LOD
|
|
** levels.
|
|
** NOTE: for now we are using vastly simplified Cost and Benefit metrics.
|
|
** (these will be improved after initial experimentation).
|
|
** the Cost metric is simply the number of polygons, and the Benefit
|
|
** Metric is 1 - 0.5 / #polygons^2.
|
|
*/
|
|
|
|
for (int i = 0; i < LodCount; i++) {
|
|
|
|
// Currently there are no pixel-related costs taken into account
|
|
Lod[i].PixelCostPerArea = 0.0f;
|
|
|
|
// Sum polycount over all non-hidden models in array
|
|
int model_count = Lod[i].Count();
|
|
int polycount = 0;
|
|
for (int j = 0; j < model_count; j++) {
|
|
if (Lod[i][j].Model->Is_Not_Hidden_At_All()) {
|
|
polycount += Lod[i][j].Model->Get_Num_Polys();
|
|
}
|
|
}
|
|
// If polycount is zero set Cost to a small nonzero amount to avoid divisions by zero.
|
|
Lod[i].NonPixelCost = (polycount != 0)? polycount : 0.000001f;
|
|
|
|
// A polycount of zero yields a benefit factor of zero: otherwise apply formula.
|
|
Lod[i].BenefitFactor = (polycount != 0) ? (1 - (0.5f / (polycount * polycount))) : 0.0f;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Increment_LOD -- move to next lod *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Increment_LOD(void)
|
|
{
|
|
if (CurLod >= (LodCount-1)) return;
|
|
|
|
if (Is_In_Scene()) {
|
|
int model_count = Lod[CurLod].Count();
|
|
for (int i = 0; i < model_count; i++) {
|
|
Lod[CurLod][i].Model->Notify_Removed(Scene);
|
|
}
|
|
}
|
|
|
|
CurLod++;
|
|
|
|
if (Is_In_Scene()) {
|
|
int model_count = Lod[CurLod].Count();
|
|
for (int i = 0; i < model_count; i++) {
|
|
Lod[CurLod][i].Model->Notify_Added(Scene);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Decrement_LOD -- move to previous lod *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Decrement_LOD(void)
|
|
{
|
|
if (CurLod < 1) return;
|
|
|
|
if (Is_In_Scene()) {
|
|
int model_count = Lod[CurLod].Count();
|
|
for (int i = 0; i < model_count; i++) {
|
|
Lod[CurLod][i].Model->Notify_Removed(Scene);
|
|
}
|
|
}
|
|
|
|
CurLod--;
|
|
|
|
if (Is_In_Scene()) {
|
|
int model_count = Lod[CurLod].Count();
|
|
for (int i = 0; i < model_count; i++) {
|
|
Lod[CurLod][i].Model->Notify_Added(Scene);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Get_Cost -- returns the cost of this LOD *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
float HLodClass::Get_Cost(void) const
|
|
{
|
|
return(Cost[CurLod]);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Get_Value -- returns the value of this LOD *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
float HLodClass::Get_Value(void) const
|
|
{
|
|
return(Value[CurLod]);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Get_Post_Increment_Value -- returns the post increment value *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
float HLodClass::Get_Post_Increment_Value(void) const
|
|
{
|
|
return(Value[CurLod + 1]);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Set_LOD_Level -- set the current lod level *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Set_LOD_Level(int lod)
|
|
{
|
|
lod = MAX(0, lod);
|
|
lod = MIN(lod, (LodCount - 1));
|
|
|
|
if (lod == CurLod) return;
|
|
|
|
|
|
if (Is_In_Scene()) {
|
|
int model_count = Lod[CurLod].Count();
|
|
for (int i = 0; i < model_count; i++) {
|
|
Lod[CurLod][i].Model->Notify_Removed(Scene);
|
|
}
|
|
}
|
|
|
|
CurLod = lod;
|
|
|
|
if (Is_In_Scene()) {
|
|
int model_count = Lod[CurLod].Count();
|
|
for (int i = 0; i < model_count; i++) {
|
|
Lod[CurLod][i].Model->Notify_Added(Scene);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Get_LOD_Level -- returns the current LOD level *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
int HLodClass::Get_LOD_Level(void) const
|
|
{
|
|
return CurLod;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Get_LOD_Count -- returns the number of levels of detail *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
int HLodClass::Get_LOD_Count(void) const
|
|
{
|
|
return LodCount;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Calculate_Cost_Value_Arrays -- computes the cost-value arrays *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
int HLodClass::Calculate_Cost_Value_Arrays(float screen_area, float *values, float *costs) const
|
|
{
|
|
int lod = 0;
|
|
|
|
// Calculate Cost heuristic for each LOD based on normalized screen area:
|
|
for (lod = 0; lod < LodCount; lod++) {
|
|
costs[lod] = Lod[lod].NonPixelCost + Lod[lod].PixelCostPerArea * screen_area;
|
|
}
|
|
|
|
// Calculate Value heuristic. First, all LOD levels for which
|
|
// MaxScreenSize is smaller than screen_area have their Value set to
|
|
// AT_MIN_LOD, as well as the first LOD after that (unless there are no
|
|
// other LODs):
|
|
for (lod = 0; lod < LodCount && Lod[lod].MaxScreenSize < screen_area; lod++) {
|
|
values[lod] = AT_MIN_LOD;
|
|
}
|
|
|
|
if (lod >= LodCount) {
|
|
lod = LodCount - 1;
|
|
} else {
|
|
values[lod] = AT_MIN_LOD;
|
|
}
|
|
|
|
// Now lod is the lowest allowed - return this value.
|
|
int minlod = lod;
|
|
|
|
// Calculate Value heuristic for any remaining LODs based on normalized screen area:
|
|
lod++;
|
|
for (; lod < LodCount; lod++) {
|
|
values[lod] = (Lod[lod].BenefitFactor * screen_area * LODBias) / costs[lod];
|
|
}
|
|
values[LodCount] = AT_MAX_LOD; // Post-inc value will flag max LOD.
|
|
|
|
return minlod;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Get_Current_LOD -- returns a render object which represents the current LOD *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
RenderObjClass * HLodClass::Get_Current_LOD(void)
|
|
{
|
|
int count = Get_Lod_Model_Count(CurLod);
|
|
|
|
if(!count)
|
|
return 0;
|
|
|
|
return Get_Lod_Model(CurLod, 0);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Set_Texture_Reduction_Factor -- resizeable texture support *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
/*
|
|
void HLodClass::Set_Texture_Reduction_Factor(float trf)
|
|
{
|
|
WWASSERT(0); // don't call to tex reduction system, it's broken!
|
|
// We don't touch the additional subobjects: they will get Prepare_LOD
|
|
// called on them individually which is where texture reduction will be
|
|
// set also.
|
|
for (int lod = 0; lod < LodCount; lod++) {
|
|
int model_count = Lod[lod].Count();
|
|
for (int model_id = 0; model_id < model_count; model_id++) {
|
|
Lod[lod][model_id].Model->Set_Texture_Reduction_Factor(trf);
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Scale -- scale this HLod model *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Scale(float scale)
|
|
{
|
|
if (scale==1.0f) return;
|
|
|
|
int lod;
|
|
int model;
|
|
|
|
//. Scale all subobjects.
|
|
for (lod = 0; lod < LodCount; lod++) {
|
|
for (model = 0; model < Lod[lod].Count(); model++) {
|
|
Lod[lod][model].Model->Scale(scale);
|
|
}
|
|
}
|
|
|
|
for (model = 0; model < AdditionalModels.Count(); model++) {
|
|
AdditionalModels[model].Model->Scale(scale);
|
|
}
|
|
|
|
// Scale HTree:
|
|
HTree->Scale(scale);
|
|
|
|
// Invalidate hierarchy
|
|
Set_Hierarchy_Valid(false);
|
|
|
|
// Now update the object space bounding volumes of this object's container:
|
|
RenderObjClass *container = Get_Container();
|
|
if (container) container->Update_Obj_Space_Bounding_Volumes();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Get_Num_Snap_Points -- returns the number of snap points in this model *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
int HLodClass::Get_Num_Snap_Points(void)
|
|
{
|
|
if (SnapPoints) {
|
|
return SnapPoints->Count();
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Get_Snap_Point -- returns specified snap-point *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Get_Snap_Point(int index,Vector3 * set)
|
|
{
|
|
WWASSERT(set != NULL);
|
|
if (SnapPoints) {
|
|
*set = (*SnapPoints)[index];
|
|
} else {
|
|
set->X = set->Y = set->Z = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Update_Sub_Object_Transforms -- updates transforms of all sub-objects *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Update_Sub_Object_Transforms(void)
|
|
{
|
|
/*
|
|
** Update the animation transforms, recurse up to the
|
|
** top of the tree...
|
|
*/
|
|
Animatable3DObjClass::Update_Sub_Object_Transforms();
|
|
|
|
/*
|
|
** Put the computed transforms into our sub objects.
|
|
*/
|
|
int lod,model;
|
|
|
|
for (lod = 0; lod < LodCount; lod++) {
|
|
for (model = 0; model < Lod[lod].Count(); model++) {
|
|
|
|
RenderObjClass * robj = Lod[lod][model].Model;
|
|
int bone = Lod[lod][model].BoneIndex;
|
|
|
|
robj->Set_Transform(HTree->Get_Transform(bone));
|
|
robj->Set_Animation_Hidden(!HTree->Get_Visibility(bone));
|
|
robj->Update_Sub_Object_Transforms();
|
|
}
|
|
}
|
|
|
|
for (model = 0; model < AdditionalModels.Count(); model++) {
|
|
|
|
RenderObjClass * robj = AdditionalModels[model].Model;
|
|
int bone = AdditionalModels[model].BoneIndex;
|
|
|
|
robj->Set_Transform(HTree->Get_Transform(bone));
|
|
robj->Set_Animation_Hidden(!HTree->Get_Visibility(bone));
|
|
robj->Update_Sub_Object_Transforms();
|
|
}
|
|
|
|
Set_Sub_Object_Transforms_Dirty(false);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Update_Obj_Space_Bounding_Volumes -- update object-space bounding volumes *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Update_Obj_Space_Bounding_Volumes(void)
|
|
{
|
|
//
|
|
// Do we still have a valid bounding box index?
|
|
//
|
|
ModelArrayClass &high_lod = Lod[LodCount - 1];
|
|
int count = high_lod.Count ();
|
|
if ( BoundingBoxIndex < 0 ||
|
|
BoundingBoxIndex >= count ||
|
|
high_lod[BoundingBoxIndex].Model->Class_ID () != RenderObjClass::CLASSID_OBBOX)
|
|
{
|
|
BoundingBoxIndex = -1;
|
|
}
|
|
|
|
//
|
|
// Attempt to find an OBBox mesh inside the heirarchy
|
|
//
|
|
int index = high_lod.Count ();
|
|
while (index -- && BoundingBoxIndex == -1) {
|
|
RenderObjClass *model = high_lod[index].Model;
|
|
|
|
//
|
|
// Is this an OBBox mesh?
|
|
//
|
|
if (model->Class_ID () == RenderObjClass::CLASSID_OBBOX)
|
|
{
|
|
const char *name = model->Get_Name ();
|
|
const char *name_seg = ::strchr (name, '.');
|
|
if (name_seg != NULL) {
|
|
name = name_seg + 1;
|
|
}
|
|
|
|
//
|
|
// Does the name match the designator we are looking for?
|
|
//
|
|
if (::stricmp (name, "BOUNDINGBOX") == 0) {
|
|
BoundingBoxIndex = index;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int i;
|
|
RenderObjClass * robj = NULL;
|
|
|
|
// if we don't have any sub objects, just set default bounds
|
|
if (Get_Num_Sub_Objects() <= 0) {
|
|
ObjSphere.Init(Vector3(0,0,0),0);
|
|
ObjBox.Center.Set(0,0,0);
|
|
ObjBox.Extent.Set(0,0,0);
|
|
return;
|
|
}
|
|
|
|
// loop through all sub-objects, combining their object-space bounding spheres and boxes.
|
|
// Put our HTree in its base pose at the origin.
|
|
SphereClass sphere;
|
|
AABoxClass obj_aabox;
|
|
MinMaxAABoxClass box;
|
|
|
|
HTree->Base_Update(Matrix3D(1));
|
|
|
|
robj = Get_Sub_Object(0);
|
|
WWASSERT(robj);
|
|
|
|
const Matrix3D & bonetm = HTree->Get_Transform(Get_Sub_Object_Bone_Index(robj));
|
|
robj->Get_Obj_Space_Bounding_Sphere(sphere);
|
|
sphere.Transform(bonetm);
|
|
robj->Get_Obj_Space_Bounding_Box(obj_aabox);
|
|
|
|
box.Init(obj_aabox);
|
|
box.Transform(bonetm);
|
|
|
|
robj->Release_Ref();
|
|
|
|
for (i=1; i<Get_Num_Sub_Objects(); i++) {
|
|
robj = Get_Sub_Object(i);
|
|
WWASSERT(robj);
|
|
|
|
const Matrix3D & bonetm = HTree->Get_Transform(Get_Sub_Object_Bone_Index(robj));
|
|
|
|
SphereClass tmpsphere;
|
|
robj->Get_Obj_Space_Bounding_Sphere(tmpsphere);
|
|
tmpsphere.Transform(bonetm);
|
|
sphere.Add_Sphere(tmpsphere);
|
|
|
|
AABoxClass tmpbox;
|
|
robj->Get_Obj_Space_Bounding_Box(tmpbox);
|
|
tmpbox.Transform(bonetm);
|
|
box.Add_Box(tmpbox);
|
|
|
|
robj->Release_Ref();
|
|
}
|
|
|
|
ObjSphere = sphere;
|
|
ObjBox = box;
|
|
|
|
Invalidate_Cached_Bounding_Volumes();
|
|
Set_Hierarchy_Valid(false);
|
|
|
|
// Now update the object space bounding volumes of this object's container:
|
|
RenderObjClass *container = Get_Container();
|
|
if (container) container->Update_Obj_Space_Bounding_Volumes();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::add_lod_model -- adds a model to one of the lods *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::add_lod_model(int lod,RenderObjClass * robj,int boneindex)
|
|
{
|
|
WWASSERT(robj != NULL);
|
|
|
|
ModelNodeClass newnode;
|
|
newnode.Model = robj;
|
|
newnode.Model->Add_Ref();
|
|
newnode.BoneIndex = boneindex;
|
|
newnode.Model->Set_Container(this);
|
|
newnode.Model->Set_Transform(HTree->Get_Transform(boneindex));
|
|
|
|
if (Is_In_Scene() && lod == CurLod) {
|
|
newnode.Model->Notify_Added(Scene);
|
|
}
|
|
Lod[lod].Add(newnode);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Create_Decal -- create a decal on this HLod *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Create_Decal(DecalGeneratorClass * generator)
|
|
{
|
|
for (int lod=0; lod<LodCount; lod++) {
|
|
for (int model=0; model<Lod[lod].Count(); model++) {
|
|
Lod[lod][model].Model->Create_Decal(generator);
|
|
}
|
|
}
|
|
|
|
for (int model=0; model<AdditionalModels.Count(); model++) {
|
|
AdditionalModels[model].Model->Create_Decal(generator);
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Delete_Decal -- remove a decal from this HLod *
|
|
* *
|
|
* The decal_id is the ID which was assigned to the DecalGeneratorClass when you created *
|
|
* the decal. *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Delete_Decal(uint32 decal_id)
|
|
{
|
|
for (int lod=0; lod<LodCount; lod++) {
|
|
for (int model=0; model<Lod[lod].Count(); model++) {
|
|
Lod[lod][model].Model->Delete_Decal(decal_id);
|
|
}
|
|
}
|
|
|
|
for (int model=0; model<AdditionalModels.Count(); model++) {
|
|
AdditionalModels[model].Model->Delete_Decal(decal_id);
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Set_HTree -- replace the hierarchy tree *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 1/26/00 gth : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Set_HTree(HTreeClass * htree)
|
|
{
|
|
Animatable3DObjClass::Set_HTree(htree);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* HLodClass::Set_Hidden -- Propogates the hidden bit to particle emitters. *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 3/19/01 pds : Created. *
|
|
*=============================================================================================*/
|
|
void HLodClass::Set_Hidden(int onoff)
|
|
{
|
|
//
|
|
// Loop over all attached models
|
|
//
|
|
int additional_count = AdditionalModels.Count();
|
|
for (int index = 0; index < additional_count; index ++) {
|
|
|
|
//
|
|
// Is this a particle emitter?
|
|
//
|
|
RenderObjClass *model = AdditionalModels[index].Model;
|
|
if (model->Class_ID () == RenderObjClass::CLASSID_PARTICLEEMITTER) {
|
|
|
|
//
|
|
// Pass the hidden bit onto the emitter
|
|
//
|
|
model->Set_Hidden(onoff);
|
|
}
|
|
}
|
|
|
|
Animatable3DObjClass::Set_Hidden(onoff);
|
|
return ;
|
|
}
|
|
|