This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/wwphys/phys.cpp

805 lines
21 KiB
C++
Raw Permalink Normal View History

/*
** 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 : WWPhys *
* *
* $Archive:: /Commando/Code/wwphys/phys.cpp $*
* *
* Author:: Greg Hjelstrom *
* *
* $Modtime:: 2/21/02 4:01p $*
* *
* $Revision:: 79 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "phys.h"
#include "colmathaabox.h"
#include "rendobj.h"
#include "rinfo.h"
#include "assetmgr.h"
#include "ww3d.h"
#include "wwdebug.h"
#include "pscene.h"
#include "cullsys.h"
#include "chunkio.h"
#include "saveload.h"
#include "persistfactory.h"
#include "physcoltest.h"
#include "lightenvironment.h"
#include "umbrasupport.h"
#if (UMBRASUPPORT)
#include <umbra.hpp>
#endif
#include "dx8wrapper.h"
#include "dx8vertexbuffer.h"
#include "dx8indexbuffer.h"
const float DEBUG_RENDER_DIST2 = (50.0f*50.0f);
const float SUN_CHECK_DISTANCE = 50.0f; //If a ray this long doesn't intersect, you can see the sun...
/*
** create_render_obj_from_filename
*/
RenderObjClass * create_render_obj_from_filename( const char * filename )
{
StringClass render_obj_name(filename,true);
if ( ::strchr( filename, '\\' ) != 0 ) {
render_obj_name = ::strrchr( filename, '\\' ) + 1;
}
render_obj_name.Erase( render_obj_name.Get_Length() - 4, 4 );
RenderObjClass *model = WW3DAssetManager::Get_Instance()->Create_Render_Obj( render_obj_name );
if ( model == NULL ) {
WWDEBUG_SAY(("Failed to create %s from %s\n", (const char *)render_obj_name, filename));
}
return model;
}
/***********************************************************************************************
**
** PhysClass Implementation
**
***********************************************************************************************/
/*
** Chunk ID's used by PhysClass
*/
enum
{
PHYS_CHUNK_VARIABLES = 0x00660055,
PHYS_CHUNK_MODEL,
PHYS_VARIABLE_CULLABLE_PTR = 0x00,
PHYS_VARIABLE_WIDGETUSER_PTR,
PHYS_VARIABLE_EDITABLE_PTR,
PHYS_VARIABLE_FLAGS,
PHYS_VARIABLE_NAME,
PHYS_VARIABLE_OBSERVER,
PHYS_VARIABLE_DEFID,
PHYS_VARIABLE_INSTANCEID,
};
PhysClass::PhysClass(void) :
Flags(DEFAULT_FLAGS),
Model(NULL),
Observer(NULL),
Definition(NULL),
InstanceID(0),
VisObjectID(0),
LastVisibleFrame(0), // JANI TEMP TEST
SunStatusLastUpdated(0),
StaticLightingCache(NULL)
#if (UMBRASUPPORT)
,UmbraObject(NULL)
#endif
{
#if (UMBRASUPPORT)
UmbraObject = new Umbra::Object(UmbraSupport::Peek_Dummy_Sphere());
UmbraObject->setUserPointer(this);
UmbraSupport::Install_Umbra_Object(this);
#endif
}
PhysClass::~PhysClass(void)
{
if (Model) {
Model->Release_Ref();
Model = NULL;
}
if (StaticLightingCache) {
delete StaticLightingCache;
}
#if (UMBRASUPPORT)
if (UmbraObject) {
UmbraSupport::Remove_Umbra_Object(this);
UmbraObject->release();
UmbraObject = NULL;
}
#endif
}
void PhysClass::Init(const PhysDefClass & def)
{
Definition = &def;
Flags = DEFAULT_FLAGS;
if (!def.ModelName.Is_Empty()) {
RenderObjClass * model = NULL;
if (::strchr(def.ModelName, '.') != NULL) {
model = ::create_render_obj_from_filename(def.ModelName);
} else {
model = WW3DAssetManager::Get_Instance()->Create_Render_Obj(def.ModelName);
}
if ( model == NULL ) {
WWDEBUG_SAY(( "*** FATAL ERROR : Failed to create model %s\n", def.ModelName ));
}
Set_Model(model);
REF_PTR_RELEASE(model);
}
}
void PhysClass::Set_Model(RenderObjClass * model)
{
PhysicsSceneClass * the_scene = PhysicsSceneClass::Get_Instance();
bool in_scene = the_scene->Contains(this);
if (Model) {
// If we had an old model, copy the transform
if ( model ) {
model->Set_Transform( Model->Get_Transform() );
}
if (in_scene) Model->Notify_Removed(the_scene);
Model->Release_Ref();
}
Model = model;
if (Model) {
Model->Add_Ref();
if (in_scene) Model->Notify_Added(the_scene);
}
if ((Definition != NULL) && (Definition->IsPreLit)) {
Enable_Is_Pre_Lit(true);
}
Invalidate_Static_Lighting_Cache ();
}
void PhysClass::Set_Model_By_Name(const char * model_type_name)
{
RenderObjClass * model = WW3DAssetManager::Get_Instance()->Create_Render_Obj(model_type_name);
if ( model == NULL ) {
WWDEBUG_SAY(( "%s failed to load\n", model_type_name ));
}
WWASSERT(model); // As above, PhysClasses cannot survive without a model...
Set_Model(model);
if (model) {
model->Release_Ref();
}
}
RenderObjClass * PhysClass::Get_Model(void)
{
if (Model) Model->Add_Ref();
return Model;
}
void PhysClass::Set_Name(const char * name)
{
Name=name;
}
const char * PhysClass::Get_Name(void)
{
return Name;
}
void PhysClass::Get_Shadow_Blob_Box(AABoxClass * set_obj_space_box)
{
WWASSERT(set_obj_space_box != NULL);
if (set_obj_space_box != NULL) {
Model->Get_Obj_Space_Bounding_Box(*set_obj_space_box);
set_obj_space_box->Extent *= 0.75f;
}
}
void PhysClass::Render(RenderInfoClass & rinfo)
{
Push_Effects(rinfo);
if (Model) {
Model->Render(rinfo);
}
Pop_Effects(rinfo);
}
void PhysClass::Vis_Render(SpecialRenderInfoClass & rinfo)
{
if (Model) {
Model->Special_Render(rinfo);
}
}
void PhysClass::Invalidate_Static_Lighting_Cache(void)
{
Set_Flag(STATIC_LIGHTING_DIRTY,true);
}
LightEnvironmentClass * PhysClass::Get_Static_Lighting_Environment(void)
{
if (Is_Pre_Lit()) {
/*
** This object doesn't need a lighting cache, make sure it doesn't have one
*/
if (StaticLightingCache != NULL) {
WWDEBUG_SAY(("Pre-Lit object %s has a lighting cache!\r\n",Model->Get_Name()));
delete StaticLightingCache;
StaticLightingCache = NULL;
}
} else if (Get_Flag(STATIC_LIGHTING_DIRTY)) {
/*
** First, ensure that we have an allocated lighting cache
*/
if (StaticLightingCache == NULL) {
StaticLightingCache = new LightEnvironmentClass;
}
/*
** Next, update our sunlight status
*/
Update_Sun_Status();
/*
** Finally, ask the physics scene to re-compute our lighting cache
*/
PhysicsSceneClass::Get_Instance()->Compute_Static_Lighting( StaticLightingCache,
Model->Get_Bounding_Sphere().Center,
Get_Flag(IS_IN_THE_SUN),
Get_Vis_Object_ID() );
Set_Flag(STATIC_LIGHTING_DIRTY,false);
}
/*
** Return our lighting cache to the caller
*/
return StaticLightingCache;
}
void PhysClass::Update_Sun_Status(void)
{
// Update sun status only four times per second
unsigned current_time=WW3D::Get_Sync_Time();
if ((current_time-SunStatusLastUpdated)<250) return;
SunStatusLastUpdated=current_time;
PhysicsSceneClass * scene = PhysicsSceneClass::Get_Instance();
Vector3 sunlight;
scene->Get_Sun_Light_Vector(&sunlight);
Vector3 center = Model->Get_Bounding_Sphere().Center;
#pragma message ("(gth) Need a collision group for sun-rays")
CastResultStruct sunresult;
LineSegClass sunray(center,center - sunlight * SUN_CHECK_DISTANCE);
PhysRayCollisionTestClass sunraytest(sunray,&sunresult,0,COLLISION_TYPE_PROJECTILE);
sunraytest.CheckStaticObjs = true;
sunraytest.CheckDynamicObjs = false;
Inc_Ignore_Counter();
scene->Cast_Ray(sunraytest);
// if the ray hits a static object which is casting a projected shadow, ignore that object
// and check again.
if ( (sunresult.Fraction < 1.0f) &&
(sunraytest.CollidedPhysObj != NULL) )
{
PhysClass * obj = sunraytest.CollidedPhysObj;
if (obj->Is_Casting_Shadow()) {
obj->Inc_Ignore_Counter();
sunresult.Reset();
scene->Cast_Ray(sunraytest);
obj->Dec_Ignore_Counter();
}
}
Dec_Ignore_Counter();
Enable_Is_In_The_Sun(sunresult.Fraction == 1.0f);
}
void PhysClass::Push_Effects(RenderInfoClass & rinfo)
{
if (!MaterialEffectsOnMe.Is_Empty()) {
RefMaterialEffectListIterator iterator(&MaterialEffectsOnMe);
for ( ; !iterator.Is_Done() ; iterator.Next()) {
iterator.Peek_Obj()->Render_Push(rinfo,this);
}
}
#if 0
if (!ProjectionsOnMe.Is_Empty()) {
ShaderClass shader = ShaderClass::_PresetOpaqueShader;
VertexMaterialClass * vmtl = VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_NODIFFUSE);
DX8Wrapper::Set_Shader(shader);
DX8Wrapper::Set_Material(vmtl);
Matrix4 view,proj;
Matrix4 identity(true);
DX8Wrapper::Get_Transform(D3DTS_VIEW,view);
DX8Wrapper::Get_Transform(D3DTS_PROJECTION,proj);
DX8Wrapper::Set_Transform(D3DTS_WORLD,identity);
DX8Wrapper::Set_Transform(D3DTS_VIEW,identity);
DX8Wrapper::Set_Transform(D3DTS_PROJECTION,identity);
TexProjListIterator iterator(&ProjectionsOnMe);
for ( ; !iterator.Is_Done() ; iterator.Next()) {
TextureClass * tex = iterator.Peek_Obj()->Peek_Material_Pass()->Peek_Texture(0);
if (tex != NULL) {
DX8Wrapper::Set_Texture(0,tex);
DynamicVBAccessClass vbaccess(BUFFER_TYPE_DYNAMIC_DX8,4);
{
DynamicVBAccessClass::WriteLockClass lock(&vbaccess);
VertexFormatXYZNDUV2 * verts = lock.Get_Formatted_Vertex_Array();
verts[0].x = -1.0f;
verts[0].y = 0.8f;
verts[0].z = 0.0;
verts[0].u1 = 0.0f;
verts[0].v1 = 0.0f;
verts[0].diffuse = 0xFFFFFFFF;
verts[1].x = -1.0f;
verts[1].y = 0.3f;
verts[1].z = 0.0;
verts[1].u1 = 0.0f;
verts[1].v1 = 1.0f;
verts[1].diffuse = 0xFFFFFFFF;
verts[2].x = -0.5f;
verts[2].y = 0.3f;
verts[2].z = 0.0;
verts[2].u1 = 1.0f;
verts[2].v1 = 1.0f;
verts[2].diffuse = 0xFFFFFFFF;
verts[3].x = -0.5f;
verts[3].y = 0.8f;
verts[3].z = 0.0;
verts[3].u1 = 1.0f;
verts[3].v1 = 0.0f;
verts[3].diffuse = 0xFFFFFFFF;
}
DynamicIBAccessClass ibaccess(BUFFER_TYPE_DYNAMIC_DX8,2*3);
{
DynamicIBAccessClass::WriteLockClass lock(&ibaccess);
unsigned short * indices = lock.Get_Index_Array();
indices[0] = 0;
indices[1] = 1;
indices[2] = 2;
indices[3] = 0;
indices[4] = 2;
indices[5] = 3;
}
DX8Wrapper::Set_Vertex_Buffer(vbaccess);
DX8Wrapper::Set_Index_Buffer(ibaccess,0);
DX8Wrapper::Draw_Triangles(0,2,0,4);
}
}
DX8Wrapper::Set_Transform(D3DTS_VIEW,view);
DX8Wrapper::Set_Transform(D3DTS_PROJECTION,proj);
REF_PTR_RELEASE(vmtl);
}
#endif
}
void PhysClass::Pop_Effects(RenderInfoClass & rinfo)
{
if (!MaterialEffectsOnMe.Is_Empty()) {
RefMaterialEffectListIterator iterator(&MaterialEffectsOnMe);
while (!iterator.Is_Done()) {
MaterialEffectClass * effect = iterator.Peek_Obj();
effect->Render_Pop(rinfo);
if (effect->Is_Auto_Remove_Enabled()) {
iterator.Remove_Current_Object();
} else {
iterator.Next();
}
}
}
}
bool PhysClass::Save (ChunkSaveClass &csave)
{
CullableClass * cullable_ptr = (CullableClass *)this;
WidgetUserClass * widgetuser_ptr = (WidgetUserClass *)this;
EditableClass * editable_ptr = (EditableClass *)this;
csave.Begin_Chunk(PHYS_CHUNK_VARIABLES);
// (gth) not saving observer pointers any more!
WRITE_MICRO_CHUNK(csave,PHYS_VARIABLE_CULLABLE_PTR,cullable_ptr);
WRITE_MICRO_CHUNK(csave,PHYS_VARIABLE_WIDGETUSER_PTR,widgetuser_ptr);
WRITE_MICRO_CHUNK(csave,PHYS_VARIABLE_EDITABLE_PTR,editable_ptr);
WRITE_MICRO_CHUNK(csave,PHYS_VARIABLE_FLAGS,Flags);
WRITE_MICRO_CHUNK(csave,PHYS_VARIABLE_INSTANCEID,InstanceID);
if (Name.Get_Length() > 0) {
csave.Begin_Micro_Chunk(PHYS_VARIABLE_NAME);
WWASSERT(Name.Get_Length()+1 < 255);
csave.Write(Name,Name.Get_Length() + 1);
csave.End_Micro_Chunk();
}
if (Definition != NULL) {
int defid = Definition->Get_ID();
WRITE_MICRO_CHUNK(csave,PHYS_VARIABLE_DEFID,defid);
}
csave.End_Chunk();
csave.Begin_Chunk(PHYS_CHUNK_MODEL);
csave.Begin_Chunk(Model->Get_Factory().Chunk_ID());
Model->Get_Factory().Save(csave,Model);
csave.End_Chunk();
csave.End_Chunk();
return true;
}
bool PhysClass::Load (ChunkLoadClass &cload)
{
PersistFactoryClass * factory = NULL;
CullableClass * cullable_ptr = NULL;
WidgetUserClass * widgetuser_ptr = NULL;
EditableClass * editable_ptr = NULL;
int defid = -1;
char tmpstring[256];
tmpstring[0] = 0;
RenderObjClass * render_model = NULL;
while (cload.Open_Chunk()) {
switch(cload.Cur_Chunk_ID())
{
case PHYS_CHUNK_VARIABLES:
while (cload.Open_Micro_Chunk()) {
switch(cload.Cur_Micro_Chunk_ID()) {
// (gth) not saving observer pointers any more!
READ_MICRO_CHUNK(cload,PHYS_VARIABLE_CULLABLE_PTR,cullable_ptr);
READ_MICRO_CHUNK(cload,PHYS_VARIABLE_WIDGETUSER_PTR,widgetuser_ptr);
READ_MICRO_CHUNK(cload,PHYS_VARIABLE_EDITABLE_PTR,editable_ptr);
READ_MICRO_CHUNK(cload,PHYS_VARIABLE_FLAGS,Flags);
READ_MICRO_CHUNK(cload,PHYS_VARIABLE_DEFID,defid);
READ_MICRO_CHUNK(cload,PHYS_VARIABLE_INSTANCEID,InstanceID);
case PHYS_VARIABLE_NAME:
cload.Read(tmpstring,cload.Cur_Micro_Chunk_Length());
break;
}
cload.Close_Micro_Chunk();
}
break;
case PHYS_CHUNK_MODEL:
cload.Open_Chunk();
factory = SaveLoadSystemClass::Find_Persist_Factory(cload.Cur_Chunk_ID());
WWASSERT(factory != NULL);
if (factory != NULL) {
render_model = (RenderObjClass *)factory->Load(cload);
SET_REF_OWNER(render_model);
}
cload.Close_Chunk();
break;
default:
WWDEBUG_SAY(("Unhandled Chunk: 0x%X File: %s Line: %d\r\n",cload.Cur_Chunk_ID(),__FILE__,__LINE__));
break;
}
if (cullable_ptr != NULL) {
SaveLoadSystemClass::Register_Pointer(cullable_ptr,(CullableClass *)this);
}
cload.Close_Chunk();
}
/*
** Set our name
*/
if (strlen(tmpstring) > 0) {
Set_Name(tmpstring);
}
/*
** Set our definition pointer
*/
if (defid != -1) {
Definition = (PhysDefClass *)_TheDefinitionMgr.Find_Definition(defid);
} else {
Definition = NULL;
}
/*
** Only install the model after our definition is installed
*/
Set_Model(render_model);
REF_PTR_RELEASE(render_model);
/*
** Ask that our Observer pointer is re-mapped
*/
if (Observer != NULL) {
REQUEST_POINTER_REMAP((void**)&Observer);
}
/*
** Register all of the multiple-inheritance versions of our this pointer
*/
if (cullable_ptr != NULL) {
SaveLoadSystemClass::Register_Pointer(cullable_ptr,(CullableClass *)this);
}
if (widgetuser_ptr != NULL) {
SaveLoadSystemClass::Register_Pointer(widgetuser_ptr,(WidgetUserClass *)this);
}
if (editable_ptr != NULL) {
SaveLoadSystemClass::Register_Pointer(editable_ptr,(EditableClass *)this);
}
/*
** Mark our static lighting cache dirty
*/
Invalidate_Static_Lighting_Cache();
/*
** Update our Umbra object
*/
#if (UMBRASUPPORT)
UmbraSupport::Update_Umbra_Object(this);
#endif
return true;
}
#ifdef WWDEBUG
void PhysClass::Add_Debug_Point(const Vector3 & p,const Vector3 & color)
{
if (Is_Debug_Display_Enabled()) {
PhysicsSceneClass::Get_Instance()->Add_Debug_Point(p,color);
}
}
#endif
#ifdef WWDEBUG
void PhysClass::Add_Debug_Vector(const Vector3 & p,const Vector3 & v,const Vector3 & color)
{
if (Is_Debug_Display_Enabled() && (v.Length2() > 0.0f)) {
PhysicsSceneClass::Get_Instance()->Add_Debug_Vector(p,v,color);
}
}
#endif
#ifdef WWDEBUG
void PhysClass::Add_Debug_AABox(const AABoxClass & box,const Vector3 & color,float opacity)
{
if (Is_Debug_Display_Enabled()) {
PhysicsSceneClass::Get_Instance()->Add_Debug_AABox(box,color,opacity);
}
}
#endif
#ifdef WWDEBUG
void PhysClass::Add_Debug_OBBox(const OBBoxClass & box,const Vector3 & color,float opacity)
{
if (Is_Debug_Display_Enabled()) {
PhysicsSceneClass::Get_Instance()->Add_Debug_OBBox(box,color,opacity);
}
}
#endif
#ifdef WWDEBUG
void PhysClass::Add_Debug_Axes(const Matrix3D & transform,const Vector3 & color)
{
if (Is_Debug_Display_Enabled()) {
PhysicsSceneClass::Get_Instance()->Add_Debug_Axes(transform,color);
}
}
#endif
bool PhysClass::Is_Debug_Display_Enabled(void) const
{
PhysicsSceneClass * the_scene = PhysicsSceneClass::Get_Instance();
Vector3 pos;
Get_Position(&pos);
float dist = (pos - the_scene->Get_Last_Camera_Position()).Length2();
if (dist > DEBUG_RENDER_DIST2) {
return false;
}
if (the_scene) {
return (((Flags & DEBUGDISPLAY) == DEBUGDISPLAY) || the_scene->Is_Debug_Display_Enabled());
} else {
return ((Flags & DEBUGDISPLAY) == DEBUGDISPLAY);
}
}
bool PhysClass::Expire(void)
{
ExpirationReactionType result = EXPIRATION_APPROVED;
if (Observer != NULL) {
result = Observer->Object_Expired(this);
}
if (result == EXPIRATION_APPROVED) {
PhysicsSceneClass::Get_Instance()->Delayed_Remove_Object(this);
return true;
} else {
return false;
}
}
//
// TSS added this... not efficient to use if you are also
// setting position
//
void PhysClass::Set_Facing(float new_facing)
{
Vector3 pos;
Get_Position(&pos);
Matrix3D tm(1);
tm.Translate(pos);
tm.Rotate_Z(new_facing);
Set_Transform(tm);
}
bool PhysClass::Do_Any_Effects_Suppress_Shadows(void)
{
RefMaterialEffectListIterator iterator(&MaterialEffectsOnMe);
for ( ; !iterator.Is_Done() ; iterator.Next()) {
if (iterator.Peek_Obj()->Are_Shadows_Suppressed()) {
return true;
}
}
return false;
}
/***********************************************************************************************
**
** PhysDefClass Implementation
** This holds the description for a PhysClass. Since PhysClass's aren't concrete, this
** definition class isn't either and thus has no persist factory (required by PersistClass)
** or create method (required by DefinitionClass)
**
***********************************************************************************************/
enum
{
PHYSDEF_CHUNK_DEFINITION = 0x055ffe07, // parent class data.
PHYSDEF_CHUNK_VARIABLES, // simple variables
PHYSDEF_VARIABLE_FLAGS = 0x00,
PHYSDEF_VARIABLE_MODELNAME,
PHYSDEF_VARIABLE_ISPRELIT,
};
PhysDefClass::PhysDefClass(void) :
ModelName ("NULL"),
IsPreLit(false)
{
FILENAME_PARAM(PhysDefClass,ModelName, "Westwood 3D Files", ".w3d");
}
bool PhysDefClass::Is_Valid_Config (StringClass &message)
{
bool retval = true;
if (ModelName.Is_Empty ()) {
message += "ModelName is invalid!\n";
retval = false;
}
return retval;
}
bool PhysDefClass::Save(ChunkSaveClass &csave)
{
csave.Begin_Chunk(PHYSDEF_CHUNK_DEFINITION);
DefinitionClass::Save(csave);
csave.End_Chunk();
csave.Begin_Chunk(PHYSDEF_CHUNK_VARIABLES);
WRITE_MICRO_CHUNK_WWSTRING(csave,PHYSDEF_VARIABLE_MODELNAME,ModelName);
WRITE_MICRO_CHUNK(csave,PHYSDEF_VARIABLE_ISPRELIT,IsPreLit);
csave.End_Chunk();
return true;
}
bool PhysDefClass::Load(ChunkLoadClass &cload)
{
while (cload.Open_Chunk()) {
switch(cload.Cur_Chunk_ID()) {
case PHYSDEF_CHUNK_DEFINITION:
DefinitionClass::Load(cload);
break;
case PHYSDEF_CHUNK_VARIABLES:
WWASSERT(cload.Cur_Chunk_ID() == PHYSDEF_CHUNK_VARIABLES);
while (cload.Open_Micro_Chunk()) {
switch(cload.Cur_Micro_Chunk_ID()) {
OBSOLETE_MICRO_CHUNK(PHYSDEF_VARIABLE_FLAGS);
READ_MICRO_CHUNK_WWSTRING(cload,PHYSDEF_VARIABLE_MODELNAME,ModelName);
READ_MICRO_CHUNK(cload,PHYSDEF_VARIABLE_ISPRELIT,IsPreLit);
}
cload.Close_Micro_Chunk();
}
break;
}
cload.Close_Chunk();
}
return true;
}
bool PhysDefClass::Is_Type(const char * type_name)
{
if (stricmp(type_name,PhysDefClass::Get_Type_Name()) == 0) {
return true;
} else {
return false;
}
}