bpt.cpp 69 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** 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 ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : WWPhys *
  23. * *
  24. * $Archive:: /Commando/Code/wwphys/bpt.cpp $*
  25. * *
  26. * Author:: Greg_h *
  27. * *
  28. * $Modtime:: 9/09/99 11:29a $*
  29. * *
  30. * $Revision:: 15 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * BptClass::BptClass -- constructor *
  35. * BptClass::~BptClass -- destructor *
  36. * BptClass::Free -- releases all assets in use *
  37. * BptClass::Build -- build a bpt from the given mesh (generates a new mesh) *
  38. * BptClass::Load -- Initialize this Bpt object from contents of a W3D file *
  39. * BptClass::Save -- Save this Bpt object into a W3D file *
  40. * BptClass::Render -- submit this object for rendering *
  41. * BptClass::Cast_Ray -- Intersect a ray with this Bpt Object *
  42. * BptClass::Cast_AABox -- Intersect a swept axis-aligned box. *
  43. * BptClass::Cast_OBBox -- Intersect a swept oriented box with this bpt object *
  44. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  45. #if 0 // OBSOLETE!!!
  46. #ifdef PORT140
  47. #include "bpt.h"
  48. #include "vector.h"
  49. #include "uarray.h"
  50. #include "mesh.h"
  51. #include "material.h"
  52. #include "chunkio.h"
  53. #include "vector3.h"
  54. #include "tri.h"
  55. #include "wwdebug.h"
  56. #include "meshbuild.h"
  57. #include "camera.h"
  58. #include "sr.hpp"
  59. #define BPT_FRONT 0x01
  60. #define BPT_BACK 0x02
  61. #define BPT_ON 0x04
  62. #define BPT_BOTH 0x08
  63. #define BPT_EPSILON 0.0001f
  64. #define BPT_COINCIDENCE_EPSILON 0.000001f
  65. class BptVertexClass;
  66. class BptPolyClass;
  67. class BptNodeClass;
  68. class BptBuilderClass;
  69. class BptImpNodeClass;
  70. class BptImpClass;
  71. class BptImpBuilderClass;
  72. /*
  73. ** NormalHasherClass, used by the code which builds the
  74. ** table of unique Normal vectors.
  75. */
  76. class NormalHasherClass : public HashCalculatorClass<Vector3>
  77. {
  78. public:
  79. virtual bool Items_Match(const Vector3 & a, const Vector3 & b)
  80. {
  81. // looking for an exact match for normals...
  82. return ((a.X == b.X) && (a.Y == b.Y) && (a.Z == b.Z));
  83. }
  84. virtual void Compute_Hash(const Vector3 & item)
  85. {
  86. HashVal = (int)(item.X*12345.6f + item.Y*1714.38484f + item.Z*27561.3f)&1023;
  87. }
  88. virtual int Num_Hash_Bits(void)
  89. {
  90. return 10; // 10bit hash value.
  91. }
  92. virtual int Num_Hash_Values(void)
  93. {
  94. return 1; // only one hash value for normals, require *exact* match
  95. }
  96. virtual int Get_Hash_Value(int index)
  97. {
  98. return HashVal;
  99. }
  100. private:
  101. int HashVal;
  102. };
  103. /*
  104. ** DistanceHasherClass, used by the code which builds the
  105. ** table of unique distance values.
  106. */
  107. class DistanceHasherClass : public HashCalculatorClass<float>
  108. {
  109. virtual bool Items_Match(const float & a, const float & b)
  110. {
  111. // looking for an exact match for distances
  112. return (a == b);
  113. }
  114. virtual void Compute_Hash(const float & item)
  115. {
  116. HashVal = (int)(item)&1023;
  117. }
  118. virtual int Num_Hash_Bits(void)
  119. {
  120. return 12; // 12bit hash value.
  121. }
  122. virtual int Num_Hash_Values(void)
  123. {
  124. return 1; // only one hash value for normals, require *exact* match
  125. }
  126. virtual int Get_Hash_Value(int index)
  127. {
  128. return HashVal;
  129. }
  130. private:
  131. int HashVal;
  132. };
  133. /*
  134. ** BPT Notes
  135. **
  136. ** - Probably need to build the initial tree in a big straightforward recursive datastructure
  137. ** with no indirection or anything. Then, when the whole thing is being built correctly,
  138. ** process the tree down so that everything that can be shared (e.g. plane equations) are
  139. ** shared.
  140. **
  141. ** - Hide most of the implementation details even from the bpt header file by using a
  142. ** BptImpClass. This class will contain the final "optimized" bpt information.
  143. **
  144. ** - Maybe need a BptBuilder class that builds the initial "straightforward" tree structure
  145. ** and then compresses it into a BptImp.
  146. **
  147. ** - Extend PlaneClass to know about special case planes such as x-y, y-z, x-z. Optimize
  148. ** the culling and clipping functions to take advantage of them.
  149. **
  150. ** - Separate the normal from the distance in the plane equation? Many many planes will
  151. ** probably share the same normal but different distances. This probably should be a
  152. ** very late optimization.
  153. */
  154. /*
  155. ** BptVertexClass
  156. ** This is the vertex representation used in building the BPT
  157. */
  158. class BptVertexClass
  159. {
  160. public:
  161. BptVertexClass(void);
  162. BptVertexClass(const BptVertexClass & that);
  163. BptVertexClass & operator = (const BptVertexClass & that);
  164. int Which_Side(const PlaneClass & plane) const;
  165. Vector3 Position;
  166. Vector3 Normal;
  167. Vector3 Color;
  168. Vector3 TexCoord;
  169. static BptVertexClass Lerp(const BptVertexClass & v0,const BptVertexClass & v1,double lerp);
  170. static BptVertexClass Intersect_Plane(const BptVertexClass & v0,const BptVertexClass & v1,const PlaneClass & plane);
  171. };
  172. /*
  173. ** BptPolyClass
  174. ** This is the polygon representation used in building the BPT
  175. */
  176. class BptPolyClass
  177. {
  178. public:
  179. enum { BPT_POLY_MAX_VERTS = 16 };
  180. BptPolyClass(void);
  181. BptPolyClass(const BptPolyClass & that);
  182. BptPolyClass(const BptVertexClass * points, int num);
  183. BptPolyClass & operator = (const BptPolyClass & that);
  184. const BptVertexClass & operator[] (int i) const { return Verts[i]; }
  185. BptVertexClass & operator[] (int i) { return Verts[i]; }
  186. void Compute_Plane(void);
  187. int Which_Side(const PlaneClass & plane) const;
  188. void Split(const PlaneClass & plane,BptPolyClass & front,BptPolyClass & back) const;
  189. bool Is_Degenerate(void);
  190. bool Salvage_Degenerate(void);
  191. int MaterialId;
  192. int NumVerts;
  193. BptVertexClass Verts[BPT_POLY_MAX_VERTS];
  194. PlaneClass Plane;
  195. };
  196. /*
  197. ** BptNodeClass
  198. ** This is the node representation used in building the BPT
  199. */
  200. class BptNodeClass
  201. {
  202. public:
  203. BptNodeClass(void) : NumPolys(0),Polys(NULL),Front(NULL),Back(NULL),ArrayIndex(-1) { }
  204. ~BptNodeClass(void) { if (Front) delete Front; if (Back) delete Back; if (Polys) delete[] Polys; }
  205. void Build(int numpolys,BptPolyClass * polys);
  206. int Num_Polys(void) const;
  207. int Num_Tris(void) const;
  208. int Num_Nodes(void) const;
  209. int Max_Depth(void) const;
  210. void Submit_Polys(MeshBuilderClass & builder) const;
  211. void Compute_Bounding_Box(void);
  212. int Assign_Array_Indices(int index);
  213. void Submit_Nodes(BptImpBuilderClass & impbuilder) const;
  214. private:
  215. PlaneClass Plane; // splitting plane
  216. uint32 NumPolys; // num polys on plane
  217. BptPolyClass * Polys; // array of polys
  218. BptNodeClass * Front; // pointer to front tree
  219. BptNodeClass * Back; // pointer to back tree
  220. int ArrayIndex; // used in building the tree into array form.
  221. Vector3 Min; // bounding box for this tree.
  222. Vector3 Max;
  223. /*
  224. ** SplitChoiceStruct. Whenever a plane is tested to see if it is a suitable splitting
  225. ** plane, we'll cache all of the values it computes so we do not duplicate the effort elsewhere.
  226. */
  227. struct SplitChoiceStruct
  228. {
  229. SplitChoiceStruct(void) : Score(0.0f),FrontCount(0),BackCount(0),OnCount(0),SplitCount(0),Plane(0,0,0,0) {}
  230. float Score; // 0.0 is worst, 1.0 is "perfect"
  231. int FrontCount; // number of polys in front of the plane
  232. int BackCount; // number of polys behind the plane
  233. int OnCount; // number of polys on the plane
  234. int SplitCount; // number of polys split by the plane
  235. PlaneClass Plane; // plane equation
  236. };
  237. /*
  238. ** SplitArrayStruct. This struct simply stores the result of a split operation. The
  239. ** arrays for the front, back and "on" polygons will be allocated and filled in.
  240. */
  241. struct SplitArraysStruct
  242. {
  243. SplitArraysStruct(void) : FrontCount(0),BackCount(0),OnCount(0),FrontPolys(NULL),BackPolys(NULL),OnPolys(NULL) {}
  244. int FrontCount;
  245. int BackCount;
  246. int OnCount;
  247. BptPolyClass * FrontPolys;
  248. BptPolyClass * BackPolys;
  249. BptPolyClass * OnPolys;
  250. };
  251. SplitChoiceStruct Compute_Plane_Score(int numpolys,BptPolyClass * polys,const PlaneClass & plane);
  252. SplitChoiceStruct Select_Splitting_Plane(int numpolys,BptPolyClass * polys);
  253. void Split_Polys(const int num_polys,
  254. const BptPolyClass * polys,
  255. const SplitChoiceStruct & sc,
  256. SplitArraysStruct * arrays);
  257. void Max_Depth_Internal(int cur_depth, int & max_depth) const;
  258. friend class BptImpBuilderClass;
  259. };
  260. /*
  261. ** BptBuilderClass
  262. ** This class builds the initial straightforward binary tree representation of
  263. ** the mesh given to it. It then "optimizes" the tree into a BptImpClass to
  264. ** save ram.
  265. */
  266. class BptBuilderClass
  267. {
  268. public:
  269. BptBuilderClass(void);
  270. ~BptBuilderClass(void);
  271. BptImpClass * Build(MeshClass * mesh);
  272. BptImpClass * Build(int numpolys,BptPolyClass * polyarray,MaterialInfoClass * matinfo);
  273. private:
  274. void unwind_mesh(MeshClass * mesh,int & set_numpolys,BptPolyClass * & set_polyarray);
  275. BptImpClass * build_imp(void);
  276. BptNodeClass * Root;
  277. MaterialInfoClass * MatInfo;
  278. int InputPolyCount;
  279. int OutputPolyCount;
  280. int InputTriCount;
  281. int OutputTriCount;
  282. int NodeCount;
  283. int MaxDepth;
  284. };
  285. /*
  286. ** BptImpNodeClass
  287. ** This is the node representation in the final BPT implementation.
  288. ** It allows for sharing of plane equations, indirection to the polygons, etc
  289. */
  290. class BptImpNodeClass
  291. {
  292. public:
  293. float MinX,MinY,MinZ;
  294. float MaxX,MaxY,MaxZ;
  295. BptImpNodeClass * Front;
  296. BptImpNodeClass * Back;
  297. uint16 FirstPoly;
  298. uint16 PolyCount;
  299. uint16 NormalIndex;
  300. uint16 DistanceIndex;
  301. bool Is_Visible(const CameraClass & camera);
  302. bool Cast_AABox_To_Polys(PhysAABoxCollisionTestClass & coltest);
  303. };
  304. /*
  305. ** BptImpClass
  306. ** This class contains the actual run-time binary partition tree information
  307. ** and the code for building a bpt out of an arbitrary list of polygons.
  308. */
  309. class BptImpClass
  310. {
  311. public:
  312. ~BptImpClass(void);
  313. void Free(void);
  314. void Build_Apt(const CameraClass & camera);
  315. bool Cast_Ray(PhysRayCollisionTestClass & raytest) const;
  316. bool Cast_AABox(PhysAABoxCollisionTestClass & boxtest) const;
  317. bool Cast_OBBox(PhysOBBoxCollisionTestClass & boxtest) const;
  318. private:
  319. // These functions are used by the BptImpBuilder to construct
  320. // the BptImp...
  321. BptImpClass(void);
  322. void Set_Mesh(MeshClass * mesh);
  323. void Set_Node_Array(int numnodes, BptImpNodeClass * nodes);
  324. void Set_Normal_Array(const UniqueArrayClass<Vector3> & normals);
  325. void Set_Distance_Array(const UniqueArrayClass<float> & distances);
  326. void Set_Poly_Index_Array(int numremaps,int * polyremaps);
  327. void Begin_Apt(void);
  328. void Add_Polys_To_Apt(BptImpNodeClass * node);
  329. void End_Apt(void);
  330. void Build_Apt_Recursive(BptImpNodeClass * node,const CameraClass & cam);
  331. bool Cast_Ray_Recursive(BptImpNodeClass * node,PhysRayCollisionTestClass & boxtest) const;
  332. bool Cast_AABox_Recursive(BptImpNodeClass * node,PhysAABoxCollisionTestClass & boxtest) const;
  333. bool Cast_OBBox_Recursive(BptImpNodeClass * node,PhysOBBoxCollisionTestClass & boxtest) const;
  334. bool Cast_Ray_To_Polys(BptImpNodeClass * node,PhysAABoxCollisionTestClass & boxtest) const { assert(0); return false; }
  335. bool Cast_AABox_To_Polys(BptImpNodeClass * node,PhysAABoxCollisionTestClass & boxtest) const;
  336. bool Cast_OBBox_To_Polys(BptImpNodeClass * node,PhysAABoxCollisionTestClass & boxtest) const { assert(0); return false; }
  337. void Verify_Node_Bounding_Volume(BptImpNodeClass * node,const Vector3 & min,const Vector3 & max) const;
  338. // Polygon Mesh in w3d-friendly form
  339. MeshClass * Mesh;
  340. // Binary partition nodes
  341. int NodeCount;
  342. BptImpNodeClass * Nodes;
  343. // Node Polygon remap arrays
  344. int PolyIndexCount;
  345. int * PolyIndices;
  346. // Plane equation normals, these are stored separate from the distances
  347. // because many many of the planes will share the same normal but not dist.
  348. int NormalCount;
  349. Vector3 * Normals;
  350. // Plane equation distances, again, stored separately from the normals
  351. int DistanceCount;
  352. float * Distances;
  353. // Active Poly Table support. These variables are used internally by
  354. // the culling code. The ActivePolyTable pointer is set to point into
  355. // the surrender mesh's apt.
  356. int ActivePolyCount;
  357. SRDWORD * ActivePolyTable;
  358. friend class BptClass;
  359. friend class BptImpBuilderClass;
  360. };
  361. /*
  362. ** BptImpBuilderClass
  363. ** This guy takes a completed bpt tree (given as a pointer to the root node)
  364. ** and churns through the thing, generating a BptImpClass.
  365. */
  366. class BptImpBuilderClass
  367. {
  368. public:
  369. BptImpBuilderClass(void);
  370. ~BptImpBuilderClass(void);
  371. void Free(void);
  372. BptImpClass * Build_Bpt_Imp(BptNodeClass * root,MaterialInfoClass * matinfo);
  373. void Add_Bpt_Node(const BptNodeClass * node);
  374. private:
  375. void Remap_Triangle_Indices(void);
  376. MeshBuilderClass MeshBuilder; // accumulate the polygons
  377. NormalHasherClass NormalHasher; // computes hash values for the normals
  378. DistanceHasherClass DistanceHasher; // computes hash values for the distances
  379. UniqueArrayClass<Vector3> * UniqueNormals; // accumulates the unique normals
  380. UniqueArrayClass<float> * UniqueDistances; // accumulates the unique distances
  381. int NodeCount; // number of nodes in the tree
  382. BptImpNodeClass * Nodes; // array of all of the nodes
  383. int TriCount; // number of triangles in the tree
  384. int CurTriIndex; // current remap index
  385. int * TriIndexArray; // array of triangle remap indices
  386. };
  387. /***********************************************************************************************
  388. * BptClass::BptClass -- constructor *
  389. * *
  390. * INPUT: *
  391. * *
  392. * OUTPUT: *
  393. * *
  394. * WARNINGS: *
  395. * *
  396. * HISTORY: *
  397. * 5/6/98 GTH : Created. *
  398. *=============================================================================================*/
  399. BptClass::BptClass(void) :
  400. BptImp(NULL)
  401. {
  402. }
  403. /***********************************************************************************************
  404. * BptClass::~BptClass -- destructor *
  405. * *
  406. * INPUT: *
  407. * *
  408. * OUTPUT: *
  409. * *
  410. * WARNINGS: *
  411. * *
  412. * HISTORY: *
  413. * 5/6/98 GTH : Created. *
  414. *=============================================================================================*/
  415. BptClass::~BptClass(void)
  416. {
  417. Free();
  418. }
  419. /***********************************************************************************************
  420. * BptClass::Free -- releases all assets in use *
  421. * *
  422. * INPUT: *
  423. * *
  424. * OUTPUT: *
  425. * *
  426. * WARNINGS: *
  427. * *
  428. * HISTORY: *
  429. * 5/6/98 GTH : Created. *
  430. *=============================================================================================*/
  431. void BptClass::Free(void)
  432. {
  433. if (BptImp) {
  434. delete BptImp;
  435. BptImp = NULL;
  436. }
  437. }
  438. /***********************************************************************************************
  439. * BptClass::Build -- build a bpt from the given mesh (generates a new mesh) *
  440. * *
  441. * This function will process the given mesh into a binary partition tree. It has to generate *
  442. * a new mesh due to the fact that some polygons may be split in the partioning process. *
  443. * *
  444. * INPUT: *
  445. * *
  446. * OUTPUT: *
  447. * *
  448. * WARNINGS: *
  449. * *
  450. * HISTORY: *
  451. * 5/6/98 GTH : Created. *
  452. *=============================================================================================*/
  453. void BptClass::Build(MeshClass * mesh)
  454. {
  455. assert(mesh);
  456. /*
  457. ** First, release everything that we have!
  458. */
  459. Free();
  460. /*
  461. ** Create a new BptImp object using the given mesh
  462. */
  463. BptBuilderClass builder;
  464. BptImp = builder.Build(mesh);
  465. }
  466. /***********************************************************************************************
  467. * BptClass::Load -- Initialize this Bpt object from contents of a W3D file *
  468. * *
  469. * INPUT: *
  470. * *
  471. * OUTPUT: *
  472. * *
  473. * WARNINGS: *
  474. * *
  475. * HISTORY: *
  476. * 5/6/98 GTH : Created. *
  477. *=============================================================================================*/
  478. int BptClass::Load(ChunkLoadClass & cload)
  479. {
  480. assert(0);
  481. return 0;
  482. }
  483. /***********************************************************************************************
  484. * BptClass::Save -- Save this Bpt object into a W3D file *
  485. * *
  486. * INPUT: *
  487. * *
  488. * OUTPUT: *
  489. * *
  490. * WARNINGS: *
  491. * *
  492. * HISTORY: *
  493. * 5/6/98 GTH : Created. *
  494. *=============================================================================================*/
  495. int BptClass::Save(ChunkSaveClass & csave)
  496. {
  497. assert(0);
  498. return 0;
  499. }
  500. /***********************************************************************************************
  501. * BptClass::Render -- submit this object for rendering *
  502. * *
  503. * This function sets the active polygon table for the mesh based on the camera frustum. The *
  504. * bpt is used to cull out portions of the level which are not inside the frustum. Then the *
  505. * mesh is added to the given surrender scene. *
  506. * *
  507. * INPUT: *
  508. * *
  509. * OUTPUT: *
  510. * *
  511. * WARNINGS: *
  512. * *
  513. * HISTORY: *
  514. * 5/6/98 GTH : Created. *
  515. * 5/29/98 GTH : Created. *
  516. *=============================================================================================*/
  517. void BptClass::Render( srScene * scene, const CameraClass &camera )
  518. {
  519. /*
  520. ** Do our APT stuff
  521. */
  522. BptImp->Build_Apt(camera);
  523. /*
  524. ** Then let Mesh render itself
  525. */
  526. BptImp->Mesh->Render(scene,camera);
  527. }
  528. void BptClass::Update_Cached_Bounding_Volumes(void) const
  529. {
  530. CachedBoundingSphere = BptImp->Mesh->Get_Bounding_Sphere();
  531. CachedBoundingBox = BptImp->Mesh->Get_Bounding_Box();
  532. Validate_Cached_Bounding_Volumes();
  533. }
  534. #if 0
  535. MeshClass * BptClass::Get_Mesh(void)
  536. {
  537. if (BptImp) {
  538. if (BptImp->Mesh) BptImp->Mesh->Add_Ref();
  539. return BptImp->Mesh;
  540. } else {
  541. return NULL;
  542. }
  543. }
  544. #endif
  545. /***********************************************************************************************
  546. * BptClass::Cast_Ray -- Intersect a ray with this Bpt Object *
  547. * *
  548. * INPUT: *
  549. * *
  550. * OUTPUT: *
  551. * *
  552. * WARNINGS: *
  553. * *
  554. * HISTORY: *
  555. * 5/6/98 GTH : Created. *
  556. *=============================================================================================*/
  557. bool BptClass::Cast_Ray(PhysRayCollisionTestClass & raytest) const
  558. {
  559. assert(BptImp);
  560. return BptImp->Cast_Ray(raytest);
  561. }
  562. /***********************************************************************************************
  563. * BptClass::Cast_AABox -- Intersect a swept axis-aligned box. *
  564. * *
  565. * INPUT: *
  566. * *
  567. * OUTPUT: *
  568. * *
  569. * WARNINGS: *
  570. * *
  571. * HISTORY: *
  572. * 5/6/98 GTH : Created. *
  573. *=============================================================================================*/
  574. bool BptClass::Cast_AABox(PhysAABoxCollisionTestClass & aaboxtest) const
  575. {
  576. assert(BptImp);
  577. return BptImp->Cast_AABox(aaboxtest);
  578. }
  579. /***********************************************************************************************
  580. * BptClass::Cast_OBBox -- Intersect a swept oriented box with this bpt object *
  581. * *
  582. * INPUT: *
  583. * *
  584. * OUTPUT: *
  585. * *
  586. * WARNINGS: *
  587. * *
  588. * HISTORY: *
  589. * 5/6/98 GTH : Created. *
  590. *=============================================================================================*/
  591. bool BptClass::Cast_OBBox(PhysOBBoxCollisionTestClass & obboxtest) const
  592. {
  593. assert(BptImp);
  594. return BptImp->Cast_OBBox(obboxtest);
  595. }
  596. /**************************************************************
  597. BptVertexClass Implementation
  598. **************************************************************/
  599. BptVertexClass::BptVertexClass(void) :
  600. Position(0,0,0),
  601. Normal(0,0,0),
  602. Color(0,0,0),
  603. TexCoord(0,0,0)
  604. {
  605. }
  606. BptVertexClass::BptVertexClass(const BptVertexClass & that)
  607. {
  608. Position = that.Position;
  609. Normal = that.Normal;
  610. Color = that.Color;
  611. TexCoord = that.TexCoord;
  612. }
  613. BptVertexClass & BptVertexClass::operator = (const BptVertexClass & that)
  614. {
  615. if (this != &that) {
  616. Position = that.Position;
  617. Normal = that.Normal;
  618. Color = that.Color;
  619. TexCoord = that.TexCoord;
  620. }
  621. return *this;
  622. }
  623. BptVertexClass BptVertexClass::Lerp(const BptVertexClass & v0,const BptVertexClass & v1,double lerp)
  624. {
  625. assert(lerp >= -BPT_EPSILON);
  626. assert(lerp <= 1.0 + BPT_EPSILON);
  627. // interpolate position
  628. BptVertexClass res;
  629. res.Position = ::Lerp(v0.Position,v1.Position,lerp);
  630. // interpolate normal, renormalize
  631. res.Normal = ::Lerp(v0.Normal,v1.Normal,lerp);
  632. res.Normal.Normalize();
  633. // interpolate color
  634. res.Color = ::Lerp(v0.Color,v1.Color,lerp);
  635. // interpolate texture coordinates
  636. res.TexCoord = ::Lerp(v0.TexCoord,v1.TexCoord,lerp);
  637. return res;
  638. }
  639. int BptVertexClass::Which_Side(const PlaneClass & plane) const
  640. {
  641. float d = Vector3::Dot_Product(plane.N,Position);
  642. d -= plane.D;
  643. if (d > BPT_EPSILON) {
  644. return BPT_FRONT;
  645. }
  646. if (d < -BPT_EPSILON) {
  647. return BPT_BACK;
  648. }
  649. return BPT_ON;
  650. }
  651. BptVertexClass BptVertexClass::Intersect_Plane
  652. (
  653. const BptVertexClass & p0,
  654. const BptVertexClass & p1,
  655. const PlaneClass & plane
  656. )
  657. {
  658. double alpha = 0.0f;
  659. plane.Compute_Intersection(p0.Position,p1.Position,&alpha);
  660. return BptVertexClass::Lerp(p0,p1,alpha);
  661. }
  662. /**************************************************************
  663. BptPolyClass Implementation
  664. **************************************************************/
  665. BptPolyClass::BptPolyClass(void) :
  666. NumVerts(0)
  667. {
  668. }
  669. BptPolyClass::BptPolyClass(const BptPolyClass & that)
  670. {
  671. NumVerts = that.NumVerts;
  672. for (int i=0;i<NumVerts;i++) {
  673. Verts[i] = that.Verts[i];
  674. }
  675. }
  676. BptPolyClass::BptPolyClass(const BptVertexClass * points, int num)
  677. {
  678. NumVerts = num;
  679. for (int i=0; i<NumVerts; i++) {
  680. Verts[i] = points[i];
  681. }
  682. }
  683. BptPolyClass & BptPolyClass::operator = (const BptPolyClass & that)
  684. {
  685. if (this != &that) {
  686. MaterialId = that.MaterialId;
  687. NumVerts = that.NumVerts;
  688. Plane = that.Plane;
  689. for (int i=0;i<NumVerts;i++) {
  690. Verts[i] = that.Verts[i];
  691. }
  692. }
  693. return * this;
  694. }
  695. void BptPolyClass::Compute_Plane(void)
  696. {
  697. double nx = 0;
  698. double ny = 0;
  699. double nz = 0;
  700. double ax = 0;
  701. double ay = 0;
  702. double az = 0;
  703. int i,j;
  704. for (i=0; i<NumVerts; i++) {
  705. j = (i+1) % NumVerts;
  706. nx += (double)(Verts[i].Position.Y - Verts[j].Position.Y) * (double)(Verts[i].Position.Z + Verts[j].Position.Z);
  707. ny += (double)(Verts[i].Position.Z - Verts[j].Position.Z) * (double)(Verts[i].Position.X + Verts[j].Position.X);
  708. nz += (double)(Verts[i].Position.X - Verts[j].Position.X) * (double)(Verts[i].Position.Y + Verts[j].Position.Y);
  709. ax += (double)Verts[i].Position.X;
  710. ay += (double)Verts[i].Position.Y;
  711. az += (double)Verts[i].Position.Z;
  712. }
  713. ax /= (double)NumVerts;
  714. ay /= (double)NumVerts;
  715. az /= (double)NumVerts;
  716. double len = sqrt(nx*nx + ny*ny + nz*nz);
  717. nx /= len;
  718. ny /= len;
  719. nz /= len;
  720. Plane.Set(Vector3(nx,ny,nz),Vector3(ax,ay,az));
  721. }
  722. int BptPolyClass::Which_Side(const PlaneClass & plane) const
  723. {
  724. int side_mask = 0;
  725. for (int i=0; i<NumVerts;i++) {
  726. side_mask |= Verts[i].Which_Side(plane);
  727. }
  728. // check if all verts are "ON"
  729. if (side_mask == BPT_ON) {
  730. return BPT_ON;
  731. }
  732. // check if all verts are either "ON" or "FRONT"
  733. if ((side_mask & ~(BPT_FRONT | BPT_ON)) == 0) {
  734. return BPT_FRONT;
  735. }
  736. // check if all verts are either "ON" or "BACK"
  737. if ((side_mask & ~(BPT_BACK | BPT_ON)) == 0) {
  738. return BPT_BACK;
  739. }
  740. // otherwise, poly spans the plane.
  741. return BPT_BOTH;
  742. }
  743. void BptPolyClass::Split(const PlaneClass & plane,BptPolyClass & front,BptPolyClass & back) const
  744. {
  745. front = *this;
  746. back = *this;
  747. front.NumVerts = back.NumVerts = 0;
  748. assert(Which_Side(plane) == BPT_BOTH);
  749. BptVertexClass point;
  750. front.NumVerts = 0;
  751. back.NumVerts = 0;
  752. // find a vertex on one side or the other
  753. int side = BPT_ON;
  754. int i;
  755. for (i = 0; (i < NumVerts) && ((side = Verts[i].Which_Side(plane)) == BPT_ON); i++);
  756. // perform clipping
  757. int iprev = i;
  758. int sideprev = side;
  759. int sidelastdefinite = 0;
  760. i = (i+1) % NumVerts;
  761. for (int j=0; j<NumVerts; j++) {
  762. side = Verts[i].Which_Side(plane);
  763. if (sideprev == BPT_FRONT) {
  764. if (side == BPT_FRONT) {
  765. // Previous vertex was in front of plane and this vertex is in
  766. // front of the plane so we emit this vertex in the front poly
  767. front.Verts[(front.NumVerts)++] = Verts[i];
  768. } else if (side == BPT_ON) {
  769. // Previous vert was in front, this vert is "on" so emit
  770. // the vertex into the front poly.
  771. sidelastdefinite = BPT_FRONT;
  772. front.Verts[(front.NumVerts)++] = Verts[i];
  773. } else { // side == BPT_BACK
  774. // Previous vert was in front, this vert is behind, compute
  775. // the intersection and emit the point in both the front
  776. // and back polys. Then continue the edge into the back halfspace
  777. point = BptVertexClass::Intersect_Plane(Verts[iprev],Verts[i],plane);
  778. front.Verts[(front.NumVerts)++] = point;
  779. back.Verts[(back.NumVerts)++] = point;
  780. back.Verts[(back.NumVerts)++] = Verts[i];
  781. }
  782. } else if (sideprev == BPT_BACK) {
  783. if (side == BPT_FRONT) {
  784. // segment is going from the back halfspace to the front halfspace
  785. // compute the intersection and emit it in both polys, then continue
  786. // the edge into the front halfspace.
  787. point = BptVertexClass::Intersect_Plane(Verts[iprev],Verts[i],plane);
  788. back.Verts[(back.NumVerts)++] = point;
  789. front.Verts[(front.NumVerts)++] = point;
  790. front.Verts[(front.NumVerts)++] = Verts[i];
  791. } else if (side == BPT_ON) {
  792. // segment went from back halfspace to "on" the plane. Emit
  793. // the vertex into the back poly and remember that we came
  794. // from the back halfspace.
  795. sidelastdefinite = BPT_BACK;
  796. back.Verts[(back.NumVerts)++] = Verts[i];
  797. } else { // side == BPT_BACK
  798. // segment is completely in the back halfspace, just emit the
  799. // vertex into the back poly
  800. back.Verts[(back.NumVerts)++] = Verts[i];
  801. }
  802. } else if (sideprev == BPT_ON) {
  803. if (side == BPT_FRONT) {
  804. // segment is on the plane
  805. if (sidelastdefinite == BPT_BACK) {
  806. front.Verts[(front.NumVerts)++] = Verts[iprev];
  807. }
  808. front.Verts[(front.NumVerts)++] = Verts[i];
  809. } else if (side == BPT_ON) {
  810. if (sidelastdefinite == BPT_FRONT) {
  811. front.Verts[(front.NumVerts)++] = Verts[i];
  812. } else {
  813. back.Verts[(back.NumVerts)++] = Verts[i];
  814. }
  815. } else { // side == BPT_BACK
  816. if (sidelastdefinite == BPT_FRONT) {
  817. back.Verts[(back.NumVerts)++] = Verts[iprev];
  818. }
  819. back.Verts[(back.NumVerts)++] = Verts[i];
  820. }
  821. } else {
  822. WWASSERT_PRINT(0,"BptPolyClass::Split : invalid side\n");
  823. }
  824. sideprev = side;
  825. iprev = i;
  826. i = (i+1)%NumVerts;
  827. }
  828. front.Compute_Plane();
  829. back.Compute_Plane();
  830. // check the two polygons
  831. if (front.Is_Degenerate()) {
  832. front.Salvage_Degenerate();
  833. }
  834. if (back.Is_Degenerate()) {
  835. back.Salvage_Degenerate();
  836. }
  837. }
  838. bool BptPolyClass::Is_Degenerate(void)
  839. {
  840. int i,j;
  841. if (NumVerts == 2) {
  842. WWDEBUG_SAY(("Degenerate Poly - fewer than 3 vertices\r\n"));
  843. return true;
  844. }
  845. for (i=0; i<NumVerts; i++) {
  846. for (j = i+1; j < NumVerts; j++) {
  847. float delta = (Verts[i].Position - Verts[j].Position).Length();
  848. if (delta < BPT_COINCIDENCE_EPSILON) {
  849. WWDEBUG_SAY(("Degenerate Poly - coincident vertices!\r\n"));
  850. return true;
  851. }
  852. }
  853. }
  854. for (i=0; i<NumVerts; i++) {
  855. int side = Verts[i].Which_Side(Plane);
  856. if (side != BPT_ON) {
  857. // hmmm, try to recalculate the plane, if it is still bad, then give up
  858. Compute_Plane();
  859. if (Verts[i].Which_Side(Plane) != BPT_ON) {
  860. WWDEBUG_SAY(("Degenerate Poly - invalid plane!\r\n"));
  861. return true;
  862. }
  863. }
  864. }
  865. return false;
  866. }
  867. bool BptPolyClass::Salvage_Degenerate(void)
  868. {
  869. /*
  870. ** About all we can do is combine sequential vertices which are co-incident
  871. */
  872. int i = 0;
  873. while (i < NumVerts) {
  874. float delta = (Verts[i].Position - Verts[i+1].Position).Length();
  875. if (delta < BPT_COINCIDENCE_EPSILON) {
  876. for (int j=i+1; j<NumVerts-1; j++) {
  877. Verts[j] = Verts[j+1];
  878. }
  879. NumVerts--;
  880. } else {
  881. i++;
  882. }
  883. }
  884. return !Is_Degenerate();
  885. }
  886. /**************************************************************
  887. BptBuilderClass Implementation
  888. **************************************************************/
  889. BptBuilderClass::BptBuilderClass(void) :
  890. Root(NULL),
  891. MatInfo(NULL),
  892. InputPolyCount(0),
  893. OutputPolyCount(0),
  894. NodeCount(0),
  895. MaxDepth(0)
  896. {
  897. }
  898. BptBuilderClass::~BptBuilderClass(void)
  899. {
  900. if (Root) delete Root;
  901. if (MatInfo) MatInfo->Release_Ref();
  902. }
  903. BptImpClass * BptBuilderClass::Build(MeshClass * mesh)
  904. {
  905. /*
  906. ** Here we go, unwind the mesh into BptVerts and BptPolys
  907. */
  908. int numpolys;
  909. BptPolyClass * polys;
  910. unwind_mesh(mesh,numpolys,polys);
  911. assert(numpolys > 0);
  912. /*
  913. ** Jump into the generalized build method
  914. */
  915. MaterialInfoClass * matinfo = mesh->Get_Material_Info();
  916. BptImpClass * result = Build(numpolys,polys,matinfo);
  917. matinfo->Release_Ref();
  918. /*
  919. ** Build function deletes the poly array...
  920. */
  921. polys = NULL;
  922. return result;
  923. }
  924. BptImpClass * BptBuilderClass::Build(int numpolys,BptPolyClass * polys,MaterialInfoClass * matinfo)
  925. {
  926. /*
  927. ** Create a copy of all of the materials
  928. */
  929. MatInfo = (MaterialInfoClass *)matinfo->Clone();
  930. /*
  931. ** Store the input counts
  932. */
  933. InputPolyCount = numpolys;
  934. InputTriCount = 0;
  935. for (int i=0; i<numpolys; i++) {
  936. InputTriCount += polys[i].NumVerts-2;
  937. }
  938. WWDEBUG_SAY(("Building Binary Tree\r\n"));
  939. /*
  940. ** Build the fat tree
  941. */
  942. assert(Root == NULL);
  943. Root = new BptNodeClass;
  944. Root->Build(numpolys,polys);
  945. /*
  946. ** Compile some statistics about the tree
  947. */
  948. OutputPolyCount = Root->Num_Polys();
  949. OutputTriCount = Root->Num_Tris();
  950. NodeCount = Root->Num_Nodes();
  951. MaxDepth = Root->Max_Depth();
  952. WWDEBUG_SAY(("Binary Tree Generated!\r\n"));
  953. WWDEBUG_SAY(("Node Count: %d\r\n",NodeCount));
  954. WWDEBUG_SAY(("Max Depth: %d\r\n",MaxDepth));
  955. WWDEBUG_SAY(("Input Poly Count: %d\r\n",InputPolyCount));
  956. WWDEBUG_SAY(("Output Poly Count: %d\r\n",OutputPolyCount));
  957. WWDEBUG_SAY(("Input Tri Count: %d\r\n",InputTriCount));
  958. WWDEBUG_SAY(("Output Tri Count: %d\r\n",OutputTriCount));
  959. WWDEBUG_SAY(("Out/In Poly Ratio: %f\r\n",(float)OutputPolyCount / (float)InputPolyCount));
  960. WWDEBUG_SAY(("Out/In Tri Ratio: %f\r\n",(float)OutputTriCount / (float)InputTriCount));
  961. WWDEBUG_SAY(("\r\n"));
  962. /*
  963. ** Build the optimized BptImp and return it.
  964. */
  965. return build_imp();
  966. }
  967. void BptBuilderClass::unwind_mesh(MeshClass * mesh,int & set_numpolys,BptPolyClass * & set_polyarray)
  968. {
  969. srMeshModel * srmesh = mesh->Get_Surrender_Mesh();
  970. // get pointers to the interesting stuff in the mesh
  971. srVector3 * loc = srmesh->getVertexLoc();
  972. srVector3 * norm = srmesh->getVertexNormal();
  973. srVector3 * uv = srmesh->getVertexUVW(srMaterial::DIFFUSE_COLOR,false);
  974. srVector3 * dcg = srmesh->getVertexDCG(false);
  975. srVector3i * polyvert = srmesh->getPolyVertex();
  976. srMaterial ** polymtl = srmesh->getPolyMaterial(false);
  977. // allocate a bunch of BptPolygons
  978. set_numpolys = srmesh->getPolygonCount();
  979. set_polyarray = new BptPolyClass[set_numpolys];
  980. int src_idx = 0;
  981. int dst_idx = 0;
  982. for (src_idx = 0; src_idx<set_numpolys; src_idx++) {
  983. set_polyarray[dst_idx].NumVerts = 3;
  984. for (int vrt_idx=0; vrt_idx<3; vrt_idx++) {
  985. // copy the three positions
  986. set_polyarray[dst_idx][vrt_idx].Position.X = loc[polyvert[src_idx][vrt_idx]].x;
  987. set_polyarray[dst_idx][vrt_idx].Position.Y = loc[polyvert[src_idx][vrt_idx]].y;
  988. set_polyarray[dst_idx][vrt_idx].Position.Z = loc[polyvert[src_idx][vrt_idx]].z;
  989. // copy the three normals
  990. if (norm) {
  991. set_polyarray[dst_idx][vrt_idx].Normal.X = norm[polyvert[src_idx][vrt_idx]].x;
  992. set_polyarray[dst_idx][vrt_idx].Normal.Y = norm[polyvert[src_idx][vrt_idx]].y;
  993. set_polyarray[dst_idx][vrt_idx].Normal.Z = norm[polyvert[src_idx][vrt_idx]].z;
  994. }
  995. // copy the three u-v's
  996. if (uv) {
  997. set_polyarray[dst_idx][vrt_idx].TexCoord.X = uv[polyvert[src_idx][vrt_idx]].x;
  998. set_polyarray[dst_idx][vrt_idx].TexCoord.Y = uv[polyvert[src_idx][vrt_idx]].y;
  999. set_polyarray[dst_idx][vrt_idx].TexCoord.Z = uv[polyvert[src_idx][vrt_idx]].z;
  1000. }
  1001. // copy the three colors
  1002. if (dcg) {
  1003. set_polyarray[dst_idx][vrt_idx].Color.X = dcg[polyvert[src_idx][vrt_idx]].x;
  1004. set_polyarray[dst_idx][vrt_idx].Color.Y = dcg[polyvert[src_idx][vrt_idx]].y;
  1005. set_polyarray[dst_idx][vrt_idx].Color.Z = dcg[polyvert[src_idx][vrt_idx]].z;
  1006. }
  1007. // store the material ID
  1008. if (polymtl) {
  1009. set_polyarray[dst_idx].MaterialId = ((MaterialClass *)(polymtl[src_idx]))->Get_Mat_Info_Index();
  1010. } else {
  1011. set_polyarray[dst_idx].MaterialId = 0;
  1012. }
  1013. }
  1014. set_polyarray[dst_idx].Compute_Plane();
  1015. // if the triangle is not degenerate, accept it; increment the counter
  1016. if (!set_polyarray[dst_idx].Is_Degenerate()) {
  1017. dst_idx++;
  1018. }
  1019. }
  1020. // set the number of polys to the actual number kept
  1021. set_numpolys = dst_idx;
  1022. assert(set_numpolys <= srmesh->getPolygonCount());
  1023. WWDEBUG_SAY(("Unwinding Input Mesh\r\n"));
  1024. WWDEBUG_SAY(("Input poly count: %d\r\n",srmesh->getPolygonCount()));
  1025. WWDEBUG_SAY(("Count after removing degenerates: %d\r\n",set_numpolys));
  1026. WWDEBUG_SAY(("\r\n"));
  1027. }
  1028. BptImpClass * BptBuilderClass::build_imp(void)
  1029. {
  1030. BptImpBuilderClass impbuilder;
  1031. BptImpClass * imp = impbuilder.Build_Bpt_Imp(Root,MatInfo);
  1032. return imp;
  1033. }
  1034. /**************************************************************
  1035. BptNodeClass Implementation
  1036. **************************************************************/
  1037. int BptNodeClass::Num_Polys(void) const
  1038. {
  1039. int count = NumPolys;
  1040. if (Front) count += Front->Num_Polys();
  1041. if (Back) count += Back->Num_Polys();
  1042. return count;
  1043. }
  1044. int BptNodeClass::Num_Tris(void) const
  1045. {
  1046. int count = 0;
  1047. for (unsigned int i=0; i<NumPolys; i++) {
  1048. count += Polys[i].NumVerts - 2;
  1049. }
  1050. if (Front) count += Front->Num_Tris();
  1051. if (Back) count += Back->Num_Tris();
  1052. return count;
  1053. }
  1054. int BptNodeClass::Num_Nodes(void) const
  1055. {
  1056. int count = 1;
  1057. if (Front) count += Front->Num_Nodes();
  1058. if (Back) count += Back->Num_Nodes();
  1059. return count;
  1060. }
  1061. int BptNodeClass::Max_Depth(void) const
  1062. {
  1063. int max_depth = 0;
  1064. Max_Depth_Internal(0,max_depth);
  1065. return max_depth;
  1066. }
  1067. void BptNodeClass::Max_Depth_Internal(int cur_depth,int & max_depth) const
  1068. {
  1069. cur_depth++;
  1070. if (cur_depth > max_depth) {
  1071. max_depth = cur_depth;
  1072. }
  1073. if (Front) {
  1074. Front->Max_Depth_Internal(cur_depth,max_depth);
  1075. }
  1076. if (Back) {
  1077. Back->Max_Depth_Internal(cur_depth,max_depth);
  1078. }
  1079. }
  1080. void BptNodeClass::Build(int numpolys,BptPolyClass * polys)
  1081. {
  1082. /*
  1083. ** Select and assign the splitting plane
  1084. */
  1085. SplitChoiceStruct sc = Select_Splitting_Plane(numpolys,polys);
  1086. Plane = sc.Plane;
  1087. /*
  1088. ** Split the polygons
  1089. */
  1090. SplitArraysStruct arrays;
  1091. Split_Polys(numpolys,polys,sc,&arrays);
  1092. /*
  1093. ** Free the memory in use by polys!
  1094. */
  1095. delete[] polys;
  1096. /*
  1097. ** Store the "on" polys in this node
  1098. */
  1099. NumPolys = arrays.OnCount;
  1100. Polys = arrays.OnPolys;
  1101. arrays.OnPolys = NULL;
  1102. /*
  1103. ** Build a front tree if necessary. Remember that the Build function
  1104. ** deletes the poly array.
  1105. */
  1106. if (arrays.FrontCount) {
  1107. assert(arrays.FrontPolys != NULL);
  1108. Front = new BptNodeClass;
  1109. Front->Build(arrays.FrontCount,arrays.FrontPolys);
  1110. arrays.FrontPolys = NULL;
  1111. }
  1112. /*
  1113. ** Build a back tree if necessary. Remember that the build function
  1114. ** deletes the poly array.
  1115. */
  1116. if (arrays.BackCount) {
  1117. assert(arrays.BackPolys != NULL);
  1118. Back = new BptNodeClass;
  1119. Back->Build(arrays.BackCount,arrays.BackPolys);
  1120. arrays.BackPolys = NULL;
  1121. }
  1122. }
  1123. BptNodeClass::SplitChoiceStruct
  1124. BptNodeClass::Compute_Plane_Score(int numpolys,BptPolyClass * polys,const PlaneClass & plane)
  1125. {
  1126. /*
  1127. ** Suitability of a plane as a partition plane is based on the following factors:
  1128. ** - How many polygons will be split
  1129. ** - How many polygons end up on each side of the tree
  1130. ** - How many polygons end up on the plane (do NOT want many on the plane)
  1131. ** - How evenly the volume of space is divided.
  1132. ** The following weights will determine how much influence each factor
  1133. ** has on the final score.
  1134. */
  1135. const float POLY_SPLIT_WEIGHT = 5.0f;
  1136. const float POLY_COUNT_BALANCE_WEIGHT = 1.0f;
  1137. const float POLYS_ON_PLANE_WEIGHT = 1.0f;
  1138. const float TOTAL_WEIGHT = POLY_SPLIT_WEIGHT + POLY_COUNT_BALANCE_WEIGHT + POLYS_ON_PLANE_WEIGHT;
  1139. const int MAX_POLYS_ON_PLANE = 10;
  1140. const int MAX_SPLITS = 10;
  1141. /*
  1142. ** Count up the cases
  1143. */
  1144. SplitChoiceStruct sc;
  1145. sc.Plane = plane;
  1146. for (int i=0; i<numpolys; i++) {
  1147. switch(polys[i].Which_Side(plane)) {
  1148. case BPT_FRONT: sc.FrontCount++; break;
  1149. case BPT_BACK: sc.BackCount++; break;
  1150. case BPT_ON: sc.OnCount++; break;
  1151. case BPT_BOTH: sc.SplitCount++; break;
  1152. }
  1153. }
  1154. /*
  1155. ** Compute the score
  1156. */
  1157. float max_splits = min(MAX_SPLITS,numpolys);
  1158. float max_on = min(MAX_POLYS_ON_PLANE,numpolys);
  1159. float split_score = (float)(max_splits - sc.SplitCount) / max_splits;
  1160. if (split_score < 0.0f) split_score = 0.0f;
  1161. float on_score = 1.0f - (float)sc.OnCount / max_on;
  1162. if (on_score < 0.0f) on_score = 0.0f;
  1163. float balance_score = 1.0f - (fabs(sc.FrontCount - sc.BackCount) / ((float)numpolys / 2.0f));
  1164. sc.Score = 0.0f;
  1165. sc.Score += split_score * POLY_SPLIT_WEIGHT;
  1166. sc.Score += balance_score * POLY_COUNT_BALANCE_WEIGHT;
  1167. sc.Score += on_score * POLYS_ON_PLANE_WEIGHT;
  1168. sc.Score /= TOTAL_WEIGHT;
  1169. /*
  1170. ** Reject the plane if any of the following conditions are true:
  1171. ** - plane does not reduce the tree! (all polys in front or behind)
  1172. ** - more than MAX_POLYS_ON_PLANE polygons on the splitting plane
  1173. */
  1174. if ((abs(sc.FrontCount-sc.BackCount) == numpolys) && (sc.OnCount == 0)) {
  1175. sc.Score = 0.0f;
  1176. }
  1177. if (sc.OnCount > MAX_POLYS_ON_PLANE) {
  1178. sc.Score *= 0.4f;
  1179. }
  1180. return sc;
  1181. }
  1182. BptNodeClass::SplitChoiceStruct
  1183. BptNodeClass::Select_Splitting_Plane(int numpolys,BptPolyClass * polys)
  1184. {
  1185. doitagain:
  1186. const int NUM_VERTEX_TRYS = 30;
  1187. const int NUM_POLY_TRYS = 30;
  1188. SplitChoiceStruct best_plane_stats;
  1189. SplitChoiceStruct considered_plane_stats;
  1190. PlaneClass plane;
  1191. /*
  1192. ** Try putting axis-aligned planes through some random vertices
  1193. */
  1194. for (int vertex_trys = 0; vertex_trys < min(NUM_VERTEX_TRYS,3*numpolys); vertex_trys++) {
  1195. int poly_index = rand() % numpolys;
  1196. int vert_index = rand() % polys[poly_index].NumVerts;;
  1197. Vector3 pos = polys[poly_index].Verts[vert_index].Position;
  1198. /*
  1199. ** Try the x-axis
  1200. */
  1201. plane.Set(Vector3(1,0,0),pos);
  1202. considered_plane_stats = Compute_Plane_Score(numpolys,polys,plane);
  1203. if (considered_plane_stats.Score > best_plane_stats.Score) {
  1204. best_plane_stats = considered_plane_stats;
  1205. }
  1206. /*
  1207. ** Try the y-axis
  1208. */
  1209. plane.Set(Vector3(0,1,0),pos);
  1210. considered_plane_stats = Compute_Plane_Score(numpolys,polys,plane);
  1211. if (considered_plane_stats.Score > best_plane_stats.Score) {
  1212. best_plane_stats = considered_plane_stats;
  1213. }
  1214. }
  1215. /*
  1216. ** Now try "autopartition" planes which come from the input polygons
  1217. */
  1218. for (int poly_trys=0; poly_trys<min(NUM_POLY_TRYS,numpolys); poly_trys++) {
  1219. int poly_index = rand() % numpolys;
  1220. assert(
  1221. (polys[poly_index][0].Which_Side(polys[poly_index].Plane) == BPT_ON) &&
  1222. (polys[poly_index][1].Which_Side(polys[poly_index].Plane) == BPT_ON) &&
  1223. (polys[poly_index][2].Which_Side(polys[poly_index].Plane) == BPT_ON)
  1224. );
  1225. considered_plane_stats = Compute_Plane_Score(numpolys,polys,polys[poly_index].Plane);
  1226. if (considered_plane_stats.Score > best_plane_stats.Score) {
  1227. best_plane_stats = considered_plane_stats;
  1228. }
  1229. }
  1230. if (best_plane_stats.Score <= 0.0f) {
  1231. _asm int 0x03;
  1232. goto doitagain;
  1233. }
  1234. //assert(best_plane_stats.Score > 0.0f);
  1235. return best_plane_stats;
  1236. }
  1237. void BptNodeClass::Split_Polys
  1238. (
  1239. const int num_polys,
  1240. const BptPolyClass * polys,
  1241. const SplitChoiceStruct & sc,
  1242. SplitArraysStruct * arrays
  1243. )
  1244. {
  1245. // Note that this routine allocates three arrays of polygons, an array of polys in
  1246. // front of the plane, an array of polys behind the plane, and an array of polys on the plane.
  1247. // The caller is then responsible for keeping track of the memory this routine allocates.
  1248. if (sc.FrontCount + sc.SplitCount > 0) {
  1249. arrays->FrontPolys = new BptPolyClass[sc.FrontCount + sc.SplitCount];
  1250. }
  1251. if (sc.BackCount + sc.SplitCount > 0) {
  1252. arrays->BackPolys = new BptPolyClass[sc.BackCount + sc.SplitCount];
  1253. }
  1254. if (sc.OnCount > 0) {
  1255. arrays->OnPolys = new BptPolyClass[sc.OnCount];
  1256. }
  1257. arrays->FrontCount = 0;
  1258. arrays->BackCount = 0;
  1259. arrays->OnCount = 0;
  1260. for (int i=0; i<num_polys; i++) {
  1261. switch(polys[i].Which_Side(sc.Plane)) {
  1262. case BPT_FRONT:
  1263. arrays->FrontPolys[arrays->FrontCount++] = polys[i];
  1264. break;
  1265. case BPT_BACK:
  1266. arrays->BackPolys[arrays->BackCount++] = polys[i];
  1267. break;
  1268. case BPT_ON:
  1269. arrays->OnPolys[arrays->OnCount++] = polys[i];
  1270. break;
  1271. case BPT_BOTH:
  1272. polys[i].Split(sc.Plane,arrays->FrontPolys[arrays->FrontCount],arrays->BackPolys[arrays->BackCount]);
  1273. if (!arrays->FrontPolys[arrays->FrontCount].Is_Degenerate()) {
  1274. arrays->FrontCount++;
  1275. }
  1276. if (!arrays->BackPolys[arrays->BackCount].Is_Degenerate()) {
  1277. arrays->BackCount++;
  1278. }
  1279. break;
  1280. }
  1281. }
  1282. // when we are all done, the counts should match.
  1283. assert(arrays->FrontCount <= sc.FrontCount + sc.SplitCount);
  1284. assert(arrays->BackCount <= sc.BackCount + sc.SplitCount);
  1285. assert(arrays->OnCount == sc.OnCount);
  1286. /*
  1287. ** Check if we threw away all of the polys
  1288. ** (this can only happen if all of them were degenerate...)
  1289. */
  1290. if ((arrays->OnCount == 0) && (arrays->OnPolys != NULL)) {
  1291. delete[] arrays->OnPolys;
  1292. arrays->OnPolys = NULL;
  1293. }
  1294. if ((arrays->BackCount == 0) && (arrays->BackPolys != NULL)) {
  1295. delete[] arrays->BackPolys;
  1296. arrays->BackPolys = NULL;
  1297. }
  1298. if ((arrays->FrontCount == 0) && (arrays->FrontPolys != NULL)) {
  1299. delete[] arrays->FrontPolys;
  1300. arrays->FrontPolys = NULL;
  1301. }
  1302. }
  1303. void BptNodeClass::Submit_Polys(MeshBuilderClass & builder) const
  1304. {
  1305. /*
  1306. ** Submit the back tree
  1307. */
  1308. if (Back) {
  1309. Back->Submit_Polys(builder);
  1310. }
  1311. /*
  1312. ** Triangulate each poly and submit it to the mesh builder
  1313. */
  1314. MeshBuilderClass::FaceClass face;
  1315. for (unsigned int fi=0; fi<NumPolys; fi++) {
  1316. BptPolyClass * poly = &(Polys[fi]);
  1317. for (int ti = 2;ti < poly->NumVerts; ti++) {
  1318. face.MaterialIdx = poly->MaterialId;
  1319. face.SmGroup = 1; //TODO: get the correct smooth group???
  1320. face.Index = 0; //TODO: do we have an actual index?
  1321. face.Attributes = 0;
  1322. face.Verts[0].Position = poly->Verts[0].Position;
  1323. face.Verts[0].TexCoord = poly->Verts[0].TexCoord;
  1324. face.Verts[0].Color = poly->Verts[0].Color;
  1325. face.Verts[1].Position = poly->Verts[ti-1].Position;
  1326. face.Verts[1].TexCoord = poly->Verts[ti-1].TexCoord;
  1327. face.Verts[1].Color = poly->Verts[ti-1].Color;
  1328. face.Verts[2].Position = poly->Verts[ti].Position;
  1329. face.Verts[2].TexCoord = poly->Verts[ti].TexCoord;
  1330. face.Verts[2].Color = poly->Verts[ti].Color;
  1331. builder.Add_Face(face);
  1332. }
  1333. }
  1334. /*
  1335. ** Submit the front tree
  1336. */
  1337. if (Front) {
  1338. Front->Submit_Polys(builder);
  1339. }
  1340. }
  1341. void BptNodeClass::Compute_Bounding_Box(void)
  1342. {
  1343. /*
  1344. ** make the children update their boxes first
  1345. */
  1346. if (Front) {
  1347. Front->Compute_Bounding_Box();
  1348. }
  1349. if (Back) {
  1350. Back->Compute_Bounding_Box();
  1351. }
  1352. Min.Set(10000.0f,10000.0f,10000.0f);
  1353. Max.Set(-10000.0f,-10000.0f,-10000.0f);
  1354. /*
  1355. ** Bound the polys in this node
  1356. */
  1357. for (unsigned int poly_index = 0; poly_index < NumPolys; poly_index++) {
  1358. for (int vert_index = 0; vert_index < Polys[poly_index].NumVerts; vert_index++) {
  1359. Vector3 & point = Polys[poly_index].Verts[vert_index].Position;
  1360. if (point.X - BPT_EPSILON < Min.X) Min.X = point.X - BPT_EPSILON;
  1361. if (point.X + BPT_EPSILON > Max.X) Max.X = point.X + BPT_EPSILON;
  1362. if (point.Y - BPT_EPSILON < Min.Y) Min.Y = point.Y - BPT_EPSILON;
  1363. if (point.Y + BPT_EPSILON > Max.Y) Max.Y = point.Y + BPT_EPSILON;
  1364. if (point.Z - BPT_EPSILON < Min.Z) Min.Z = point.Z - BPT_EPSILON;
  1365. if (point.Z + BPT_EPSILON > Max.Z) Max.Z = point.Z + BPT_EPSILON;
  1366. }
  1367. }
  1368. /*
  1369. ** bound the polys in the front child node
  1370. */
  1371. if (Front) {
  1372. if (Front->Min.X < Min.X) Min.X = Front->Min.X;
  1373. if (Front->Max.X > Max.X) Max.X = Front->Max.X;
  1374. if (Front->Min.Y < Min.Y) Min.Y = Front->Min.Y;
  1375. if (Front->Max.Y > Max.Y) Max.Y = Front->Max.Y;
  1376. if (Front->Min.Z < Min.Z) Min.Z = Front->Min.Z;
  1377. if (Front->Max.Z > Max.Z) Max.Z = Front->Max.Z;
  1378. }
  1379. /*
  1380. ** bound the polys in the back child node
  1381. */
  1382. if (Back) {
  1383. if (Back->Min.X < Min.X) Min.X = Back->Min.X;
  1384. if (Back->Max.X > Max.X) Max.X = Back->Max.X;
  1385. if (Back->Min.Y < Min.Y) Min.Y = Back->Min.Y;
  1386. if (Back->Max.Y > Max.Y) Max.Y = Back->Max.Y;
  1387. if (Back->Min.Z < Min.Z) Min.Z = Back->Min.Z;
  1388. if (Back->Max.Z > Max.Z) Max.Z = Back->Max.Z;
  1389. }
  1390. assert(Min.X != 10000.0f);
  1391. assert(Min.Y != 10000.0f);
  1392. assert(Min.Z != 10000.0f);
  1393. assert(Max.X != -10000.0f);
  1394. assert(Max.Y != -10000.0f);
  1395. assert(Max.Z != -10000.0f);
  1396. }
  1397. int BptNodeClass::Assign_Array_Indices(int index)
  1398. {
  1399. /*
  1400. ** This function is used to assign a sequential index to
  1401. ** each node in the tree. The BptImp stores its nodes in
  1402. ** an array so this index is used to determine which slot
  1403. ** in the array to put each node into.
  1404. */
  1405. ArrayIndex = index;
  1406. index++;
  1407. if (Front) {
  1408. index = Front->Assign_Array_Indices(index);
  1409. }
  1410. if (Back) {
  1411. index = Back->Assign_Array_Indices(index);
  1412. }
  1413. return index;
  1414. }
  1415. void BptNodeClass::Submit_Nodes(BptImpBuilderClass & imp_builder) const
  1416. {
  1417. imp_builder.Add_Bpt_Node(this);
  1418. if (Front) {
  1419. Front->Submit_Nodes(imp_builder);
  1420. }
  1421. if (Back) {
  1422. Back->Submit_Nodes(imp_builder);
  1423. }
  1424. }
  1425. /**************************************************************
  1426. BptImpClass Implementation
  1427. **************************************************************/
  1428. inline bool BptImpNodeClass::Is_Visible(const CameraClass & camera)
  1429. {
  1430. return !camera.Cull_Box(Vector3(MinX,MinY,MinZ),Vector3(MaxX,MaxY,MaxZ));
  1431. }
  1432. /**************************************************************
  1433. BptImpClass Implementation
  1434. **************************************************************/
  1435. BptImpClass::BptImpClass(void) :
  1436. Mesh(NULL),
  1437. NodeCount(0),
  1438. Nodes(NULL),
  1439. PolyIndexCount(0),
  1440. PolyIndices(NULL),
  1441. NormalCount(0),
  1442. Normals(NULL),
  1443. DistanceCount(0),
  1444. Distances(NULL),
  1445. ActivePolyCount(0),
  1446. ActivePolyTable(NULL)
  1447. {
  1448. }
  1449. BptImpClass::~BptImpClass(void)
  1450. {
  1451. Free();
  1452. }
  1453. void BptImpClass::Free(void)
  1454. {
  1455. if (Mesh!=NULL) {
  1456. Mesh->Release_Ref();
  1457. Mesh = NULL;
  1458. }
  1459. NodeCount = 0;
  1460. if (Nodes != NULL) {
  1461. delete[] Nodes;
  1462. Nodes = NULL;
  1463. }
  1464. PolyIndexCount = 0;
  1465. if (PolyIndices != NULL) {
  1466. delete[] PolyIndices;
  1467. PolyIndices = NULL;
  1468. }
  1469. NormalCount = 0;
  1470. if (Normals != NULL) {
  1471. delete[] Normals;
  1472. Normals = NULL;
  1473. }
  1474. DistanceCount = 0;
  1475. if (Distances != NULL) {
  1476. delete[] Distances;
  1477. Distances = NULL;
  1478. }
  1479. }
  1480. void BptImpClass::Set_Mesh(MeshClass * mesh)
  1481. {
  1482. if (Mesh) Mesh->Release_Ref();
  1483. Mesh = mesh;
  1484. if (Mesh) Mesh->Add_Ref();
  1485. }
  1486. void BptImpClass::Set_Node_Array(int numnodes, BptImpNodeClass * nodes)
  1487. {
  1488. if (Nodes) delete[] Nodes;
  1489. Nodes = nodes;
  1490. NodeCount = numnodes;
  1491. }
  1492. void BptImpClass::Set_Normal_Array(const UniqueArrayClass<Vector3> & normals)
  1493. {
  1494. if (normals.Count() != NormalCount) {
  1495. if (Normals) delete[] Normals;
  1496. Normals = new Vector3[normals.Count()];
  1497. }
  1498. NormalCount = normals.Count();
  1499. for (int i=0; i<NormalCount; i++) {
  1500. Normals[i] = normals.Get(i);
  1501. }
  1502. }
  1503. void BptImpClass::Set_Distance_Array(const UniqueArrayClass<float> & distances)
  1504. {
  1505. if (distances.Count() != DistanceCount) {
  1506. if (Distances) delete[] Distances;
  1507. Distances = new float[distances.Count()];
  1508. }
  1509. DistanceCount = distances.Count();
  1510. for (int i=0; i<DistanceCount; i++) {
  1511. Distances[i] = distances.Get(i);
  1512. }
  1513. }
  1514. void BptImpClass::Set_Poly_Index_Array(int numremaps,int * polyremaps)
  1515. {
  1516. if (PolyIndices) delete[] PolyIndices;
  1517. PolyIndices = polyremaps;
  1518. PolyIndexCount = numremaps;
  1519. }
  1520. void BptImpClass::Build_Apt(const CameraClass & camera)
  1521. {
  1522. WWDEBUG_PROFILE_START("BPT::Build_Apt");
  1523. Begin_Apt();
  1524. Build_Apt_Recursive(&(Nodes[0]),camera);
  1525. End_Apt();
  1526. WWDEBUG_PROFILE_STOP("BPT::Build_Apt");
  1527. }
  1528. void BptImpClass::Begin_Apt(void)
  1529. {
  1530. ActivePolyCount = 0;
  1531. ActivePolyTable = Mesh->Get_Surrender_Mesh()->getActivePolygonTable();
  1532. }
  1533. void BptImpClass::Add_Polys_To_Apt(BptImpNodeClass * node)
  1534. {
  1535. assert(node != NULL);
  1536. #if 0
  1537. memcpy(&(ActivePolyTable[ActivePolyCount]),&(PolyIndices[node->FirstPoly]),node->PolyCount);
  1538. ActivePolyCount += node->PolyCount;
  1539. #else
  1540. for (int poly_index=0; poly_index<node->PolyCount; poly_index++) {
  1541. ActivePolyTable[ActivePolyCount++] = PolyIndices[node->FirstPoly + poly_index];
  1542. }
  1543. #endif
  1544. }
  1545. void BptImpClass::End_Apt(void)
  1546. {
  1547. Mesh->Get_Surrender_Mesh()->setActivePolygonCount(ActivePolyCount);
  1548. // WWDEBUG_SAY(("Active Polys: %d\r\n",ActivePolyCount));
  1549. }
  1550. void BptImpClass::Build_Apt_Recursive(BptImpNodeClass * node,const CameraClass & cam)
  1551. {
  1552. /*
  1553. ** Check the camera's frustum against this node's
  1554. ** bounding volume
  1555. */
  1556. if (!node->Is_Visible(cam)) {
  1557. Verify_Node_Bounding_Volume(node,Vector3(node->MinX,node->MinY,node->MinZ),Vector3(node->MaxX,node->MaxY,node->MaxZ));
  1558. return;
  1559. }
  1560. /*
  1561. ** Ok part of this tree may be visible, compute
  1562. ** which side of the splitting plane the camera is on
  1563. */
  1564. float dist = Vector3::Dot_Product(Normals[node->NormalIndex],cam.Get_Position());
  1565. if (dist > Distances[node->DistanceIndex]) {
  1566. /*
  1567. ** FRONT:
  1568. ** We are in front of the plane so proceed in the following order:
  1569. ** Visit the 'Back' node
  1570. ** Add our polys to the APT
  1571. ** Visit the 'Front' node
  1572. */
  1573. if (node->Back) Build_Apt_Recursive(node->Back,cam);
  1574. Add_Polys_To_Apt(node);
  1575. if (node->Front) Build_Apt_Recursive(node->Front,cam);
  1576. } else {
  1577. /*
  1578. ** BACK:
  1579. ** We are in back of the plane so proceed in the following order:
  1580. ** Visit the 'Front' node
  1581. ** Add our polys to the APT
  1582. ** Visit the 'Back' node
  1583. */
  1584. if (node->Front) Build_Apt_Recursive(node->Front,cam);
  1585. Add_Polys_To_Apt(node);
  1586. if (node->Back) Build_Apt_Recursive(node->Back,cam);
  1587. }
  1588. }
  1589. bool BptImpClass::Cast_Ray(PhysRayCollisionTestClass & raytest) const
  1590. {
  1591. return Cast_Ray_Recursive(&(Nodes[0]),raytest);
  1592. }
  1593. bool BptImpClass::Cast_AABox(PhysAABoxCollisionTestClass & boxtest) const
  1594. {
  1595. /*
  1596. ** Test the sweeping AABox against the BPT recursively!
  1597. */
  1598. WWDEBUG_PROFILE_START("BPT::Cast_AABox");
  1599. bool res = Cast_AABox_Recursive(&(Nodes[0]),boxtest);
  1600. WWDEBUG_PROFILE_STOP("BPT::Cast_AABox");
  1601. return res;
  1602. }
  1603. bool BptImpClass::Cast_OBBox(PhysOBBoxCollisionTestClass & boxtest) const
  1604. {
  1605. return Cast_OBBox_Recursive(&(Nodes[0]),boxtest);
  1606. }
  1607. bool BptImpClass::Cast_Ray_Recursive
  1608. (
  1609. BptImpNodeClass * node,
  1610. PhysRayCollisionTestClass & raytest
  1611. ) const
  1612. {
  1613. return false;
  1614. }
  1615. bool BptImpClass::Cast_AABox_Recursive
  1616. (
  1617. BptImpNodeClass * node,
  1618. PhysAABoxCollisionTestClass & boxtest
  1619. ) const
  1620. {
  1621. /*
  1622. ** First, check the bounding box of the move against the bounding box
  1623. ** of this tree, if they don't intersect, bail out
  1624. */
  1625. if ((boxtest.SweepMin.X > node->MaxX) || (boxtest.SweepMax.X < node->MinX)) {
  1626. return false;
  1627. }
  1628. if ((boxtest.SweepMin.Y > node->MaxY) || (boxtest.SweepMax.Y < node->MinY)) {
  1629. return false;
  1630. }
  1631. if ((boxtest.SweepMin.Z > node->MaxZ) || (boxtest.SweepMax.Z < node->MinZ)) {
  1632. return false;
  1633. }
  1634. if (node->Front) {
  1635. Cast_AABox_Recursive(node->Front,boxtest);
  1636. }
  1637. Cast_AABox_To_Polys(node,boxtest);
  1638. if (node->Back) {
  1639. Cast_AABox_Recursive(node->Back,boxtest);
  1640. }
  1641. return false;
  1642. }
  1643. bool BptImpClass::Cast_OBBox_Recursive
  1644. (
  1645. BptImpNodeClass * node,
  1646. PhysOBBoxCollisionTestClass & boxtest
  1647. ) const
  1648. {
  1649. return false;
  1650. }
  1651. bool BptImpClass::Cast_AABox_To_Polys(BptImpNodeClass * node,PhysAABoxCollisionTestClass & boxtest) const
  1652. {
  1653. /*
  1654. ** Simply loop through the polys in this node, checking each for collision
  1655. */
  1656. TriClass tri;
  1657. srMeshModel * srmesh = Mesh->Get_Surrender_Mesh();
  1658. srVector3 * loc = srmesh->getVertexLoc();
  1659. srVector4 * norms = srmesh->getPolyEq();
  1660. srVector3i * polyverts = srmesh->getPolyVertex();
  1661. int polyhit = -1;
  1662. for (int poly_counter=0; poly_counter<node->PolyCount; poly_counter++) {
  1663. int poly_index = PolyIndices[node->FirstPoly + poly_counter];
  1664. tri.V[0] = As_Vector3(&(loc[ polyverts[poly_index][0] ]));
  1665. tri.V[1] = As_Vector3(&(loc[ polyverts[poly_index][1] ]));
  1666. tri.V[2] = As_Vector3(&(loc[ polyverts[poly_index][2] ]));
  1667. tri.N = (Vector3 *)&(norms[poly_index]);
  1668. if ( boxtest.Box.Cast_To_Tri(boxtest.Move,tri,boxtest.Result) ) {;
  1669. polyhit = poly_index;
  1670. }
  1671. if (boxtest.Result->StartBad) {
  1672. return true;
  1673. }
  1674. }
  1675. if (polyhit != -1) {
  1676. return true;
  1677. }
  1678. return false;
  1679. }
  1680. void BptImpClass::Verify_Node_Bounding_Volume(BptImpNodeClass * node,const Vector3 & min,const Vector3 & max) const
  1681. {
  1682. srMeshModel * srmesh = Mesh->Get_Surrender_Mesh();
  1683. srVector3 * loc = srmesh->getVertexLoc();
  1684. srVector3i * polyverts = srmesh->getPolyVertex();
  1685. Vector3 * v;
  1686. for (int remap_index = node->FirstPoly; remap_index < node->FirstPoly + node->PolyCount; remap_index++) {
  1687. int poly_index = PolyIndices[remap_index];
  1688. v = As_Vector3(&loc[ polyverts[poly_index][0] ]);
  1689. assert(v->X >= min.X);
  1690. assert(v->Y >= min.Y);
  1691. assert(v->Z >= min.Z);
  1692. assert(v->X <= max.X);
  1693. assert(v->Y <= max.Y);
  1694. assert(v->Z <= max.Z);
  1695. v = As_Vector3(&loc[ polyverts[poly_index][1] ]);
  1696. assert(v->X >= min.X);
  1697. assert(v->Y >= min.Y);
  1698. assert(v->Z >= min.Z);
  1699. assert(v->X <= max.X);
  1700. assert(v->Y <= max.Y);
  1701. assert(v->Z <= max.Z);
  1702. v = As_Vector3(&loc[ polyverts[poly_index][2] ]);
  1703. assert(v->X >= min.X);
  1704. assert(v->Y >= min.Y);
  1705. assert(v->Z >= min.Z);
  1706. assert(v->X <= max.X);
  1707. assert(v->Y <= max.Y);
  1708. assert(v->Z <= max.Z);
  1709. }
  1710. if (node->Back) {
  1711. Verify_Node_Bounding_Volume(node->Back,min,max);
  1712. }
  1713. if (node->Front) {
  1714. Verify_Node_Bounding_Volume(node->Front,min,max);
  1715. }
  1716. }
  1717. /**************************************************************
  1718. BptImpBuilderClass Implementation
  1719. **************************************************************/
  1720. BptImpBuilderClass::BptImpBuilderClass(void) :
  1721. MeshBuilder(true,10000,5000), // TODO: should move this to Build_Bpt_Imp so it is dynamically initialzed
  1722. UniqueNormals(NULL),
  1723. UniqueDistances(NULL),
  1724. NodeCount(0),
  1725. Nodes(NULL),
  1726. TriCount(0),
  1727. CurTriIndex(0),
  1728. TriIndexArray(NULL)
  1729. {
  1730. }
  1731. BptImpBuilderClass::~BptImpBuilderClass(void)
  1732. {
  1733. Free();
  1734. }
  1735. void BptImpBuilderClass::Free(void)
  1736. {
  1737. if (UniqueNormals != NULL) {
  1738. delete UniqueNormals;
  1739. UniqueNormals = NULL;
  1740. }
  1741. if (UniqueDistances != NULL) {
  1742. delete UniqueDistances;
  1743. UniqueDistances = NULL;
  1744. }
  1745. NodeCount = 0;
  1746. if (Nodes != NULL) {
  1747. delete[] Nodes;
  1748. Nodes = NULL;
  1749. }
  1750. TriCount = 0;
  1751. CurTriIndex = 0;
  1752. if (TriIndexArray != NULL) {
  1753. delete[] TriIndexArray;
  1754. TriIndexArray = NULL;
  1755. }
  1756. }
  1757. BptImpClass * BptImpBuilderClass::Build_Bpt_Imp(BptNodeClass * root,MaterialInfoClass * matinfo)
  1758. {
  1759. Free();
  1760. WWDEBUG_SAY(("Building the Run-Time Bpt\r\n"));
  1761. TriCount = root->Num_Tris();
  1762. /*
  1763. ** Allocate the UniqueNormals and UniqueDistances objects
  1764. */
  1765. int size = TriCount;
  1766. int growth = TriCount / 3;
  1767. if (growth < 5) growth = 5;
  1768. UniqueNormals = new UniqueArrayClass<Vector3>(size,growth,&NormalHasher);
  1769. UniqueDistances = new UniqueArrayClass<float>(size,growth,&DistanceHasher);
  1770. /*
  1771. ** Set up the mesh builder
  1772. */
  1773. MeshBuilder.Reset(true,TriCount,growth);
  1774. MeshBuilder.Disable_All_Vertex_Channels();
  1775. MeshBuilder.Enable_Vertex_Channel(MeshBuilderClass::VERTEX_CHANNEL_NORMAL);
  1776. // MeshBuilder.Enable_Vertex_Channel(MeshBuilderClass::VERTEX_CHANNEL_COLOR);
  1777. MeshBuilder.Enable_Vertex_Channel(MeshBuilderClass::VERTEX_CHANNEL_TEXCOORD);
  1778. /*
  1779. ** Allocate the array of triangle indices, set
  1780. ** CurTriIndex to point to the top.
  1781. */
  1782. TriIndexArray = new int[TriCount];
  1783. CurTriIndex = 0;
  1784. /*
  1785. ** Allocate the array of nodes
  1786. */
  1787. NodeCount = root->Num_Nodes();
  1788. Nodes = new BptImpNodeClass[NodeCount];
  1789. /*
  1790. ** Compute the hierarchical bounding boxes
  1791. */
  1792. WWDEBUG_SAY(("Computing Hierarchical Bounding Volumes.\r\n"));
  1793. root->Compute_Bounding_Box();
  1794. WWDEBUG_SAY(("Hierarchical Bounding Volumes Done.\r\n"));
  1795. /*
  1796. ** Have the tree "unwind" itself into our arrays
  1797. */
  1798. root->Assign_Array_Indices(0);
  1799. root->Submit_Nodes(*this);
  1800. /*
  1801. ** Process the mesh
  1802. */
  1803. MeshBuilder.Build_Mesh(true);
  1804. /*
  1805. ** Remap all of the polygon indices (account for the
  1806. ** mesh builder re-ording polygons)
  1807. */
  1808. Remap_Triangle_Indices();
  1809. /*
  1810. ** Create the BptImpClass
  1811. */
  1812. MeshClass * mesh = new MeshClass();
  1813. mesh->Init(MeshBuilder,matinfo,"BspMesh","");
  1814. BptImpClass * bptimp = new BptImpClass();
  1815. bptimp->Set_Mesh(mesh);
  1816. bptimp->Set_Node_Array(NodeCount,Nodes);
  1817. bptimp->Set_Poly_Index_Array(TriCount,TriIndexArray);
  1818. bptimp->Set_Normal_Array(*UniqueNormals);
  1819. bptimp->Set_Distance_Array(*UniqueDistances);
  1820. // the "imp" assumed ownership of this stuff
  1821. mesh->Release_Ref();
  1822. mesh = NULL;
  1823. Nodes = NULL;
  1824. TriIndexArray = NULL;
  1825. Free();
  1826. WWDEBUG_SAY(("Run-Time Bpt Done\r\n"));
  1827. WWDEBUG_SAY(("\r\n"));
  1828. return bptimp;
  1829. }
  1830. void BptImpBuilderClass::Add_Bpt_Node(const BptNodeClass * node)
  1831. {
  1832. BptImpNodeClass newnode;
  1833. /*
  1834. ** initialize the front pointer
  1835. */
  1836. if (node->Front) {
  1837. assert(node->Front->ArrayIndex >= 0);
  1838. assert(node->Front->ArrayIndex < NodeCount);
  1839. newnode.Front = &(Nodes[node->Front->ArrayIndex]);
  1840. } else {
  1841. newnode.Front = NULL; //BptImpNodeClass::NULL_NODE_INDEX;
  1842. }
  1843. /*
  1844. ** initialize the back pointer
  1845. */
  1846. if (node->Back) {
  1847. assert(node->Back->ArrayIndex >= 0);
  1848. assert(node->Back->ArrayIndex < NodeCount);
  1849. newnode.Back = &(Nodes[node->Back->ArrayIndex]);
  1850. } else {
  1851. newnode.Back = NULL; //BptImpNodeClass::NULL_NODE_INDEX;
  1852. }
  1853. /*
  1854. ** Triangulate each poly and submit it to the mesh builder
  1855. ** install the Triangle Remap Indices as we go
  1856. */
  1857. newnode.FirstPoly = CurTriIndex;
  1858. newnode.PolyCount = 0;
  1859. MeshBuilderClass::FaceClass face;
  1860. for (unsigned int fi=0; fi<node->NumPolys; fi++) {
  1861. BptPolyClass * poly = &(node->Polys[fi]);
  1862. for (int ti = 2;ti < poly->NumVerts; ti++) {
  1863. face.MaterialIdx = poly->MaterialId;
  1864. face.SmGroup = 1; //TODO: get the correct smooth group???
  1865. face.Index = 0; //TODO: do we have an actual index?
  1866. face.Attributes = 0;
  1867. face.Verts[0].Position = poly->Verts[0].Position;
  1868. face.Verts[0].TexCoord = poly->Verts[0].TexCoord;
  1869. face.Verts[0].Color = poly->Verts[0].Color;
  1870. face.Verts[1].Position = poly->Verts[ti-1].Position;
  1871. face.Verts[1].TexCoord = poly->Verts[ti-1].TexCoord;
  1872. face.Verts[1].Color = poly->Verts[ti-1].Color;
  1873. face.Verts[2].Position = poly->Verts[ti].Position;
  1874. face.Verts[2].TexCoord = poly->Verts[ti].TexCoord;
  1875. face.Verts[2].Color = poly->Verts[ti].Color;
  1876. TriIndexArray[CurTriIndex] = MeshBuilder.Add_Face(face);
  1877. CurTriIndex++;
  1878. newnode.PolyCount++;
  1879. /*
  1880. ** just verifying that all verts are inside the bounding box
  1881. */
  1882. assert(face.Verts[0].Position.X >= node->Min.X);
  1883. assert(face.Verts[0].Position.Y >= node->Min.Y);
  1884. assert(face.Verts[0].Position.Z >= node->Min.Z);
  1885. assert(face.Verts[1].Position.X >= node->Min.X);
  1886. assert(face.Verts[1].Position.Y >= node->Min.Y);
  1887. assert(face.Verts[1].Position.Z >= node->Min.Z);
  1888. assert(face.Verts[2].Position.X >= node->Min.X);
  1889. assert(face.Verts[2].Position.Y >= node->Min.Y);
  1890. assert(face.Verts[2].Position.Z >= node->Min.Z);
  1891. assert(face.Verts[0].Position.X <= node->Max.X);
  1892. assert(face.Verts[0].Position.Y <= node->Max.Y);
  1893. assert(face.Verts[0].Position.Z <= node->Max.Z);
  1894. assert(face.Verts[1].Position.X <= node->Max.X);
  1895. assert(face.Verts[1].Position.Y <= node->Max.Y);
  1896. assert(face.Verts[1].Position.Z <= node->Max.Z);
  1897. assert(face.Verts[2].Position.X <= node->Max.X);
  1898. assert(face.Verts[2].Position.Y <= node->Max.Y);
  1899. assert(face.Verts[2].Position.Z <= node->Max.Z);
  1900. }
  1901. }
  1902. /*
  1903. ** Bounding box
  1904. */
  1905. newnode.MinX = node->Min.X;
  1906. newnode.MinY = node->Min.Y;
  1907. newnode.MinZ = node->Min.Z;
  1908. newnode.MaxX = node->Max.X;
  1909. newnode.MaxY = node->Max.Y;
  1910. newnode.MaxZ = node->Max.Z;
  1911. assert(newnode.MinX <= newnode.MaxX);
  1912. assert(newnode.MinY <= newnode.MaxY);
  1913. assert(newnode.MinZ <= newnode.MaxZ);
  1914. /*
  1915. ** Plane Equation
  1916. */
  1917. assert(UniqueNormals);
  1918. assert(UniqueDistances);
  1919. newnode.NormalIndex = UniqueNormals->Add(node->Plane.N);
  1920. newnode.DistanceIndex = UniqueDistances->Add(node->Plane.D);
  1921. /*
  1922. ** install the node!
  1923. */
  1924. Nodes[node->ArrayIndex] = newnode;
  1925. }
  1926. void BptImpBuilderClass::Remap_Triangle_Indices(void)
  1927. {
  1928. int pi;
  1929. int * index_remap = new int[MeshBuilder.Get_Face_Count()];
  1930. assert(MeshBuilder.Get_Face_Count() == TriCount);
  1931. for (pi=0; pi < MeshBuilder.Get_Face_Count(); pi++) {
  1932. const MeshBuilderClass::FaceClass & face = MeshBuilder.Get_Face(pi);
  1933. assert(face.AddIndex >= 0);
  1934. assert(face.AddIndex < TriCount);
  1935. index_remap[ face.AddIndex ] = pi;
  1936. }
  1937. for (pi=0; pi < TriCount; pi++) {
  1938. TriIndexArray[pi] = index_remap[TriIndexArray[pi]];
  1939. }
  1940. delete[] index_remap;
  1941. }
  1942. #endif // PORT140
  1943. #endif // OBSOLETE!