| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018 |
- /*
- ** Command & Conquer Generals(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/meshgeometry.cpp $*
- * *
- * Original Author:: Greg Hjelstrom *
- * *
- * $Author:: Vss_sync $*
- * *
- * $Modtime:: 8/29/01 7:29p $*
- * *
- * $Revision:: 13 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * MeshGeometryClass::MeshGeometryClass -- Constructor *
- * MeshGeometryClass::MeshGeometryClass -- Copy Constructor *
- * -- assignment operator *
- * MeshGeometryClass::~MeshGeometryClass -- destructor *
- * MeshGeometryClass::Reset_Geometry -- releases current resources and allocates space if ne *
- * MeshGeometryClass::Get_Name -- returns the name *
- * MeshGeometryClass::Set_Name -- set the name of this model *
- * MeshGeometryClass::Get_User_Text -- get the user-text buffer *
- * MeshGeometryClass::Set_User_Text -- set the user text buffer *
- * MeshGeometryClass::Get_Bounding_Box -- get the bounding box *
- * MeshGeometryClass::Get_Bounding_Sphere -- get the bounding sphere *
- * MeshGeometryClass::Generate_Rigid_APT -- generate active polygon table *
- * MeshGeometryClass::Generate_Skin_APT -- generate an active polygon table *
- * MeshGeometryClass::Contains -- test if the mesh contains the given point *
- * MeshGeometryClass::Cast_Ray -- compute a ray intersection with this mesh *
- * MeshGeometryClass::Cast_AABox -- cast an AABox against this mesh *
- * MeshGeometryClass::Cast_OBBox -- Cast an obbox against this mesh *
- * MeshGeometryClass::Intersect_OBBox -- test for intersection with the given OBBox *
- * MeshGeometryClass::Cast_World_Space_AABox -- test for intersection with a worldspace AABox*
- * MeshGeometryClass::cast_semi_infinite_axis_aligned_ray -- casts an axis aligned ray *
- * MeshGeometryClass::cast_aabox_identity -- aligned aabox test *
- * MeshGeometryClass::cast_aabox_z90 -- aabox test which is rotated about z by 90 *
- * MeshGeometryClass::cast_aabox_z180 -- aabox test which is rotated about z by 180 *
- * MeshGeometryClass::cast_aabox_z270 -- aabox test which is rotated about z by 270 *
- * MeshGeometryClass::cast_ray_brute_force -- brute force ray-cast *
- * MeshGeometryClass::cast_aabox_brute_force -- brute force aabox cast *
- * MeshGeometryClass::cast_obbox_brute_force -- brute force obbox cast *
- * MeshGeometryClass::intersect_obbox_brute_force -- brute force intersection check *
- * MeshGeometryClass::Compute_Plane_Equations -- Recalculates the plane equations *
- * MeshGeometryClass::Compute_Vertex_Normals -- recompute the vertex normals *
- * MeshGeometryClass::Compute_Bounds -- recomputes the bounding volumes *
- * MeshGeometryClass::get_vert_normals -- get the vertex normal array *
- * MeshGeometryClass::Get_Vertex_Normal_Array -- validates and returns the vertex normal arr *
- * MeshGeometryClass::get_planes -- get the plane array memory (internal) *
- * MeshGeometryClass::Get_Plane_Array -- validates and returns the array of plane equations *
- * MeshGeometryClass::Compute_Plane -- compute the plane equation of a single poly *
- * MeshGeometryClass::Generate_Culling_Tree -- Generate an AABTree for this mesh *
- * MeshGeometryClass::Load_W3D -- Load a mesh from a w3d *
- * MeshGeometryClass::read_chunks -- read w3d chunks *
- * MeshGeometryClass::read_vertices -- read the vertex chunk from a W3D file *
- * MeshGeometryClass::read_vertex_normals -- read the vertex normals chunk from a w3d file *
- * MeshGeometryClass::read_triangles -- read the triangles chunk from a w3d file *
- * MeshGeometryClass::read_user_text -- read the user text chunk from a w3d file *
- * MeshGeometryClass::read_vertex_influences -- read the vertex influences chunk from a w3d *
- * MeshGeometryClass::read_vertex_shade_indices -- read the vertex shade indices chunk *
- * MeshGeometryClass::read_aabtree -- read the AABTree chunk from a w3d file *
- * MeshGeometryClass::Generate_APT -- generate an apt for a box and view direction *
- * MeshGeometryClass::Generate_Rigid_APT -- generate an apt using backface culling *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "meshgeometry.h"
- #include "aabtree.h"
- #include "chunkio.h"
- #include "aabox.h"
- #include "obbox.h"
- #include "sphere.h"
- #include "plane.h"
- #include "wwdebug.h"
- #include "wwmemlog.h"
- #include "w3d_file.h"
- #include "vp.h"
- #if (OPTIMIZE_PLANEEQ_RAM)
- static SimpleVecClass<Vector4> _PlaneEQArray(1024);
- #endif
- #if (OPTIMIZE_VNORM_RAM)
- static SimpleVecClass<Vector3> _VNormArray(1024);
- #endif
- /***********************************************************************************************
- * MeshGeometryClass::MeshGeometryClass -- Constructor *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/9/2000 gth : Created. *
- *=============================================================================================*/
- MeshGeometryClass::MeshGeometryClass(void) :
- MeshName(NULL),
- UserText(NULL),
- Flags(0),
- SortLevel(SORT_LEVEL_NONE),
- W3dAttributes(0),
- PolyCount(0),
- VertexCount(0),
- Poly(NULL),
- PolySurfaceType(NULL),
- Vertex(NULL),
- VertexNorm(NULL),
- PlaneEq(NULL),
- VertexShadeIdx(NULL),
- VertexBoneLink(NULL),
- BoundBoxMin(0,0,0),
- BoundBoxMax(1,1,1),
- BoundSphereCenter(0,0,0),
- BoundSphereRadius(1),
- CullTree(NULL)
- {
- }
- /***********************************************************************************************
- * MeshGeometryClass::MeshGeometryClass -- Copy Constructor *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/9/2000 gth : Created. *
- *=============================================================================================*/
- MeshGeometryClass::MeshGeometryClass(const MeshGeometryClass & that) :
- MeshName(NULL),
- UserText(NULL),
- Flags(0),
- SortLevel(SORT_LEVEL_NONE),
- W3dAttributes(0),
- PolyCount(0),
- VertexCount(0),
- Poly(NULL),
- PolySurfaceType(NULL),
- Vertex(NULL),
- VertexNorm(NULL),
- PlaneEq(NULL),
- VertexShadeIdx(NULL),
- VertexBoneLink(NULL),
- BoundBoxMin(0,0,0),
- BoundBoxMax(1,1,1),
- BoundSphereCenter(0,0,0),
- BoundSphereRadius(1),
- CullTree(NULL)
- {
- *this = that;
- }
- /***********************************************************************************************
- * -- assignment operator *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/9/2000 gth : Created. *
- *=============================================================================================*/
- MeshGeometryClass & MeshGeometryClass::operator = (const MeshGeometryClass & that)
- {
- if (this != &that) {
- Flags = that.Flags;
- SortLevel = that.SortLevel;
- W3dAttributes = that.W3dAttributes;
- PolyCount = that.PolyCount;
- VertexCount = that.VertexCount;
- BoundBoxMin = that.BoundBoxMin;
- BoundBoxMax = that.BoundBoxMax;
- BoundSphereCenter = that.BoundSphereCenter;
- BoundSphereRadius = that.BoundSphereRadius;
- REF_PTR_SET(MeshName,that.MeshName);
- REF_PTR_SET(UserText,that.UserText);
- REF_PTR_SET(Poly,that.Poly);
- REF_PTR_SET(PolySurfaceType,that.PolySurfaceType);
- REF_PTR_SET(Vertex,that.Vertex);
- REF_PTR_SET(VertexNorm,that.VertexNorm);
- REF_PTR_SET(PlaneEq,that.PlaneEq);
- REF_PTR_SET(VertexShadeIdx,that.VertexShadeIdx);
- REF_PTR_SET(VertexBoneLink,that.VertexBoneLink);
- REF_PTR_SET(CullTree,that.CullTree);
- }
- return * this;
- }
- /***********************************************************************************************
- * MeshGeometryClass::~MeshGeometryClass -- destructor *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/9/2000 gth : Created. *
- *=============================================================================================*/
- MeshGeometryClass::~MeshGeometryClass(void)
- {
- Reset_Geometry(0,0);
- }
- /***********************************************************************************************
- * MeshGeometryClass::Reset_Geometry -- releases current resources and allocates space if need *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/9/2000 gth : Created. *
- *=============================================================================================*/
- void MeshGeometryClass::Reset_Geometry(int polycount,int vertcount)
- {
- // Release everything we have and reset to initial state
- Flags = 0;
- PolyCount = 0;
- VertexCount = 0;
- SortLevel = SORT_LEVEL_NONE;
- REF_PTR_RELEASE(MeshName);
- REF_PTR_RELEASE(UserText);
- REF_PTR_RELEASE(Poly);
- REF_PTR_RELEASE(PolySurfaceType);
- REF_PTR_RELEASE(Vertex);
- REF_PTR_RELEASE(VertexNorm);
- REF_PTR_RELEASE(PlaneEq);
- REF_PTR_RELEASE(VertexShadeIdx);
- REF_PTR_RELEASE(VertexBoneLink);
- REF_PTR_RELEASE(CullTree);
- PolyCount = polycount;
- VertexCount = vertcount;
- // allocate new geometry arrays
- if ((polycount != 0) && (vertcount != 0)) {
- Poly = NEW_REF(ShareBufferClass<Vector3i>,(PolyCount, "MeshGeometryClass::Poly"));
- PolySurfaceType = NEW_REF(ShareBufferClass<uint8>,(PolyCount, "MeshGeometryClass::PolySurfaceType"));
- Vertex = NEW_REF(ShareBufferClass<Vector3>,(VertexCount, "MeshGeometryClass::Vertex"));
- Poly->Clear();
- PolySurfaceType->Clear();
- Vertex->Clear();
- #if (!OPTIMIZE_VNORM_RAM)
- VertexNorm = NEW_REF(ShareBufferClass<Vector3>,(VertexCount, "MeshGeometryClass::VertexNorm"));
- VertexNorm->Clear();
- #endif
- }
- return ;
- }
- /***********************************************************************************************
- * MeshGeometryClass::Get_Name -- returns the name *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/9/2000 gth : Created. *
- *=============================================================================================*/
- const char * MeshGeometryClass::Get_Name(void) const
- {
- if (MeshName) {
- return MeshName->Get_Array();
- }
- return NULL;
- }
- /***********************************************************************************************
- * MeshGeometryClass::Set_Name -- set the name of this model *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/9/2000 gth : Created. *
- *=============================================================================================*/
- void MeshGeometryClass::Set_Name(const char * newname)
- {
- if (MeshName) {
- MeshName->Release_Ref();
- }
- if (newname) {
- MeshName = NEW_REF(ShareBufferClass<char>,(strlen(newname)+1, "MeshGeometryClass::MeshName"));
- strcpy(MeshName->Get_Array(),newname);
- }
- }
- /***********************************************************************************************
- * MeshGeometryClass::Get_User_Text -- get the user-text buffer *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/9/2000 gth : Created. *
- *=============================================================================================*/
- const char * MeshGeometryClass::Get_User_Text(void)
- {
- if (UserText) {
- return UserText->Get_Array();
- }
- return NULL;
- }
- /***********************************************************************************************
- * MeshGeometryClass::Set_User_Text -- set the user text buffer *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/9/2000 gth : Created. *
- *=============================================================================================*/
- void MeshGeometryClass::Set_User_Text(char * usertext)
- {
- if (UserText) {
- UserText->Release_Ref();
- }
- if (usertext) {
- UserText = NEW_REF(ShareBufferClass<char>,(strlen(usertext)+1, "MeshGeometryClass::UserText"));
- strcpy(UserText->Get_Array(),usertext);
- }
- }
- /***********************************************************************************************
- * MeshGeometryClass::Get_Bounding_Box -- get the bounding box *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/9/2000 gth : Created. *
- *=============================================================================================*/
- void MeshGeometryClass::Get_Bounding_Box(AABoxClass * set_box)
- {
- WWASSERT(set_box != NULL);
- set_box->Center = (BoundBoxMax + BoundBoxMin) * 0.5f;
- set_box->Extent = (BoundBoxMax - BoundBoxMin) * 0.5f;
- }
- /***********************************************************************************************
- * MeshGeometryClass::Get_Bounding_Sphere -- get the bounding sphere *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/9/2000 gth : Created. *
- *=============================================================================================*/
- void MeshGeometryClass::Get_Bounding_Sphere(SphereClass * set_sphere)
- {
- WWASSERT(set_sphere != NULL);
- set_sphere->Center = BoundSphereCenter;
- set_sphere->Radius = BoundSphereRadius;
- }
- /***********************************************************************************************
- * MeshGeometryClass::Generate_Rigid_APT -- generate an apt using backface culling *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 5/10/2001 gth : Created. *
- *=============================================================================================*/
- void MeshGeometryClass::Generate_Rigid_APT(const Vector3 & view_dir, SimpleDynVecClass<uint32> & apt)
- {
- const Vector3 * loc = Get_Vertex_Array();
- const Vector4 * norms = Get_Plane_Array();
- const Vector3i * polys = Get_Polygon_Array();
- TriClass tri;
- for (int poly_counter = 0; poly_counter < PolyCount; poly_counter++) {
- tri.V[0] = &(loc[ polys[poly_counter][0] ]);
- tri.V[1] = &(loc[ polys[poly_counter][1] ]);
- tri.V[2] = &(loc[ polys[poly_counter][2] ]);
- tri.N = (Vector3*)&(norms[poly_counter]);
-
- if (Vector3::Dot_Product(*tri.N,view_dir) < 0.0f) {
- apt.Add(poly_counter);
- }
- }
- }
- /***********************************************************************************************
- * MeshGeometryClass::Generate_Rigid_APT -- generate active polygon table *
- * *
- * This function will cull the mesh against the specified volume *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/9/2000 gth : Created. *
- *=============================================================================================*/
- void MeshGeometryClass::Generate_Rigid_APT(const OBBoxClass & local_box, SimpleDynVecClass<uint32> & apt)
- {
- if (CullTree != NULL) {
- CullTree->Generate_APT(local_box, apt);
- } else {
- // Beware, this is gonna be expensive!
- const Vector3 * loc = Get_Vertex_Array();
- const Vector4 * norms = Get_Plane_Array();
- const Vector3i * polys = Get_Polygon_Array();
- TriClass tri;
- for (int poly_counter = 0; poly_counter < PolyCount; poly_counter++) {
- tri.V[0] = &(loc[ polys[poly_counter][0] ]);
- tri.V[1] = &(loc[ polys[poly_counter][1] ]);
- tri.V[2] = &(loc[ polys[poly_counter][2] ]);
- tri.N = (Vector3*)&(norms[poly_counter]);
-
- if (CollisionMath::Intersection_Test(local_box, tri)) {;
- apt.Add(poly_counter);
- }
- }
- }
- }
- /***********************************************************************************************
- * MeshGeometryClass::Generate_APT -- generate an apt for a box and view direction *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 5/10/2001 gth : Created. *
- *=============================================================================================*/
- void MeshGeometryClass::Generate_Rigid_APT(const OBBoxClass & local_box,const Vector3 & viewdir,SimpleDynVecClass<uint32> & apt)
- {
- if (CullTree != NULL) {
- CullTree->Generate_APT(local_box, viewdir,apt);
- } else {
- // Beware, this is gonna be expensive!
- const Vector3 * loc = Get_Vertex_Array();
- const Vector4 * norms = Get_Plane_Array();
- const Vector3i * polys = Get_Polygon_Array();
- TriClass tri;
- for (int poly_counter = 0; poly_counter < PolyCount; poly_counter++) {
- tri.V[0] = &(loc[ polys[poly_counter][0] ]);
- tri.V[1] = &(loc[ polys[poly_counter][1] ]);
- tri.V[2] = &(loc[ polys[poly_counter][2] ]);
- tri.N = (Vector3*)&(norms[poly_counter]);
-
- if (Vector3::Dot_Product(*tri.N,viewdir) < 0.0f) {
- if (CollisionMath::Intersection_Test(local_box,tri)) {
- apt.Add(poly_counter);
- }
- }
- }
- }
- }
- /***********************************************************************************************
- * MeshGeometryClass::Generate_Skin_APT -- generate an active polygon table *
- * *
- * This function culls the mesh against the specified volume *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/9/2000 gth : Created. *
- *=============================================================================================*/
- void MeshGeometryClass::Generate_Skin_APT(const OBBoxClass & world_box, SimpleDynVecClass<uint32> & apt, const Vector3 *world_vertex_locs)
- {
- WWASSERT(world_vertex_locs);
- // Beware, this is gonna be expensive!
- const Vector3i * polys = Get_Polygon_Array();
- TriClass tri;
- for (int poly_counter=0; poly_counter < PolyCount; poly_counter++) {
- tri.V[0] = &(world_vertex_locs[ polys[poly_counter][0] ]);
- tri.V[1] = &(world_vertex_locs[ polys[poly_counter][1] ]);
- tri.V[2] = &(world_vertex_locs[ polys[poly_counter][2] ]);
- // We would have to do a non-trivial amount of computation to get the triangle normal
- // (since this is a skin we have no valid plane equations) and we know that N is not used
- // in the Intersection_Test, so we set it to a dummy value.
- static const Vector3 dummy_vec(0.0f, 0.0f, 1.0f);
- tri.N = &dummy_vec;
-
- if (CollisionMath::Intersection_Test(world_box,tri)) {;
- apt.Add(poly_counter);
- }
- }
- }
- /***********************************************************************************************
- * MeshGeometryClass::Contains -- test if the mesh contains the given point *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/9/2000 gth : Created. *
- *=============================================================================================*/
- bool MeshGeometryClass::Contains(const Vector3 &point)
- {
- // To determine whether the mesh contains a point, we will use the parity method (cast a
- // semi-infinite ray from the point and check the number of intersections with the mesh.
- // An even number of intersections means the point is outside the mesh, and an odd number
- // means the point is inside the mesh. Since we can cast the ray in any direction we will
- // use axis-aligned rays for speed.
- // The method fails if the ray goes through any triangle edge or corner. For robustness
- // we will cast rays in all six axis-aligned directions, and take a majority vote. We will
- // significantly reduce the weighting of rays which go through corners/edges.
- // Also, if any raycast reports that the point is embedded in a triangle, we will stop and
- // report that the point is contained in the mesh (using the normal algorithm in this case
- // could lead to errors).
- float yes = 0.0f; // weighted sum of rays indicating the point is contained in the mesh
- float no = 0.0f; // weighted sum of rays indicating the point is not contained in the mesh
- for (int axis_dir = 0; axis_dir < 6; axis_dir++) {
- unsigned char flags = TRI_RAYCAST_FLAG_NONE;
- int intersections = cast_semi_infinite_axis_aligned_ray(point, axis_dir, flags);
- if (flags & TRI_RAYCAST_FLAG_START_IN_TRI) return true;
- float weight = flags & TRI_RAYCAST_FLAG_HIT_EDGE ? 0.1f : 1.0f;
- if (intersections & 0x01) {
- yes += weight;
- } else {
- no += weight;
- }
- }
- return yes > no;
- }
- /***********************************************************************************************
- * MeshGeometryClass::Cast_Ray -- compute a ray intersection with this mesh *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 3/1/2001 NH : Created. *
- *=============================================================================================*/
- bool MeshGeometryClass::Cast_Ray(RayCollisionTestClass & raytest)
- {
- bool hit = false;
- if (CullTree) {
- hit = CullTree->Cast_Ray(raytest);
- } else {
- hit = cast_ray_brute_force(raytest);
- }
- return hit;
- }
-
- /***********************************************************************************************
- * MeshGeometryClass::Cast_AABox -- cast an AABox against this mesh *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 3/1/2001 NH : Created. *
- *=============================================================================================*/
- bool MeshGeometryClass::Cast_AABox(AABoxCollisionTestClass & boxtest)
- {
- bool hit = false;
-
- if (CullTree) {
- hit = CullTree->Cast_AABox(boxtest);
- } else {
- hit = cast_aabox_brute_force(boxtest);
- }
- return hit;
- }
-
- /***********************************************************************************************
- * MeshGeometryClass::Cast_OBBox -- Cast an obbox against this mesh *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 3/1/2001 NH : Created. *
- *=============================================================================================*/
- bool MeshGeometryClass::Cast_OBBox(OBBoxCollisionTestClass & boxtest)
- {
- bool hit = false;
- if (CullTree) {
- hit = CullTree->Cast_OBBox(boxtest);
- } else {
- hit = cast_obbox_brute_force(boxtest);
- }
- return hit;
- }
-
- /***********************************************************************************************
- * MeshGeometryClass::Intersect_OBBox -- test for intersection with the given OBBox *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 3/1/2001 NH : Created. *
- *=============================================================================================*/
- bool MeshGeometryClass::Intersect_OBBox(OBBoxIntersectionTestClass & boxtest)
- {
- bool hit = false;
- if (CullTree) {
- hit = CullTree->Intersect_OBBox(boxtest);
- } else {
- hit = intersect_obbox_brute_force(boxtest);
- }
- return hit;
- }
- /***********************************************************************************************
- * MeshGeometryClass::Cast_World_Space_AABox -- test for intersection with a worldspace AABox*
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 3/1/2001 NH : Created. *
- *=============================================================================================*/
- bool MeshGeometryClass::Cast_World_Space_AABox(AABoxCollisionTestClass & boxtest, const Matrix3D &transform)
- {
- /*
- ** Attempt to classify the transform:
- ** NOTE: This code assumes that the matrix is orthogonal! Much code in W3D assumes
- ** orthogonal matrices, if that convention is broken this code is also broken.
- ** Basically what I'm doing here is doing the minimum number of compares needed
- ** to identify a transform which is a 90 degree rotation about the z axis.
- ** TODO: cache some transform flags somewhere to reduce the number of times
- ** that these compares are done
- */
- bool hit = false;
-
- if ((transform[0][0] == 1.0f) && (transform[1][1] == 1.0f)) {
- hit = cast_aabox_identity(boxtest,-transform.Get_Translation());
-
- } else if ((transform[0][1] == -1.0f) && (transform[1][0] == 1.0f)) {
-
- // this mesh has been rotated 90 degrees about z
- hit = cast_aabox_z90(boxtest,-transform.Get_Translation());
-
- } else if ((transform[0][0] == -1.0f) && (transform[1][1] == -1.0f)) {
-
- // this mesh has been rotated 180
- hit = cast_aabox_z180(boxtest,-transform.Get_Translation());
-
- } else if ((transform[0][1] == 1.0f) && (transform[1][0] == -1.0f)) {
-
- // this mesh has been rotated 270
- hit = cast_aabox_z270(boxtest,-transform.Get_Translation());
-
- } else {
- /*
- ** Ok, we fell through to here, that means there is a more general
- ** transform on this mesh. In this case, I create a new test which
- ** is an oriented box test in the coordinate system of the mesh and cast it.
- */
- Matrix3D world_to_obj;
- transform.Get_Orthogonal_Inverse(world_to_obj);
- OBBoxCollisionTestClass obbox(boxtest, world_to_obj);
- if (CullTree) {
- hit = CullTree->Cast_OBBox(obbox);
- } else {
- hit = cast_obbox_brute_force(obbox);
- }
- /*
- ** now, we must transform the results of the test back to the original
- ** coordinate system.
- */
- if (hit) {
- Matrix3D::Rotate_Vector(transform, obbox.Result->Normal, &(obbox.Result->Normal));
- if (boxtest.Result->ComputeContactPoint) {
- Matrix3D::Transform_Vector(transform, obbox.Result->ContactPoint, &(obbox.Result->ContactPoint));
- }
- }
- }
- return hit;
- }
- /***********************************************************************************************
- * MeshGeometryClass::cast_semi_infinite_axis_aligned_ray -- casts an axis aligned ray *
- * *
- * This function is used by the 'Contains' function *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/9/2000 gth : Created. *
- *=============================================================================================*/
- int MeshGeometryClass::cast_semi_infinite_axis_aligned_ray(const Vector3 & start_point, int axis_dir,
- unsigned char & flags)
- {
- int count = 0;
- if (CullTree) {
- count = CullTree->Cast_Semi_Infinite_Axis_Aligned_Ray(start_point, axis_dir, flags);
- } else {
-
- const Vector3 * loc = Get_Vertex_Array();
- const Vector4 * plane = Get_Plane_Array();
- const Vector3i * polyverts = Get_Polygon_Array();
- // These tables translate between the axis_dir representation (which is an integer in which 0
- // indicates a ray along the positive x axis, 1 along the negative x axis, 2 the positive y
- // axis, 3 negative y axis, 4 positive z axis, 5 negative z axis) and a four-integer
- // representation (axis_r is the axis number - 0, 1 or 2 - of the axis along which the ray is
- // cast; axis_1 and axis_2 are the axis numbers of the other two axes; direction is 0 for
- // negative and 1 for positive direction of the ray).
- static const int axis_r[6] = { 0, 0, 1, 1, 2, 2 };
- static const int axis_1[6] = { 1, 1, 2, 2, 0, 0 };
- static const int axis_2[6] = { 2, 2, 0, 0, 1, 1 };
- static const int direction[6] = { 1, 0, 1, 0, 1, 0 };
- WWASSERT(axis_dir >= 0);
- WWASSERT(axis_dir < 6);
- // The functions called after this point will 'or' bits into this variable, so it needs to
- // be initialized here to TRI_RAYCAST_FLAG_NONE.
- flags = TRI_RAYCAST_FLAG_NONE;
- /*
- ** Loop over each polygon
- */
- int poly_count = Get_Polygon_Count();
- for (int poly_counter=0; poly_counter < poly_count; poly_counter++) {
-
- const Vector3 &v0 = loc[ polyverts[poly_counter][0] ];
- const Vector3 &v1 = loc[ polyverts[poly_counter][1] ];
- const Vector3 &v2 = loc[ polyverts[poly_counter][2] ];
- const Vector4 &tri_plane = plane[poly_counter];
- // Since (int)true is defined as 1, and (int)false as 0:
- count += (unsigned int)Cast_Semi_Infinite_Axis_Aligned_Ray_To_Triangle(v0, v1, v2,
- tri_plane, start_point, axis_r[axis_dir], axis_1[axis_dir], axis_2[axis_dir],
- direction[axis_dir], flags);
- }
- }
- return count;
- }
- /***********************************************************************************************
- * MeshGeometryClass::cast_aabox_identity -- aligned aabox test *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 3/1/2001 NH : Created. *
- *=============================================================================================*/
- bool MeshGeometryClass::cast_aabox_identity(AABoxCollisionTestClass & boxtest, const Vector3 & translation)
- {
- // transform the test into the mesh's coordinate system
- AABoxCollisionTestClass newbox(boxtest);
- newbox.Translate(translation);
- // cast the box against the mesh
- if (CullTree) {
- return CullTree->Cast_AABox(newbox);
- } else {
- return cast_aabox_brute_force(newbox);
- }
- }
- /***********************************************************************************************
- * MeshGeometryClass::cast_aabox_z90 -- aabox test which is rotated about z by 90 *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 3/1/2001 NH : Created. *
- *=============================================================================================*/
- bool MeshGeometryClass::cast_aabox_z90(AABoxCollisionTestClass & boxtest, const Vector3 & translation)
- {
- // transform the test into the mesh's coordinate system
- AABoxCollisionTestClass newbox(boxtest);
- newbox.Translate(translation);
- newbox.Rotate(AABoxCollisionTestClass::ROTATE_Z270);
- // cast the box against the mesh, using culling if possible
- bool hit;
- if (CullTree) {
- hit = CullTree->Cast_AABox(newbox);
- } else {
- hit = cast_aabox_brute_force(newbox);
- }
- // if we hit something, we need to rotate the normal back out of the mesh coordinate system
- if (hit) {
- // rotating the normal by 90 degrees about Z
- float tmp = boxtest.Result->Normal.X;
- boxtest.Result->Normal.X = -boxtest.Result->Normal.Y;
- boxtest.Result->Normal.Y = tmp;
- }
- return hit;
- }
- /***********************************************************************************************
- * MeshGeometryClass::cast_aabox_z180 -- aabox test which is rotated about z by 180 *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 3/1/2001 NH : Created. *
- *=============================================================================================*/
- bool MeshGeometryClass::cast_aabox_z180(AABoxCollisionTestClass & boxtest, const Vector3 & translation)
- {
- // transform the test into the meshes coordinate system
- AABoxCollisionTestClass newbox(boxtest);
- newbox.Translate(translation);
- newbox.Rotate(AABoxCollisionTestClass::ROTATE_Z180);
- // cast the box against the mesh, using culling if possible
- bool hit;
- if (CullTree) {
- hit = CullTree->Cast_AABox(newbox);
- } else {
- hit = cast_aabox_brute_force(newbox);
- }
-
- // if we hit something, we need to rotate the normal back out of the mesh coordinate system
- if (hit) {
- // rotating the normal by 180 degrees about Z
- boxtest.Result->Normal.X = -boxtest.Result->Normal.X;
- boxtest.Result->Normal.Y = -boxtest.Result->Normal.Y;
- }
- return hit;
- }
- /***********************************************************************************************
- * MeshGeometryClass::cast_aabox_z270 -- aabox test which is rotated about z by 270 *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 3/1/2001 NH : Created. *
- *=============================================================================================*/
- bool MeshGeometryClass::cast_aabox_z270(AABoxCollisionTestClass & boxtest, const Vector3 & translation)
- {
- // transform the test into the mesh's coordinate system
- AABoxCollisionTestClass newbox(boxtest);
- newbox.Translate(translation);
- newbox.Rotate(AABoxCollisionTestClass::ROTATE_Z90);
- // cast the box against the mesh, using culling if possible
- bool hit;
- if (CullTree) {
- hit = CullTree->Cast_AABox(newbox);
- } else {
- hit = cast_aabox_brute_force(newbox);
- }
- // if we hit something, we need to rotate the normal back out of the mesh coordinate system
- if (hit) {
- // rotating the normal by 270 degrees about Z
- float tmp = boxtest.Result->Normal.X;
- boxtest.Result->Normal.X = boxtest.Result->Normal.Y;
- boxtest.Result->Normal.Y = -tmp;
- }
- return hit;
- }
- /***********************************************************************************************
- * MeshGeometryClass::intersect_obbox_brute_force -- brute force intersection check *
- * *
- * This function gets used if the mesh does not have a CullTree *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 3/1/2001 NH : Created. *
- *=============================================================================================*/
- bool MeshGeometryClass::intersect_obbox_brute_force(OBBoxIntersectionTestClass & localtest)
- {
- TriClass tri;
- const Vector3 * loc = Get_Vertex_Array();
- const Vector3i * polyverts = Get_Polygon_Array();
- #ifndef COMPUTE_NORMALS
- const Vector4 * norms = Get_Plane_Array();
- #endif
- /*
- ** Loop over each polygon
- */
- for (int srtri=0; srtri < Get_Polygon_Count(); srtri++) {
-
- tri.V[0] = &(loc[ polyverts[srtri][0] ]);
- tri.V[1] = &(loc[ polyverts[srtri][1] ]);
- tri.V[2] = &(loc[ polyverts[srtri][2] ]);
- #ifdef COMPUTE_NORMALS
- static Vector3 _normal;
- tri.N = &_normal;
- tri.Compute_Normal();
- #else
- tri.N = (Vector3 *)&(norms[srtri]);
- #endif
-
- if (CollisionMath::Intersection_Test(localtest.Box, tri)) {
- return true;
- }
- }
- return false;
- }
- /***********************************************************************************************
- * MeshGeometryClass::cast_ray_brute_force -- brute force ray-cast *
- * *
- * This function gets used if the mesh does not have a CullTree *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 3/1/2001 NH : Created. *
- *=============================================================================================*/
- bool MeshGeometryClass::cast_ray_brute_force(RayCollisionTestClass & raytest)
- {
- int srtri;
- TriClass tri;
- const Vector3 * loc = Get_Vertex_Array();
- const Vector3i * polyverts = Get_Polygon_Array();
- #ifndef COMPUTE_NORMALS
- const Vector4 * norms = Get_Plane_Array();
- #endif
- /*
- ** Loop over each polygon
- */
- bool hit = false;
- for (srtri=0; srtri < Get_Polygon_Count(); srtri++) {
-
- // TODO: find a better way to do this?
- tri.V[0] = &(loc[ polyverts[srtri][0] ]);
- tri.V[1] = &(loc[ polyverts[srtri][1] ]);
- tri.V[2] = &(loc[ polyverts[srtri][2] ]);
- #ifdef COMPUTE_NORMALS
- static Vector3 _normal;
- tri.N = &_normal;
- tri.Compute_Normal();
- #else
- tri.N = (Vector3 *)&(norms[srtri]);
- #endif
-
- hit = hit | CollisionMath::Collide(raytest.Ray, tri, raytest.Result);
- if (hit) {
- raytest.Result->SurfaceType = Get_Poly_Surface_Type (srtri);
- }
-
- if (raytest.Result->StartBad) return true;
- }
- return hit;
- }
- /***********************************************************************************************
- * MeshGeometryClass::cast_aabox_brute_force -- brute force aabox cast *
- * *
- * This function gets used only if the mesh doesn't have a CullTree *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 3/1/2001 NH : Created. *
- *=============================================================================================*/
- bool MeshGeometryClass::cast_aabox_brute_force(AABoxCollisionTestClass & boxtest)
- {
- /*
- ** Loop over each polygon
- */
- TriClass tri;
- int polyhit = -1;
- const Vector3 * loc = Get_Vertex_Array();
- const Vector3i * polyverts = Get_Polygon_Array();
- #ifndef COMPUTE_NORMALS
- const Vector4 * norms = Get_Plane_Array();
- #endif
- for (int srtri = 0; srtri < Get_Polygon_Count(); srtri++) {
- tri.V[0] = &(loc[ polyverts[srtri][0] ]);
- tri.V[1] = &(loc[ polyverts[srtri][1] ]);
- tri.V[2] = &(loc[ polyverts[srtri][2] ]);
- #ifdef COMPUTE_NORMALS
- static Vector3 _normal;
- tri.N = &_normal;
- tri.Compute_Normal();
- #else
- tri.N = (Vector3 *)&(norms[srtri]);
- #endif
- if (CollisionMath::Collide(boxtest.Box, boxtest.Move, tri, boxtest.Result)) {
- polyhit = srtri;
- }
- if (boxtest.Result->StartBad) {
- return true;
- }
- }
- if (polyhit != -1) {
- boxtest.Result->SurfaceType = Get_Poly_Surface_Type(polyhit);
- return true;
- }
- return false;
- }
- /***********************************************************************************************
- * MeshGeometryClass::cast_obbox_brute_force -- brute force obbox cast *
- * *
- * This function gets used only if the mesh doesn't have a CullTree *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 3/1/2001 NH : Created. *
- *=============================================================================================*/
- bool MeshGeometryClass::cast_obbox_brute_force(OBBoxCollisionTestClass & boxtest)
- {
- /*
- ** Loop over each polygon
- */
- TriClass tri;
- int polyhit = -1;
- const Vector3 * loc = Get_Vertex_Array();
- const Vector3i * polyverts = Get_Polygon_Array();
- #ifndef COMPUTE_NORMALS
- const Vector4 * norms = Get_Plane_Array();
- #endif
- for (int srtri = 0; srtri < Get_Polygon_Count(); srtri++) {
- tri.V[0] = &(loc[ polyverts[srtri][0] ]);
- tri.V[1] = &(loc[ polyverts[srtri][1] ]);
- tri.V[2] = &(loc[ polyverts[srtri][2] ]);
- #ifdef COMPUTE_NORMALS
- static Vector3 _normal;
- tri.N = &_normal;
- tri.Compute_Normal();
- #else
- tri.N = (Vector3 *)&(norms[srtri]);
- #endif
- if (CollisionMath::Collide(boxtest.Box, boxtest.Move, tri, Vector3(0,0,0), boxtest.Result)) {
- polyhit = srtri;
- }
- if (boxtest.Result->StartBad) {
- return true;
- }
- }
- if (polyhit != -1) {
- boxtest.Result->SurfaceType = Get_Poly_Surface_Type(polyhit);
- return true;
- }
- return false;
- }
- /***********************************************************************************************
- * MeshGeometryClass::Compute_Plane_Equations -- Recalculates the plane equations *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * This function should not normally be needed during run-time. *
- * The array pointer must point to enough memory to hold a plane equation per polygon *
- * *
- * HISTORY: *
- * 11/9/2000 gth : Created. *
- *=============================================================================================*/
- void MeshGeometryClass::Compute_Plane_Equations(Vector4 * peq)
- {
- WWASSERT(peq!=NULL);
- Vector3i * poly = Poly->Get_Array();
- Vector3 * vert = Vertex->Get_Array();
- for(int pidx = 0; pidx < PolyCount; pidx++)
- {
- Vector3 a,b,normal;
- const Vector3 & p0= vert[poly[pidx][0]];
- Vector3::Subtract(vert[poly[pidx][1]],p0,&a);
- Vector3::Subtract(vert[poly[pidx][2]],p0,&b);
- Vector3::Cross_Product(a,b,&normal);
- normal.Normalize();
- peq[pidx].Set( normal.X, normal.Y, normal.Z, -(Vector3::Dot_Product(p0,normal)) );
- }
- Set_Flag(DIRTY_PLANES,false);
- }
- /***********************************************************************************************
- * MeshGeometryClass::Compute_Vertex_Normals -- recompute the vertex normals *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * This function should not normally be needed during run-time. *
- * The array pointer must point to an array of Vector3's of size NumVerts *
- * *
- * HISTORY: *
- * 11/9/2000 gth : Created. *
- *=============================================================================================*/
- void MeshGeometryClass::Compute_Vertex_Normals(Vector3 * vnorm)
- {
- WWASSERT(vnorm != NULL);
- if ((PolyCount == 0)|| (VertexCount == 0)) {
- return;
- }
- const Vector4 * peq = Get_Plane_Array();
- Vector3i * poly = Poly->Get_Array();
- const uint32 * shadeIx = Get_Vertex_Shade_Index_Array(false);
- // Two cases, with or without vertex shade indices. The vertex shade indices
- // implicitly contain the smoothing groups information from the original mesh.
- // In their abscesnce, the entire mesh is smoothed.
- if (!shadeIx) {
- VectorProcessorClass::Clear(vnorm, VertexCount);
- for(int pidx = 0; pidx < PolyCount; pidx++) {
- vnorm[poly[pidx].I].X += peq[pidx].X;
- vnorm[poly[pidx].I].Y += peq[pidx].Y;
- vnorm[poly[pidx].I].Z += peq[pidx].Z;
-
- vnorm[poly[pidx].J].X += peq[pidx].X;
- vnorm[poly[pidx].J].Y += peq[pidx].Y;
- vnorm[poly[pidx].J].Z += peq[pidx].Z;
-
- vnorm[poly[pidx].K].X += peq[pidx].X;
- vnorm[poly[pidx].K].Y += peq[pidx].Y;
- vnorm[poly[pidx].K].Z += peq[pidx].Z;
- }
-
- } else {
-
- VectorProcessorClass::Clear (vnorm, VertexCount);
- for (int pidx = 0; pidx < PolyCount; pidx++) {
- vnorm[shadeIx[poly[pidx].I]].X += peq[pidx].X;
- vnorm[shadeIx[poly[pidx].I]].Y += peq[pidx].Y;
- vnorm[shadeIx[poly[pidx].I]].Z += peq[pidx].Z;
- vnorm[shadeIx[poly[pidx].J]].X += peq[pidx].X;
- vnorm[shadeIx[poly[pidx].J]].Y += peq[pidx].Y;
- vnorm[shadeIx[poly[pidx].J]].Z += peq[pidx].Z;
- vnorm[shadeIx[poly[pidx].K]].X += peq[pidx].X;
- vnorm[shadeIx[poly[pidx].K]].Y += peq[pidx].Y;
- vnorm[shadeIx[poly[pidx].K]].Z += peq[pidx].Z;
- }
- // normalize the "master" vertex normals and copy the smoothed ones
- // (note: we always encounter the "master" ones first)
- for (unsigned vidx = 0; vidx < (unsigned)VertexCount; vidx ++) {
- if (shadeIx[vidx] == vidx) {
- vnorm[vidx].Normalize();
- } else {
- vnorm[vidx] = vnorm[shadeIx[vidx]];
- }
- }
- }
- VectorProcessorClass::Normalize(vnorm, VertexCount);
- Set_Flag(DIRTY_VNORMALS,false);
- }
- /***********************************************************************************************
- * MeshGeometryClass::Compute_Bounds -- recomputes the bounding volumes *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * This function should not normally be needed during run-time. *
- * *
- * HISTORY: *
- * 11/9/2000 gth : Created. *
- *=============================================================================================*/
- void MeshGeometryClass::Compute_Bounds(Vector3 * verts)
- {
- BoundBoxMin.Set(0,0,0);
- BoundBoxMax.Set(0,0,0);
- BoundSphereCenter.Set(0,0,0);
- BoundSphereRadius = 0.0;
- if (VertexCount == 0) {
- return;
- }
- // find bounding box minimum and maximum
- if (verts == NULL) {
- verts = Vertex->Get_Array();
- }
- VectorProcessorClass::MinMax(verts,BoundBoxMin,BoundBoxMax,VertexCount);
- // calculate the bounding sphere
- BoundSphereCenter = (BoundBoxMin + BoundBoxMax)/2.0f;
- BoundSphereRadius = (float)(BoundBoxMax-BoundSphereCenter).Length2();
- BoundSphereRadius = ((float)sqrt(BoundSphereRadius))*1.00001f;
- Set_Flag(DIRTY_BOUNDS,false);
- }
- /***********************************************************************************************
- * MeshGeometryClass::get_vert_normals -- get the vertex normal array *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 6/14/2001 gth : Created. *
- *=============================================================================================*/
- Vector3 * MeshGeometryClass::get_vert_normals(void)
- {
- #if (OPTIMIZE_VNORM_RAM)
- _VNormArray.Uninitialised_Grow(VertexCount);
- return &(_VNormArray[0]);
- #else
- WWASSERT(VertexNorm);
- return VertexNorm->Get_Array();
- #endif
- }
- /***********************************************************************************************
- * MeshGeometryClass::Get_Vertex_Normal_Array -- validates and returns the vertex normal array *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 6/14/2001 gth : Created. *
- *=============================================================================================*/
- const Vector3 * MeshGeometryClass::Get_Vertex_Normal_Array(void)
- {
- #if (OPTIMIZE_VNORM_RAM)
- Compute_Vertex_Normals(get_vert_normals());
- return get_vert_normals();
- #else
- if (Get_Flag(DIRTY_VNORMALS)) {
- Compute_Vertex_Normals(get_vert_normals());
- }
- return get_vert_normals();
- #endif
- }
- /***********************************************************************************************
- * MeshGeometryClass::get_planes -- get the plane array memory (internal) *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 6/14/2001 gth : Created. *
- *=============================================================================================*/
- Vector4 * MeshGeometryClass::get_planes(bool create)
- {
- #if (OPTIMIZE_PLANEEQ_RAM)
- _PlaneEQArray.Uninitialised_Grow(PolyCount);
- return &(_PlaneEQArray[0]);
- #else
- if (create && !PlaneEq) {
- PlaneEq = NEW_REF(ShareBufferClass<Vector4>,(PolyCount, "MeshGeometryClass::PlaneEq"));
- }
- if (PlaneEq) {
- return PlaneEq->Get_Array();
- }
- return NULL;
- #endif
- }
- /***********************************************************************************************
- * MeshGeometryClass::Get_Plane_Array -- validates and returns the array of plane equations *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 6/14/2001 gth : Created. *
- *=============================================================================================*/
- const Vector4 * MeshGeometryClass::Get_Plane_Array(bool create)
- {
- #if (OPTIMIZE_PLANEEQ_RAM)
- Vector4 * planes = get_planes(create);
- Compute_Plane_Equations(planes);
- return planes;
- #else
- Vector4 * planes = get_planes(create);
- if (planes && Get_Flag(DIRTY_PLANES)) {
- Compute_Plane_Equations(planes);
- }
- return planes;
- #endif
- }
- /***********************************************************************************************
- * MeshGeometryClass::Compute_Plane -- compute the plane equation of a single poly *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 6/14/2001 gth : Created. *
- *=============================================================================================*/
- void MeshGeometryClass::Compute_Plane(int pidx,PlaneClass * set_plane) const
- {
- WWASSERT(pidx >= 0);
- WWASSERT(pidx < PolyCount);
- Vector3i & poly = Poly->Get_Array()[pidx];
- Vector3 * verts = Vertex->Get_Array();
- set_plane->Set(verts[poly.I],verts[poly.J],verts[poly.K]);
- }
- /***********************************************************************************************
- * MeshGeometryClass::Generate_Culling_Tree -- Generate an AABTree for this mesh *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * This function should not normally be needed during run-time. *
- * *
- * HISTORY: *
- * 11/9/2000 gth : Created. *
- *=============================================================================================*/
- void MeshGeometryClass::Generate_Culling_Tree(void)
- {
- WWMEMLOG(MEM_CULLINGDATA);
- {
- AABTreeBuilderClass builder;
- builder.Build_AABTree(PolyCount,Poly->Get_Array(),VertexCount,Vertex->Get_Array());
-
- CullTree = NEW_REF(AABTreeClass,(&builder));
- CullTree->Set_Mesh(this);
- }
- }
- /***********************************************************************************************
- * MeshGeometryClass::Load_W3D -- Load a mesh from a w3d file *
- * *
- * This function will extract just the geometry information from a W3D mesh. It must *
- * be completely replaced by any derived classes that want to handle all of the chunks. *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/9/2000 gth : Created. *
- *=============================================================================================*/
- WW3DErrorType MeshGeometryClass::Load_W3D(ChunkLoadClass & cload)
- {
- /*
- ** This function will initialize this MeshGeometryClass from the contents of a W3D file.
- ** Note that derived classes need to completely replace this function; only re-using the individual
- ** chunk handling functions.
- */
- /*
- ** Open the first chunk, it should be the mesh header
- */
- cload.Open_Chunk();
-
- if (cload.Cur_Chunk_ID() != W3D_CHUNK_MESH_HEADER3) {
- WWDEBUG_SAY(("Old format mesh mesh, no longer supported.\n"));
- goto Error;
- }
-
- W3dMeshHeader3Struct header;
- if (cload.Read(&header,sizeof(W3dMeshHeader3Struct)) != sizeof(W3dMeshHeader3Struct)) {
- goto Error;
- }
- cload.Close_Chunk();
- /*
- ** Process the header
- */
- char * tmpname;
- int namelen;
-
- Reset_Geometry(header.NumTris,header.NumVertices);
-
- namelen = strlen(header.ContainerName);
- namelen += strlen(header.MeshName);
- namelen += 2;
- W3dAttributes = header.Attributes;
- SortLevel = header.SortLevel;
- tmpname = W3DNEWARRAY char[namelen];
- memset(tmpname,0,namelen);
- if (strlen(header.ContainerName) > 0) {
- strcpy(tmpname,header.ContainerName);
- strcat(tmpname,".");
- }
- strcat(tmpname,header.MeshName);
- Set_Name(tmpname);
- delete[] tmpname;
- tmpname = NULL;
- /*
- ** Set Bounding Info
- */
- BoundBoxMin.Set(header.Min.X,header.Min.Y,header.Min.Z);
- BoundBoxMax.Set(header.Max.X,header.Max.Y,header.Max.Z);
- BoundSphereCenter.Set(header.SphCenter.X,header.SphCenter.Y,header.SphCenter.Z);
- BoundSphereRadius = header.SphRadius;
- /*
- ** Flags
- */
- if (header.Version >= W3D_MAKE_VERSION(4,1)) {
- int geometry_type = header.Attributes & W3D_MESH_FLAG_GEOMETRY_TYPE_MASK;
- switch (geometry_type)
- {
- case W3D_MESH_FLAG_GEOMETRY_TYPE_NORMAL:
- break;
- case W3D_MESH_FLAG_GEOMETRY_TYPE_CAMERA_ALIGNED:
- Set_Flag(ALIGNED,true);
- break;
- case W3D_MESH_FLAG_GEOMETRY_TYPE_CAMERA_ORIENTED:
- Set_Flag(ORIENTED,true);
- break;
- case W3D_MESH_FLAG_GEOMETRY_TYPE_SKIN:
- Set_Flag(SKIN,true);
- break;
- }
- }
- if (header.Attributes & W3D_MESH_FLAG_TWO_SIDED) {
- Set_Flag(TWO_SIDED,true);
- }
- if (header.Attributes & W3D_MESH_FLAG_CAST_SHADOW) {
- Set_Flag(CAST_SHADOW,true);
- }
- read_chunks(cload);
- /*
- ** If this is a pre-3.0 mesh and it has vertex influences,
- ** fixup the bone indices to account for the new root node
- */
- if ((header.Version < W3D_MAKE_VERSION(3,0)) && (Get_Flag(SKIN))) {
- uint16 * links = get_bone_links();
- WWASSERT(links);
-
- for (int bi = 0; bi < Get_Vertex_Count(); bi++) {
- links[bi] += 1;
- }
- }
- /*
- ** If this mesh is collideable and no AABTree was in the file, generate one now
- */
- if ( (((W3dAttributes & W3D_MESH_FLAG_COLLISION_TYPE_MASK) >> W3D_MESH_FLAG_COLLISION_TYPE_SHIFT) != 0) &&
- (CullTree == NULL))
- {
- Generate_Culling_Tree();
- }
- return WW3D_ERROR_OK;
- Error:
- return WW3D_ERROR_LOAD_FAILED;
- }
- /***********************************************************************************************
- * MeshGeometryClass::read_chunks -- read w3d chunks *
- * *
- * Again, derived classes must replace this function with one that handles all of their *
- * chunks in addition to calling to this class for the individual chunks that it handles. *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/9/2000 gth : Created. *
- *=============================================================================================*/
- WW3DErrorType MeshGeometryClass::read_chunks(ChunkLoadClass & cload)
- {
- /*
- ** Read in the chunk header
- ** If there are no more chunks within the mesh chunk,
- ** we are done.
- */
- while (cload.Open_Chunk()) {
- /*
- ** Process the chunk
- */
- WW3DErrorType error = WW3D_ERROR_OK;
- switch (cload.Cur_Chunk_ID()) {
- case W3D_CHUNK_VERTICES:
- error = read_vertices(cload);
- break;
- case W3D_CHUNK_SURRENDER_NORMALS:
- case W3D_CHUNK_VERTEX_NORMALS:
- error = read_vertex_normals(cload);
- break;
- case W3D_CHUNK_TRIANGLES:
- error = read_triangles(cload);
- break;
- case W3D_CHUNK_MESH_USER_TEXT:
- error = read_user_text(cload);
- break;
-
- case W3D_CHUNK_VERTEX_INFLUENCES:
- error = read_vertex_influences(cload);
- break;
- case W3D_CHUNK_VERTEX_SHADE_INDICES:
- error = read_vertex_shade_indices(cload);
- break;
- case W3D_CHUNK_AABTREE:
- read_aabtree(cload);
- break;
- default:
- break;
- }
-
- cload.Close_Chunk();
- if (error != WW3D_ERROR_OK) {
- return error;
- }
- }
- return WW3D_ERROR_OK;
- }
- /***********************************************************************************************
- * MeshGeometryClass::read_vertices -- read the vertex chunk from a W3D file *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/9/2000 gth : Created. *
- *=============================================================================================*/
- WW3DErrorType MeshGeometryClass::read_vertices(ChunkLoadClass & cload)
- {
- W3dVectorStruct vert;
- Vector3 * loc = Vertex->Get_Array();
- assert(loc);
- for (int i=0; i<Get_Vertex_Count(); i++) {
- if (cload.Read(&vert,sizeof(W3dVectorStruct)) != sizeof(W3dVectorStruct)) {
- return WW3D_ERROR_LOAD_FAILED;
- }
-
- loc[i].X = vert.X;
- loc[i].Y = vert.Y;
- loc[i].Z = vert.Z;
- }
- return WW3D_ERROR_OK;
- }
- /***********************************************************************************************
- * MeshGeometryClass::read_vertex_normals -- read the vertex normals chunk from a w3d file *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/9/2000 gth : Created. *
- *=============================================================================================*/
- WW3DErrorType MeshGeometryClass::read_vertex_normals(ChunkLoadClass & cload)
- {
- W3dVectorStruct norm;
- Vector3 * mdlnorms = get_vert_normals();
- WWASSERT(mdlnorms);
- for (int i=0; i<VertexCount; i++) {
- if (cload.Read(&norm,sizeof(W3dVectorStruct)) != sizeof(W3dVectorStruct)) {
- return WW3D_ERROR_LOAD_FAILED;
- }
- mdlnorms[i].Set(norm.X,norm.Y,norm.Z);
- }
- return WW3D_ERROR_OK;
- }
- /***********************************************************************************************
- * MeshGeometryClass::read_triangles -- read the triangles chunk from a w3d file *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/9/2000 gth : Created. *
- *=============================================================================================*/
- WW3DErrorType MeshGeometryClass::read_triangles(ChunkLoadClass & cload)
- {
- W3dTriStruct tri;
- // cache pointers to various arrays in the surrender mesh
- Vector3i * vi = get_polys();
- Set_Flag(DIRTY_PLANES,false);
- Vector4 * peq = get_planes();
- uint8 * surface_types = Get_Poly_Surface_Type_Array();
- // read in each polygon one by one
- for (int i=0; i<Get_Polygon_Count(); i++) {
- if (cload.Read(&tri,sizeof(W3dTriStruct)) != sizeof(W3dTriStruct)) {
- return WW3D_ERROR_LOAD_FAILED;
- }
- // set the vertex indices
- vi[i].I = tri.Vindex[0];
- vi[i].J = tri.Vindex[1];
- vi[i].K = tri.Vindex[2];
- // set the normal
- peq[i].X = tri.Normal.X;
- peq[i].Y = tri.Normal.Y;
- peq[i].Z = tri.Normal.Z;
- peq[i].W = -tri.Dist;
- // set the surface type
- WWASSERT(tri.Attributes < 256);
- surface_types[i] = (uint8)(tri.Attributes);
- }
- return WW3D_ERROR_OK;
- }
- /***********************************************************************************************
- * MeshGeometryClass::read_user_text -- read the user text chunk from a w3d file *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/9/2000 gth : Created. *
- *=============================================================================================*/
- WW3DErrorType MeshGeometryClass::read_user_text(ChunkLoadClass & cload)
- {
- unsigned int textlen = cload.Cur_Chunk_Length();
- /*
- ** This shouldn't happen but if there are more than one
- ** USER_TEXT chunks in the mesh file, store only the first
- ** one. I am assuming that if the UserText buffer is not
- ** NULL, then a previous user text chunk has been read in...
- */
- if (UserText != NULL) {
- return WW3D_ERROR_OK;
- }
-
- /*
- ** Allocate the buffer and read in the text
- */
- UserText = NEW_REF(ShareBufferClass<char>,(textlen, "MeshGeometryClass::UserText"));
- if (cload.Read(UserText->Get_Array(),textlen) != textlen) {
- return WW3D_ERROR_LOAD_FAILED;
- }
- return WW3D_ERROR_OK;
- }
- /***********************************************************************************************
- * MeshGeometryClass::read_vertex_influences -- read the vertex influences chunk from a w3d fi *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/9/2000 gth : Created. *
- *=============================================================================================*/
- WW3DErrorType MeshGeometryClass::read_vertex_influences(ChunkLoadClass & cload)
- {
- W3dVertInfStruct vinf;
- uint16 * links = get_bone_links(true);
- WWASSERT(links);
- for (int i=0; i<Get_Vertex_Count(); i++) {
- if (cload.Read(&vinf,sizeof(W3dVertInfStruct)) != sizeof(W3dVertInfStruct)) {
- return WW3D_ERROR_LOAD_FAILED;
- }
- links[i] = vinf.BoneIdx;
- }
- Set_Flag(SKIN,true);
- return WW3D_ERROR_OK;
- }
- /***********************************************************************************************
- * MeshGeometryClass::read_vertex_shade_indices -- read the vertex shade indices chunk *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/9/2000 gth : Created. *
- *=============================================================================================*/
- WW3DErrorType MeshGeometryClass::read_vertex_shade_indices(ChunkLoadClass & cload)
- {
- uint32 * shade_index = get_shade_indices(true);
- uint32 si;
- for (int i=0; i<Get_Vertex_Count(); i++) {
- if (cload.Read(&si,sizeof(uint32)) != sizeof(uint32)) {
- return WW3D_ERROR_LOAD_FAILED;
- }
- shade_index[i] = si;
- }
- return WW3D_ERROR_OK;
- }
- /***********************************************************************************************
- * MeshGeometryClass::read_aabtree -- read the AABTree chunk from a w3d file *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 11/9/2000 gth : Created. *
- *=============================================================================================*/
- WW3DErrorType MeshGeometryClass::read_aabtree(ChunkLoadClass &cload)
- {
- REF_PTR_RELEASE(CullTree);
- CullTree = NEW_REF(AABTreeClass,());
- CullTree->Load_W3D(cload);
- CullTree->Set_Mesh(this);
- return (WW3D_ERROR_OK);
- }
- void MeshGeometryClass::Scale(const Vector3 &sc)
- {
- WWASSERT(Vertex);
- Vector3 * vert = Vertex->Get_Array();
-
- for (int i=0;i<VertexCount; i++) {
- vert[i].X *= sc.X;
- vert[i].Y *= sc.Y;
- vert[i].Z *= sc.Z;
- }
-
- BoundBoxMin.Scale(sc);
- BoundBoxMax.Scale(sc);
- BoundSphereCenter.Scale(sc);
-
- float max;
- max = (sc.X > sc.Y) ? sc.X : sc.Y;
- max = (max > sc.Z) ? max : sc.Z;
- BoundSphereRadius *= max;
- // If scaling uniformly normals are OK:
- if (sc.X != sc.Y || sc.Y != sc.Z) {
- Set_Flag(DIRTY_VNORMALS,true);
- }
- // pnormals are plane equations...
- Set_Flag(DIRTY_PLANES,true);
- }
|