| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131 |
- /*
- ** 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 : WW3D *
- * *
- * $Archive:: /Commando/Code/ww3d2/meshgeometry.cpp $*
- * *
- * Original Author:: Greg Hjelstrom *
- * *
- * $Author:: Jani_p $*
- * *
- * $Modtime:: 11/24/01 5:34p $*
- * *
- * $Revision:: 14 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * 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"
- #include "htree.h"
- #include "matrix4.h"
- #include "rinfo.h"
- #include "camera.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);
- // Clone the cull tree..
- REF_PTR_RELEASE(CullTree);
- if (that.CullTree) {
- CullTree = NEW_REF(AABTreeClass, ());
- *CullTree = *that.CullTree;
- CullTree->Set_Mesh(this);
- }
- }
- 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<TriIndex>,(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 TriIndex * 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 TriIndex * 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 TriIndex * 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 TriIndex * 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 TriIndex * 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 TriIndex * 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 TriIndex * 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
-
- if (CollisionMath::Collide(raytest.Ray, tri, raytest.Result)) {
- hit = true;
- 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 TriIndex * 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 TriIndex * 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);
- TriIndex * 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();
- TriIndex * 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);
- TriIndex & 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
- TriIndex * 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);
- // the cull tree is invalid, release it and make a new one
- if (CullTree) {
- // If the scale is uniform, we can scale the cull tree, which is a lot faster than creating a new one
- if (fabs(sc[0]-sc[1])<WWMATH_EPSILON && fabs(sc[0]-sc[2])<WWMATH_EPSILON) {
- // create a copy of the old culltree
- AABTreeClass *temp = NEW_REF(AABTreeClass, ());
- *temp = *CullTree;
- temp->Set_Mesh(this);
- REF_PTR_SET(CullTree, temp);
- REF_PTR_RELEASE(temp);
- CullTree->Scale(sc[0]);
- }
- else {
- REF_PTR_RELEASE(CullTree);
- Generate_Culling_Tree();
- }
- }
- }
- // Destination pointers MUST point to arrays large enough to hold all vertices
- void MeshGeometryClass::get_deformed_vertices(Vector3 *dst_vert,const HTreeClass * htree)
- {
- Vector3 * src_vert = Vertex->Get_Array();
- uint16 * bonelink = VertexBoneLink->Get_Array();
- for (int vi = 0; vi < Get_Vertex_Count(); vi++) {
- const Matrix3D & tm = htree->Get_Transform(bonelink[vi]);
- Matrix3D::Transform_Vector(tm, src_vert[vi], &(dst_vert[vi]));
- }
- }
- // Destination pointers MUST point to arrays large enough to hold all vertices
- void MeshGeometryClass::get_deformed_vertices(Vector3 *dst_vert, Vector3 *dst_norm,const HTreeClass * htree)
- {
- int vi;
- int vertex_count=Get_Vertex_Count();
- Vector3 * src_vert = Vertex->Get_Array();
- #if (OPTIMIZE_VNORMS)
- Vector3 * src_norm = (Vector3 *)Get_Vertex_Normal_Array();
- #else
- Vector3 * src_norm = VertexNorm->Get_Array();
- #endif
- uint16 * bonelink = VertexBoneLink->Get_Array();
- for (vi = 0; vi < vertex_count;) {
- const Matrix3D & tm = htree->Get_Transform(bonelink[vi]);
- // Make a copy so we can set the translation to zero
- Matrix3D mytm=tm;
- int idx=bonelink[vi];
- int cnt;
- for (cnt = vi; cnt < vertex_count; cnt++) {
- if (idx!=bonelink[cnt]) {
- break;
- }
- }
- VectorProcessorClass::Transform(dst_vert+vi,src_vert+vi,mytm,cnt-vi);
- mytm.Set_Translation(Vector3(0.0f,0.0f,0.0f));
- VectorProcessorClass::Transform(dst_norm+vi,src_norm+vi,mytm,cnt-vi);
- vi=cnt;
- }
- }
- // Destination pointers MUST point to arrays large enough to hold all vertices
- void MeshGeometryClass::get_deformed_screenspace_vertices(Vector4 *dst_vert,const RenderInfoClass & rinfo,const Matrix3D & mesh_transform,const HTreeClass * htree)
- {
- Matrix4x4 prj = rinfo.Camera.Get_Projection_Matrix() * rinfo.Camera.Get_View_Matrix() * mesh_transform;
- Vector3 * src_vert = Vertex->Get_Array();
- int vertex_count=Get_Vertex_Count();
-
- if (Get_Flag(SKIN) && VertexBoneLink && htree) {
- uint16 * bonelink = VertexBoneLink->Get_Array();
- for (int vi = 0; vi < vertex_count;) {
- int idx=bonelink[vi];
- Matrix4x4 tm = prj * htree->Get_Transform(idx);
- // Count equal matrices (the vertices should be pre-sorted by matrices they use)
- for (int cnt = vi; cnt < vertex_count; cnt++) if (idx!=bonelink[cnt]) break;
- // Transform to screenspace (x,y,z,w)
- VectorProcessorClass::Transform(
- dst_vert+vi,
- src_vert+vi,
- tm,
- cnt-vi);
- vi=cnt;
- }
- } else {
- VectorProcessorClass::Transform(
- dst_vert,
- src_vert,
- prj,
- vertex_count);
- }
- }
|