| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681 |
- /*
- ** Command & Conquer Generals Zero Hour(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 : WWShade *
- * *
- * $Archive:: wwshade/shdmesh.cpp $*
- * *
- * Org Author:: Jani P *
- * *
- * Author : Kenny Mitchell *
- * *
- * $Modtime:: 07/12/02 10:31a $*
- * *
- * $Revision:: 1 $*
- * *
- *---------------------------------------------------------------------------------------------*
- *---------------------------------------------------------------------------------------------*/
- #include "shdmesh.h"
- #include "shdsubmesh.h"
- #include "shdrenderer.h"
- #include "rinfo.h"
- #include "camera.h"
- #include "dx8wrapper.h"
- #include "wwdebug.h"
- #include "wwprofile.h"
- #include "mesh.h"
- #include "meshmdl.h"
- ShdMeshClass::ShdMeshClass()
- : Name("UnNamed"),
- LightEnvironment(NULL),
- Applying_Shadow_Map(false)
- {
- }
- ShdMeshClass::ShdMeshClass(const ShdMeshClass & src)
- : RenderObjClass(src),
- Name(src.Name),
- LightEnvironment(NULL),
- Applying_Shadow_Map(false)
- {
- Free();
- SubMeshes.Resize(src.SubMeshes.Length());
- for (int i=0;i<SubMeshes.Length();++i)
- {
- SubMeshes[i].Mesh=NULL;
- SubMeshes[i].Renderer=NULL;
- REF_PTR_SET(SubMeshes[i].Mesh,src.SubMeshes[i].Mesh);
- }
- }
- ShdMeshClass::~ShdMeshClass()
- {
- Free();
- // TODO TODO TODO!!!!!
- }
- RenderObjClass * ShdMeshClass::Clone() const
- {
- return new ShdMeshClass(*this);
- }
- const char * ShdMeshClass::Get_Name() const
- {
- return Name;
- }
- void ShdMeshClass::Set_Name(const char * name)
- {
- Name = name;
- }
- /***********************************************************************************************
- * ShdMeshClass::Free -- Releases all memory/assets in use by this mesh *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 1/6/98 GTH : Created. *
- *=============================================================================================*/
- void ShdMeshClass::Free()
- {
- for (int i=0;i<SubMeshes.Length();++i)
- {
- REF_PTR_RELEASE(SubMeshes[i].Mesh);
- if (SubMeshes[i].Renderer)
- {
- delete SubMeshes[i].Renderer;
- SubMeshes[i].Renderer=NULL;
- }
- }
- }
-
- int ShdMeshClass::Get_Num_Polys() const
- {
- int count = 0;
- for (int i=0; i<SubMeshes.Length(); i++)
- {
- count+= SubMeshes[i].Mesh->Get_Polygon_Count();
- }
- return count;
- }
- int ShdMeshClass::Get_Num_Vertices(void) const
- {
- int count = 0;
- for (int i=0; i<SubMeshes.Length(); i++)
- {
- count+= SubMeshes[i].Mesh->Get_Vertex_Count();
- }
- return count;
- }
- void ShdMeshClass::Render(RenderInfoClass& rinfo)
- {
- WWPROFILE("ShdMeshClass::Render");
- if (Is_Not_Hidden_At_All() == false)
- {
- return;
- }
- // DX8_RECORD_MESH_RENDER();
- // TODO: Static sort lists
- Set_Lighting_Environment(rinfo.light_environment);
- const FrustumClass & frustum=rinfo.Camera.Get_Frustum();
- // if rendering shadow remember camera info
- if ((rinfo.Current_Override_Flags()&RenderInfoClass::RINFO_OVERRIDE_SHADOW_RENDERING))
- {
- // is generating shadow map
- Set_Is_Self_Shadowed();
- // set texture projector
- Texture_Projector=rinfo.Texture_Projector;
- Unset_Is_Applying_Shadow_Map();
- }
- else if (Is_Self_Shadowed())
- {
- // is applying shadow map
- Set_Is_Applying_Shadow_Map();
- Unset_Is_Self_Shadowed();
- }
- else
- {
- Unset_Is_Applying_Shadow_Map();
- }
- // TODO: What to do with SKINS?
- if (1)//CollisionMath::Overlap_Test(frustum,Get_Bounding_Box())!=CollisionMath::OUTSIDE )
- {
- // bool rendered_something = false;
- // TODO: Override flags, decals and material passes (probably in the submesh rendering)
- for (int i=0;i<SubMeshes.Length();++i)
- {
- if (!SubMeshes[i].Renderer)
- {
- SubMeshes[i].Renderer=ShdRendererClass::Peek_Instance()->Register_Mesh(this,SubMeshes[i].Mesh);
- }
- SubMeshes[i].Renderer->Render(rinfo);
- }
- // TODO: RendererDebugger
- }
- }
- //void ShdMeshClass::Render_Material_Pass(MaterialPassClass * pass,IndexBufferClass * ib)
- //{
- //
- //}
- void ShdMeshClass::Special_Render(SpecialRenderInfoClass & rinfo)
- {
- }
- /***********************************************************************************************
- * ShdMeshClass::Cast_Ray -- compute a ray intersection with this mesh *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 6/17/98 GTH : Created. *
- *=============================================================================================*/
- bool ShdMeshClass::Cast_Ray(RayCollisionTestClass & raytest)
- {
- if ((Get_Collision_Type() & raytest.CollisionType) == 0) return false;
- if ((Is_Translucent()!=0) && (!raytest.CheckTranslucent)) return false;
- if (Is_Animation_Hidden()) return false;
- if (raytest.Result->StartBad) return false;
- Matrix3D world_to_obj;
- Matrix3D world=Get_Transform();
- // if aligned or oriented rotate the mesh so that it's aligned to the ray
- /* if (Model->Get_Flag(MeshModelClass::ALIGNED)) {
- Vector3 mesh_position;
- world.Get_Translation(&mesh_position);
- world.Obj_Look_At(mesh_position,mesh_position - raytest.Ray.Get_Dir(),0.0f);
- } else if (Model->Get_Flag(MeshModelClass::ORIENTED)) {
- Vector3 mesh_position;
- world.Get_Translation(&mesh_position);
- world.Obj_Look_At(mesh_position,raytest.Ray.Get_P0(),0.0f);
- }
- */
- world.Get_Orthogonal_Inverse(world_to_obj);
- RayCollisionTestClass objray(raytest,world_to_obj);
- for (int i=0;i<SubMeshes.Length();++i) {
- if (SubMeshes[i].Mesh->Cast_Ray(objray)) {
- // transform result back into original coordinate system
- raytest.CollidedRenderObj = this;
- Matrix3D::Rotate_Vector(world,raytest.Result->Normal, &(raytest.Result->Normal));
- if (raytest.Result->ComputeContactPoint) {
- Matrix3D::Transform_Vector(world,raytest.Result->ContactPoint, &(raytest.Result->ContactPoint));
- }
- return true;
- }
- }
-
- return false;
- }
- /***********************************************************************************************
- * ShdMeshClass::Cast_AABox -- cast an AABox against this mesh *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 6/17/98 GTH : Created. *
- *=============================================================================================*/
- bool ShdMeshClass::Cast_AABox(AABoxCollisionTestClass & boxtest)
- {
- if ((Get_Collision_Type() & boxtest.CollisionType) == 0) return false;
- if (boxtest.Result->StartBad) return false;
- for (int i=0;i<SubMeshes.Length();++i) {
- // This function analyses the tranform to call optimized functions in certain cases
- if (SubMeshes[i].Mesh->Cast_World_Space_AABox(boxtest, Get_Transform())) {
- boxtest.CollidedRenderObj = this;
- return true;
- }
- }
- return false;
- }
- /***********************************************************************************************
- * Cast_OBBox -- Cast an obbox against this mesh *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 6/17/98 GTH : Created. *
- *=============================================================================================*/
- bool ShdMeshClass::Cast_OBBox(OBBoxCollisionTestClass & boxtest)
- {
- if ((Get_Collision_Type() & boxtest.CollisionType) == 0) return false;
- if (boxtest.Result->StartBad) return false;
- /*
- ** transform into the local coordinate system of the mesh.
- */
- const Matrix3D & tm = Get_Transform();
- Matrix3D world_to_obj;
- tm.Get_Orthogonal_Inverse(world_to_obj);
- OBBoxCollisionTestClass localtest(boxtest,world_to_obj);
- for (int i=0;i<SubMeshes.Length();++i) {
- if (SubMeshes[i].Mesh->Cast_OBBox(localtest)) {
- /*
- ** If we hit, transform the result of the test back to the original coordinate system.
- */
- boxtest.CollidedRenderObj = this;
- Matrix3D::Rotate_Vector(tm,boxtest.Result->Normal, &(boxtest.Result->Normal));
- if (boxtest.Result->ComputeContactPoint) {
- Matrix3D::Transform_Vector(tm,boxtest.Result->ContactPoint, &(boxtest.Result->ContactPoint));
- }
- return true;
- }
- }
- return false;
- }
- /***********************************************************************************************
- * ShdMeshClass::Intersect_AABox -- test for intersection with given AABox *
- * *
- * The AAbox given is assumed to be in world space. Since meshes aren't generally in world *
- * space, the test must be transformed into our local coordinate system (which turns it into *
- * an OBBox...) *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 1/19/00 gth : Created. *
- *=============================================================================================*/
- bool ShdMeshClass::Intersect_AABox(AABoxIntersectionTestClass & boxtest)
- {
- if ((Get_Collision_Type() & boxtest.CollisionType) == 0) return false;
- Matrix3D inv_tm;
- Get_Transform().Get_Orthogonal_Inverse(inv_tm);
- OBBoxIntersectionTestClass local_test(boxtest,inv_tm);
-
- for (int i=0;i<SubMeshes.Length();++i) {
- if (SubMeshes[i].Mesh->Intersect_OBBox(local_test)) return true;
- }
- return false;
- }
- /***********************************************************************************************
- * ShdMeshClass::Intersect_OBBox -- test for intersection with the given OBBox *
- * *
- * The given OBBox is assumed to be in world space so we need to transform it into the mesh's *
- * local coordinate system. *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 1/19/00 gth : Created. *
- *=============================================================================================*/
- bool ShdMeshClass::Intersect_OBBox(OBBoxIntersectionTestClass & boxtest)
- {
- if ((Get_Collision_Type() & boxtest.CollisionType) == 0) return false;
- Matrix3D inv_tm;
- Get_Transform().Get_Orthogonal_Inverse(inv_tm);
- OBBoxIntersectionTestClass local_test(boxtest,inv_tm);
- for (int i=0;i<SubMeshes.Length();++i) {
- if (SubMeshes[i].Mesh->Intersect_OBBox(local_test)) return true;
- }
- return false;
- }
- /***********************************************************************************************
- * ShdMeshClass::Add_Dependencies_To_List -- Add dependent files to the list. *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 3/18/99 PDS : Created. *
- * 6/05/02 KJM : Added dependency calculation for shader system
- *=============================================================================================*/
- void ShdMeshClass::Add_Dependencies_To_List
- (
- DynamicVectorClass<StringClass> &file_list,
- bool textures_only
- )
- {
- // loop through sub meshes
- for (int i=0;i<SubMeshes.Length();i++)
- {
- ShdInterfaceClass* shd=SubMeshes[i].Mesh->Peek_Shader();
-
- for (int tidx=0;tidx<shd->Get_Texture_Count();tidx++)
- {
- TextureClass* texture=shd->Peek_Texture(tidx);
- if (texture)
- {
- file_list.Add(texture->Get_Full_Path());
- }
- }
- }
- RenderObjClass::Add_Dependencies_To_List (file_list, textures_only);
- return ;
- }
- /***********************************************************************************************
- * ShdMeshClass::Update_Cached_Bounding_Volumes -- default collision sphere. *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 5/14/2001 NH : Created. *
- *=============================================================================================*/
- void ShdMeshClass::Update_Cached_Bounding_Volumes(void) const
- {
- Get_Obj_Space_Bounding_Sphere(CachedBoundingSphere);
- Matrix3D::Transform_Vector(Get_Transform(),CachedBoundingSphere.Center,&CachedBoundingSphere.Center);
- // If we are camera-aligned or -oriented, we don't know which way we are facing at this point,
- // so the box we return needs to contain the sphere. Otherewise do the normal computation.
- /* if (Model->Get_Flag(MeshModelClass::ALIGNED) || Model->Get_Flag(MeshModelClass::ORIENTED)) {
- CachedBoundingBox.Center = CachedBoundingSphere.Center;
- CachedBoundingBox.Extent.Set(CachedBoundingSphere.Radius, CachedBoundingSphere.Radius, CachedBoundingSphere.Radius);
- } else {
- */ Get_Obj_Space_Bounding_Box(CachedBoundingBox);
- CachedBoundingBox.Transform(Get_Transform());
- // }
- Validate_Cached_Bounding_Volumes();
- }
- /***********************************************************************************************
- * ShdMeshClass::Get_Obj_Space_Bounding_Sphere -- returns obj-space bounding sphere *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 1/19/00 gth : Created. *
- *=============================================================================================*/
- void ShdMeshClass::Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const
- {
- if (SubMeshes.Length()) {
- SubMeshes[0].Mesh->Get_Bounding_Sphere(&sphere);
- // If there are more than one submesh, merge all bounding spheres
- for (int i=1;i<SubMeshes.Length();++i) {
- SphereClass tmp_s;
- SubMeshes[i].Mesh->Get_Bounding_Sphere(&tmp_s);
- sphere+=tmp_s;
- }
- }
- else {
- sphere.Center.Set(0,0,0);
- sphere.Radius = 1.0f;
- }
- }
- /***********************************************************************************************
- * ShdMeshClass::Get_Obj_Space_Bounding_Box -- returns the obj-space bounding box *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 1/19/00 gth : Created. *
- *=============================================================================================*/
- void ShdMeshClass::Get_Obj_Space_Bounding_Box(AABoxClass & box) const
- {
- if (SubMeshes.Length()) {
- SubMeshes[0].Mesh->Get_Bounding_Box(&box);
- // If there are more than one submesh, merge all bounding boxes
- for (int i=1;i<SubMeshes.Length();++i) {
- AABoxClass tmp_b;
- SubMeshes[i].Mesh->Get_Bounding_Box(&tmp_b);
-
- box.Add_Box(tmp_b);
- }
- }
- else {
- box.Init(Vector3(0,0,0),Vector3(1,1,1));
- }
- }
- void ShdMeshClass::Init_From_Legacy_Mesh(MeshClass* mesh)
- {
- Set_Name(mesh->Get_Name());
- MeshModelClass* model=mesh->Peek_Model();
- if (model)
- {
- int first_poly=0;
- int sub_mesh_count=0;
- while (first_poly<model->Get_Polygon_Count()) {
- sub_mesh_count++;
- ShdSubMeshClass * sub_mesh = NEW_REF( ShdSubMeshClass, () );
- sub_mesh->Init_From_Legacy_Mesh_Model(model,first_poly);
- SubMeshes.Resize(sub_mesh_count);
- SubMeshes[sub_mesh_count-1].Mesh=sub_mesh;
- SubMeshes[sub_mesh_count-1].Renderer=NULL;
- if (sub_mesh->Get_Visible_Polygon_Count()==0) break;
- first_poly+=sub_mesh->Get_Visible_Polygon_Count();
- }
- }
- // Pull interesting stuff out of the w3d attributes bits
- Set_Collision_Type(mesh->Get_Collision_Type());
- Set_Hidden(mesh->Is_Hidden());
- Set_Translucent(mesh->Is_Translucent());
- }
- /***********************************************************************************************
- * ShdMeshClass::Load -- creates a shader mesh out of a shader mesh chunk in a .w3d file *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 05/21/2002 KM : Created. *
- *=============================================================================================*/
- WW3DErrorType ShdMeshClass::Load_W3D(ChunkLoadClass& cload)
- {
- // Open the first chunk, it should be the shader mesh name
- cload.Open_Chunk();
-
- if (cload.Cur_Chunk_ID()!=W3D_CHUNK_SHDMESH_NAME)
- {
- WWDEBUG_SAY(("Invalid format shader mesh.\n"));
- return WW3D_ERROR_LOAD_FAILED;
- }
- // read name
- char buf[MAX_PATH];
- cload.Read(buf,cload.Cur_Chunk_Length());
- cload.Close_Chunk();
- Set_Name(buf);
- // open header
- W3dShdMeshHeaderStruct hdr;
- cload.Open_Chunk();
- if
- (
- cload.Read
- (
- &hdr,
- sizeof(W3dShdMeshHeaderStruct)
- )!=sizeof(W3dShdMeshHeaderStruct)
- )
- {
- return WW3D_ERROR_LOAD_FAILED;
- }
- cload.Close_Chunk();
- // Process the header
- // Set Bounding Info
- Vector3 min(hdr.BoxMin.X,hdr.BoxMin.Y,hdr.BoxMin.Z);
- Vector3 max(hdr.BoxMax.X,hdr.BoxMax.Y,hdr.BoxMax.Z);
- CachedBoundingBox.Init_Min_Max(min,max);
- Vector3 cntr(hdr.SphCenter.X,hdr.SphCenter.Y,hdr.SphCenter.Z);
- CachedBoundingSphere.Init(cntr,hdr.SphRadius);
- // Flags (todo)
- // user text
-
- // next are the sub meshes
- Free();
- SubMeshes.Resize(hdr.NumSubMeshes);
- for (int i=0;i<SubMeshes.Length(); )
- {
- cload.Open_Chunk();
- if (cload.Cur_Chunk_ID()==W3D_CHUNK_SHDMESH_USER_TEXT)
- {
- // todo
- cload.Read(buf,cload.Cur_Chunk_Length());
- }
- else
- {
- ShdSubMeshClass* ssmesh=NEW_REF(ShdSubMeshClass,());
- if (ssmesh==NULL)
- {
- WWDEBUG_SAY(("ShdMeshClass::Load_W3D - Failed to allocate sub mesh\r\n"));
- return WW3D_ERROR_LOAD_FAILED;
- }
- SubMeshes[i].Mesh=ssmesh;
- SubMeshes[i].Renderer=NULL;
- REF_PTR_SET(SubMeshes[i].Mesh,SubMeshes[i].Mesh);
- ssmesh->Load_W3D(cload);
-
- // assign each sub-mesh with a name in the format: <parentmesh>.<index>
- StringClass tmp;
- tmp.Format("%s.%d",Name,i);
- ssmesh->Set_Name(tmp);
-
- i++;
- }
- cload.Close_Chunk();
- }
- // Pull interesting stuff out of the w3d attributes bits
- int col_bits = (hdr.Attributes & W3D_MESH_FLAG_COLLISION_TYPE_MASK) >> W3D_MESH_FLAG_COLLISION_TYPE_SHIFT;
- Set_Collision_Type( col_bits << 1 );
- Set_Hidden(hdr.Attributes & W3D_MESH_FLAG_HIDDEN);
-
- for (i=0;i<SubMeshes.Length(); i++) {
- bool shadow = (hdr.Attributes & W3D_MESH_FLAG_CAST_SHADOW) == W3D_MESH_FLAG_CAST_SHADOW;
- SubMeshes[i].Mesh->Set_Flag(MeshGeometryClass::CAST_SHADOW,shadow);
- }
-
- // Indicate whether this mesh is translucent. The mesh is considered translucent
- // if sorting has been enabled (alpha blending on pass 0) or if pass0 contains alpha-test.
- // This flag is used to determine if the mesh can cast a geometric shadow.
- bool is_translucent = false;
- for (i=0;i<SubMeshes.Length(); i++) {
- if (SubMeshes[i].Mesh) {
- if (SubMeshes[i].Mesh->Is_Sorting()) {
- Set_Translucent(true);
- }
- ShdInterfaceClass * shader = SubMeshes[i].Mesh->Peek_Shader();
- if ((shader) && (!shader->Is_Opaque())) {
- Set_Translucent(true);
- }
- }
- }
- return WW3D_ERROR_OK;
- }
- int ShdMeshClass::Get_Sub_Mesh_Count(void) const
- {
- return SubMeshes.Length();
- }
- ShdSubMeshClass * ShdMeshClass::Peek_Sub_Mesh(int i) const
- {
- return SubMeshes[i].Mesh;
- }
|