pointgr.cpp 81 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917
  1. /*
  2. ** Command & Conquer Generals(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 : G *
  23. * *
  24. * $Archive:: /VSS_Sync/ww3d2/pointgr.cpp $*
  25. * *
  26. * $Author:: Vss_sync $*
  27. * *
  28. * $Modtime:: 8/29/01 7:29p $*
  29. * *
  30. * $Revision:: 37 $*
  31. * *
  32. *-------------------------------------------------------------------------*
  33. * Functions: *
  34. * PointGroupClass::PointGroupClass -- PointGroupClass CTor. *
  35. * PointGroupClass::~PointGroupClass -- PointGroupClass DTor. *
  36. * PointGroupClass::operator = -- PointGroupClass assignment operator. *
  37. * PointGroupClass::Set_Arrays -- Set point location/color/enable arrays.*
  38. * PointGroupClass::Set_Point_Size -- Set default point size. *
  39. * PointGroupClass::Get_Point_Size -- Get default point size. *
  40. * PointGroupClass::Set_Point_Color -- Set default point color. *
  41. * PointGroupClass::Get_Point_Color -- Get default point color. *
  42. * PointGroupClass::Set_Point_Alpha -- Set default point alpha. *
  43. * PointGroupClass::Get_Point_Alpha -- Get default point alpha. *
  44. * PointGroupClass::Set_Point_Orientation -- Set default point orientatio*
  45. * PointGroupClass::Get_Point_Orientation -- Get default point orientatio*
  46. * PointGroupClass::Set_Point_Frame -- Set default point frame. *
  47. * PointGroupClass::Get_Point_Frame -- Get default point frame. *
  48. * PointGroupClass::Set_Point_Mode -- Set point rendering method. *
  49. * PointGroupClass::Get_Point_Mode -- Get point rendering method. *
  50. * PointGroupClass::Set_Flag -- Set given flag to on or off. *
  51. * PointGroupClass::Get_Flag -- Get current value (on/off) of given flag.*
  52. * PointGroupClass::Set_Texture -- Set texture used. *
  53. * PointGroupClass::Get_Texture -- Get texture used. *
  54. * PointGroupClass::Set_Shader -- Set shader used. *
  55. * PointGroupClass::Get_Shader -- Get shader used. *
  56. * PointGroupClass::Set_Billboard -- Set whether to billboard. *
  57. * PointGroupClass::Get_Billboard -- Get whether to billboard. *
  58. * PointGroupClass::Get_Discrete_Orientation_Count_Log2 -- what it says *
  59. * PointGroupClass::Set_Discrete_Orientation_Count_Log2 -- what it says. *
  60. * PointGroupClass::Get_Frame_Row_Column_Count_Log2 -- what it says *
  61. * PointGroupClass::Set_Frame_Row_Column_Count_Log2 -- what it says. *
  62. * PointGroupClass::Get_Polygon_Count -- Get estimated polygon count. *
  63. * PointGroupClass::Render -- draw point group. *
  64. * PointGroupClass::vInstance -- Create instance of class. *
  65. * PointGroupClass::sGetClassName -- Get name of class. *
  66. * PointGroupClass::Update_Arrays -- Update all arrays used in rendering *
  67. * PointGroupClass::Peek_Texture -- Peeks texture *
  68. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  69. #include "pointgr.h"
  70. #include "vertmaterial.h"
  71. #include "ww3d.h"
  72. #include "aabox.h"
  73. #include "statistics.h"
  74. #include "simplevec.h"
  75. #include "texture.h"
  76. #include "vector.h"
  77. #include "vp.h"
  78. #include "matrix4.h"
  79. #include "dx8wrapper.h"
  80. #include "dx8vertexbuffer.h"
  81. #include "dx8indexbuffer.h"
  82. #include "rinfo.h"
  83. #include "camera.h"
  84. #include "dx8fvf.h"
  85. #include "D3DXMath.h"
  86. #include "sortingrenderer.h"
  87. // Upgraded to DX8 2/2/01 HY
  88. // static data members
  89. Vector3 PointGroupClass::_TriVertexLocationOrientationTable[256][3];
  90. Vector3 PointGroupClass::_QuadVertexLocationOrientationTable[256][4];
  91. Vector2 *PointGroupClass::_TriVertexUVFrameTable[5] = { NULL, NULL, NULL, NULL, NULL};
  92. Vector2 *PointGroupClass::_QuadVertexUVFrameTable[5] = { NULL, NULL, NULL, NULL, NULL};
  93. VertexMaterialClass *PointGroupClass::PointMaterial=NULL;
  94. // Static arrays for intermediate calcs (never resized down, just up):
  95. VectorClass<Vector3> PointGroupClass::compressed_loc; // point locations 'compressed' by APT
  96. VectorClass<Vector4> PointGroupClass::compressed_diffuse; // point colors 'compressed' by APT
  97. VectorClass<float> PointGroupClass::compressed_size; // point sizes 'compressed' by APT
  98. VectorClass<unsigned char> PointGroupClass::compressed_orient; // point orientations 'compressed' by APT
  99. VectorClass<unsigned char> PointGroupClass::compressed_frame; // point frames 'compressed' by APT
  100. VectorClass<Vector3> PointGroupClass::transformed_loc; // transformed point locations
  101. // This array has vertex locations for screenspace mode - calculated to cover exactly 1x1 and 2x2 pixels.
  102. Vector3 PointGroupClass::_ScreenspaceVertexLocationSizeTable[2][3] =
  103. {
  104. Vector3(0.5f, 0.0f, -1.0f),
  105. Vector3(1.0f, 1.0f, -1.0f),
  106. Vector3(0.0f, 1.0f, -1.0f),
  107. Vector3(1.0f, -0.5f, -1.0f),
  108. Vector3(2.7f, 2.0f, -1.0f),
  109. Vector3(-0.7f, 2.0f, -1.0f)
  110. };
  111. // useful for particles that aren't aligned with the screen.
  112. static Vector3 GroundMultiplierX(1.0f, 0.0f, 0.0f);
  113. static Vector3 GroundMultiplierY(0.0f, 1.0f, 0.0f);
  114. // Some internal variables
  115. VectorClass<Vector3> VertexLoc; // camera-space vertex locations
  116. VectorClass<Vector4> VertexDiffuse; // vertex diffuse/alpha colors
  117. VectorClass<Vector2> VertexUV; // vertex texture coords
  118. // Some DX 8 variables
  119. #define MAX_VB_SIZE 2048
  120. #define MAX_TRI_POINTS MAX_VB_SIZE/3
  121. #define MAX_TRI_IB_SIZE 3*MAX_TRI_POINTS
  122. #define MAX_QUAD_POINTS MAX_VB_SIZE/4
  123. #define MAX_QUAD_IB_SIZE 6*MAX_QUAD_POINTS
  124. DX8IndexBufferClass *Tris, *Quads; // Index buffers.
  125. SortingIndexBufferClass *SortingTris, *SortingQuads; // Sorting index buffers.
  126. /**************************************************************************
  127. * PointGroupClass::PointGroupClass -- PointGroupClass CTor. *
  128. * *
  129. * INPUT: *
  130. * *
  131. * OUTPUT: *
  132. * *
  133. * WARNINGS: *
  134. * *
  135. * HISTORY: *
  136. * 11/17/1998 NH : Created. *
  137. *========================================================================*/
  138. PointGroupClass::PointGroupClass(void) :
  139. PointLoc(NULL),
  140. PointDiffuse(NULL),
  141. APT(NULL),
  142. PointSize(NULL),
  143. PointOrientation(NULL),
  144. PointFrame(NULL),
  145. PointCount(0),
  146. FrameRowColumnCountLog2(0),
  147. Texture(NULL),
  148. Flags(0),
  149. Shader(ShaderClass::_PresetAdditiveSpriteShader),
  150. PointMode(TRIS),
  151. DefaultPointSize(0.0f),
  152. DefaultPointColor(1.0f, 1.0f, 1.0f),
  153. DefaultPointAlpha(1.0f),
  154. DefaultPointOrientation(0),
  155. DefaultPointFrame(0),
  156. VPXMin(0.0f),
  157. VPYMin(0.0f),
  158. VPXMax(0.0f),
  159. VPYMax(0.0f)
  160. {
  161. }
  162. /**************************************************************************
  163. * PointGroupClass::~PointGroupClass -- PointGroupClass DTor. *
  164. * *
  165. * INPUT: *
  166. * *
  167. * OUTPUT: *
  168. * *
  169. * WARNINGS: *
  170. * *
  171. * HISTORY: *
  172. * 11/17/1998 NH : Created. *
  173. *========================================================================*/
  174. PointGroupClass::~PointGroupClass(void)
  175. {
  176. if (PointLoc) {
  177. PointLoc->Release_Ref();
  178. PointLoc = NULL;
  179. }
  180. if (PointDiffuse) {
  181. PointDiffuse->Release_Ref();
  182. PointDiffuse=NULL;
  183. }
  184. if (APT) {
  185. APT->Release_Ref();
  186. APT = NULL;
  187. }
  188. if (PointSize) {
  189. PointSize->Release_Ref();
  190. PointSize = NULL;
  191. }
  192. if (PointOrientation) {
  193. PointOrientation->Release_Ref();
  194. PointOrientation = NULL;
  195. }
  196. if (PointFrame) {
  197. PointFrame->Release_Ref();
  198. PointFrame = NULL;
  199. }
  200. if (Texture) {
  201. REF_PTR_RELEASE(Texture);
  202. Texture = NULL;
  203. }
  204. }
  205. /**************************************************************************
  206. * PointGroupClass::operator = -- PointGroupClass assignment operator. *
  207. * *
  208. * INPUT: *
  209. * *
  210. * OUTPUT: *
  211. * *
  212. * WARNINGS: *
  213. * *
  214. * HISTORY: *
  215. * 11/17/1998 NH : Created. *
  216. *========================================================================*/
  217. PointGroupClass & PointGroupClass::operator = (const PointGroupClass & that)
  218. {
  219. if (this != &that) {
  220. WWASSERT(0); // If you hit this assert implement the function!
  221. }
  222. return *this;
  223. }
  224. /**************************************************************************
  225. * PointGroupClass::Set_Arrays -- Set point location/color/enable arrays. *
  226. * *
  227. * INPUT: *
  228. * *
  229. * OUTPUT: *
  230. * *
  231. * WARNINGS: *
  232. * *
  233. * NOTES: colors, alphas, APT, sizes, orientations and frames are *
  234. * optional. active_point_count can also be used with a NULL apt.*
  235. * In this case active_point_count is ignored if it is -1 *
  236. * (default value) and otherwise it indicates the first N active *
  237. * points in the arrays. *
  238. * The view plane rectangle may optionally be passed as well - *
  239. * this is only used in SCREENSPACE mode. *
  240. * *
  241. * HISTORY: *
  242. * 11/17/1998 NH : Created. *
  243. * 08/25/1999 NH : Alphas added. *
  244. * 06/28/2000 NH : Orientations and frames added. *
  245. * 02/08/2001 HY : Upgraded to DX8 *
  246. *========================================================================*/
  247. void PointGroupClass::Set_Arrays(
  248. ShareBufferClass<Vector3> *locs,
  249. ShareBufferClass<Vector4> *diffuse,
  250. ShareBufferClass<unsigned int> *apt,
  251. ShareBufferClass<float> *sizes,
  252. ShareBufferClass<unsigned char> *orientations,
  253. ShareBufferClass<unsigned char> *frames,
  254. unsigned int active_point_count,
  255. float vpxmin,
  256. float vpymin,
  257. float vpxmax,
  258. float vpymax)
  259. {
  260. // The point locations array is NOT optional!
  261. WWASSERT(locs);
  262. // Ensure lengths of all arrays are the same:
  263. WWASSERT(!diffuse || locs->Get_Count() == diffuse->Get_Count());
  264. WWASSERT(!apt || locs->Get_Count() == apt->Get_Count());
  265. WWASSERT(!sizes || locs->Get_Count() == sizes->Get_Count());
  266. WWASSERT(!orientations || locs->Get_Count() == orientations->Get_Count());
  267. WWASSERT(!frames || locs->Get_Count() == frames->Get_Count());
  268. REF_PTR_SET(PointLoc,locs);
  269. REF_PTR_SET(PointDiffuse,diffuse);
  270. REF_PTR_SET(APT,apt);
  271. REF_PTR_SET(PointSize,sizes);
  272. REF_PTR_SET(PointOrientation,orientations);
  273. REF_PTR_SET(PointFrame,frames);
  274. if (APT) {
  275. PointCount = active_point_count;
  276. } else {
  277. PointCount = (active_point_count >= 0) ? active_point_count : PointLoc->Get_Count();
  278. }
  279. // Store view plane rectangle (only used in SCREENSPACE mode)
  280. VPXMin = vpxmin;
  281. VPYMin = vpymin;
  282. VPXMax = vpxmax;
  283. VPYMax = vpymax;
  284. }
  285. /**************************************************************************
  286. * PointGroupClass::Set_Point_Size -- Set default point size. *
  287. * *
  288. * INPUT: *
  289. * *
  290. * OUTPUT: *
  291. * *
  292. * WARNINGS: This size is ignored if a size array is present. *
  293. * *
  294. * HISTORY: *
  295. * 11/17/1998 NH : Created. *
  296. *========================================================================*/
  297. void PointGroupClass::Set_Point_Size(float size)
  298. {
  299. DefaultPointSize = size;
  300. }
  301. /**************************************************************************
  302. * PointGroupClass::Get_Point_Size -- Get default point size. *
  303. * *
  304. * INPUT: *
  305. * *
  306. * OUTPUT: *
  307. * *
  308. * WARNINGS: This size is ignored if a size array is present. *
  309. * *
  310. * HISTORY: *
  311. * 11/17/1998 NH : Created. *
  312. *========================================================================*/
  313. float PointGroupClass::Get_Point_Size(void)
  314. {
  315. return DefaultPointSize;
  316. }
  317. /**************************************************************************
  318. * PointGroupClass::Set_Point_Color -- Set default point color. *
  319. * *
  320. * INPUT: *
  321. * *
  322. * OUTPUT: *
  323. * *
  324. * WARNINGS: This color is ignored if a color array is present. *
  325. * *
  326. * HISTORY: *
  327. * 04/20/1999 NH : Created. *
  328. *========================================================================*/
  329. void PointGroupClass::Set_Point_Color(Vector3 color)
  330. {
  331. DefaultPointColor = color;
  332. }
  333. /**************************************************************************
  334. * PointGroupClass::Get_Point_Color -- Get default point color. *
  335. * *
  336. * INPUT: *
  337. * *
  338. * OUTPUT: *
  339. * *
  340. * WARNINGS: This color is ignored if a color array is present. *
  341. * *
  342. * HISTORY: *
  343. * 04/20/1999 NH : Created. *
  344. *========================================================================*/
  345. Vector3 PointGroupClass::Get_Point_Color(void)
  346. {
  347. return DefaultPointColor;
  348. }
  349. /**************************************************************************
  350. * PointGroupClass::Set_Point_Alpha -- Set default point alpha. *
  351. * *
  352. * INPUT: *
  353. * *
  354. * OUTPUT: *
  355. * *
  356. * WARNINGS: This alpha is ignored if an alpha array is present. *
  357. * *
  358. * HISTORY: *
  359. * 08/25/1999 NH : Created. *
  360. *========================================================================*/
  361. void PointGroupClass::Set_Point_Alpha(float alpha)
  362. {
  363. DefaultPointAlpha = alpha;
  364. }
  365. /**************************************************************************
  366. * PointGroupClass::Get_Point_Alpha -- Get default point alpha. *
  367. * *
  368. * INPUT: *
  369. * *
  370. * OUTPUT: *
  371. * *
  372. * WARNINGS: This alpha is ignored if an alpha array is present. *
  373. * *
  374. * HISTORY: *
  375. * 08/25/1999 NH : Created. *
  376. *========================================================================*/
  377. float PointGroupClass::Get_Point_Alpha(void)
  378. {
  379. return DefaultPointAlpha;
  380. }
  381. /**************************************************************************
  382. * PointGroupClass::Set_Point_Orientation -- Set default point orientation*
  383. * *
  384. * INPUT: *
  385. * *
  386. * OUTPUT: *
  387. * *
  388. * WARNINGS: This is ignored if an orientation array is present. *
  389. * *
  390. * NOTE: No need to ensure value in valid range - it will be masked later.*
  391. * *
  392. * HISTORY: *
  393. * 06/28/2000 NH : Created. *
  394. *========================================================================*/
  395. void PointGroupClass::Set_Point_Orientation(unsigned char orientation)
  396. {
  397. DefaultPointOrientation = orientation;
  398. }
  399. /**************************************************************************
  400. * PointGroupClass::Get_Point_Orientation -- Get default point orientation*
  401. * *
  402. * INPUT: *
  403. * *
  404. * OUTPUT: *
  405. * *
  406. * WARNINGS: This is ignored if an orientation array is present. *
  407. * *
  408. * HISTORY: *
  409. * 06/28/2000 NH : Created. *
  410. *========================================================================*/
  411. unsigned char PointGroupClass::Get_Point_Orientation(void)
  412. {
  413. return DefaultPointOrientation;
  414. }
  415. /**************************************************************************
  416. * PointGroupClass::Set_Point_Frame -- Set default point frame. *
  417. * *
  418. * INPUT: *
  419. * *
  420. * OUTPUT: *
  421. * *
  422. * WARNINGS: This frame is ignored if an frame array is present. *
  423. * *
  424. * NOTE: No need to ensure value in valid range - it will be masked later.*
  425. * *
  426. * HISTORY: *
  427. * 06/28/2000 NH : Created. *
  428. *========================================================================*/
  429. void PointGroupClass::Set_Point_Frame(unsigned char frame)
  430. {
  431. DefaultPointFrame = frame;
  432. }
  433. /**************************************************************************
  434. * PointGroupClass::Get_Point_Frame -- Get default point frame. *
  435. * *
  436. * INPUT: *
  437. * *
  438. * OUTPUT: *
  439. * *
  440. * WARNINGS: This frame is ignored if an frame array is present. *
  441. * *
  442. * HISTORY: *
  443. * 06/28/2000 NH : Created. *
  444. *========================================================================*/
  445. unsigned char PointGroupClass::Get_Point_Frame(void)
  446. {
  447. return DefaultPointFrame;
  448. }
  449. /**************************************************************************
  450. * PointGroupClass::Set_Point_Mode -- Set point rendering method. *
  451. * *
  452. * INPUT: *
  453. * *
  454. * OUTPUT: *
  455. * *
  456. * WARNINGS: *
  457. * *
  458. * HISTORY: *
  459. * 11/17/1998 NH : Created. *
  460. *========================================================================*/
  461. void PointGroupClass::Set_Point_Mode(PointModeEnum mode)
  462. {
  463. PointMode = mode;
  464. }
  465. /**************************************************************************
  466. * PointGroupClass::Get_Point_Mode -- Get point rendering method. *
  467. * *
  468. * INPUT: *
  469. * *
  470. * OUTPUT: *
  471. * *
  472. * WARNINGS: *
  473. * *
  474. * HISTORY: *
  475. * 11/17/1998 NH : Created. *
  476. *========================================================================*/
  477. PointGroupClass::PointModeEnum PointGroupClass::Get_Point_Mode(void)
  478. {
  479. return PointMode;
  480. }
  481. /**************************************************************************
  482. * Set_Flag -- PointGroupClass::Set given flag to on or off. *
  483. * *
  484. * INPUT: *
  485. * *
  486. * OUTPUT: *
  487. * *
  488. * WARNINGS: *
  489. * *
  490. * HISTORY: *
  491. * 11/17/1998 NH : Created. *
  492. *========================================================================*/
  493. void PointGroupClass::Set_Flag(FlagsType flag, bool onoff)
  494. {
  495. if (onoff) Flags|=1<<flag;
  496. else
  497. Flags&=~(1<<flag);
  498. }
  499. /**************************************************************************
  500. * PointGroupClass::Get_Flag -- Get current value (on/off) of given flag. *
  501. * *
  502. * INPUT: *
  503. * *
  504. * OUTPUT: *
  505. * *
  506. * WARNINGS: *
  507. * *
  508. * HISTORY: *
  509. * 11/17/1998 NH : Created. *
  510. *========================================================================*/
  511. int PointGroupClass::Get_Flag(FlagsType flag)
  512. {
  513. return (Flags>>flag) & 0x1;
  514. }
  515. /**************************************************************************
  516. * PointGroupClass::Set_Texture -- Set texture used. *
  517. * *
  518. * INPUT: *
  519. * *
  520. * OUTPUT: *
  521. * *
  522. * WARNINGS: *
  523. * *
  524. * HISTORY: *
  525. * 11/17/1998 NH : Created. *
  526. * 02/08/2001 HY : Upgraded to DX8 *
  527. *========================================================================*/
  528. void PointGroupClass::Set_Texture(TextureClass* texture)
  529. {
  530. REF_PTR_SET(Texture,texture);
  531. }
  532. /**************************************************************************
  533. * PointGroupClass::Get_Texture -- Get texture used. *
  534. * *
  535. * INPUT: *
  536. * *
  537. * OUTPUT: *
  538. * *
  539. * WARNINGS: *
  540. * *
  541. * HISTORY: *
  542. * 11/17/1998 NH : Created. *
  543. * 02/08/2001 HY : Upgraded to DX8 *
  544. *========================================================================*/
  545. TextureClass * PointGroupClass::Get_Texture(void)
  546. {
  547. if (Texture) Texture->Add_Ref();
  548. return Texture;
  549. }
  550. /***********************************************************************************************
  551. * PointGroupClass::Peek_Texture -- Peeks texture *
  552. * *
  553. * *
  554. * *
  555. * *
  556. * INPUT: *
  557. * *
  558. * OUTPUT: *
  559. * *
  560. * WARNINGS: *
  561. * *
  562. * HISTORY: *
  563. * 4/12/2001 hy : Created. *
  564. *=============================================================================================*/
  565. TextureClass * PointGroupClass::Peek_Texture(void)
  566. {
  567. return Texture;
  568. }
  569. /**************************************************************************
  570. * PointGroupClass::Set_Shader -- Set shader used. *
  571. * *
  572. * INPUT: *
  573. * *
  574. * OUTPUT: *
  575. * *
  576. * WARNINGS: the primary gradient will be set to MODULATE/DISABLE in *
  577. * the shader depending on whether a color or alpha array was *
  578. * passed in Set_Point_Arrays. also, texturing will be *
  579. * enabled or disabled dependent on whether a non-NULL *
  580. * texture was set. *
  581. * these will override the primary gradient/texturing *
  582. * settings in the given shader. *
  583. * *
  584. * HISTORY: *
  585. * 11/17/1998 NH : Created. *
  586. * 02/08/2001 HY : Upgraded to DX8 *
  587. *========================================================================*/
  588. void PointGroupClass::Set_Shader(ShaderClass shader)
  589. {
  590. Shader = shader;
  591. }
  592. /**************************************************************************
  593. * PointGroupClass::Get_Shader -- Get shader used. *
  594. * *
  595. * INPUT: *
  596. * *
  597. * OUTPUT: *
  598. * *
  599. * WARNINGS: *
  600. * *
  601. * HISTORY: *
  602. * 11/17/1998 NH : Created. *
  603. * 02/08/2001 HY : Upgraded to DX8 *
  604. *========================================================================*/
  605. ShaderClass PointGroupClass::Get_Shader(void)
  606. {
  607. return Shader;
  608. }
  609. /**************************************************************************
  610. * PointGroupClass::Set_Billboard -- Set whether to Billboard. *
  611. * *
  612. * INPUT: *
  613. * *
  614. * OUTPUT: *
  615. * *
  616. * WARNINGS: *
  617. * *
  618. * HISTORY: *
  619. * 04/25/2002 JM : Created. *
  620. *========================================================================*/
  621. void PointGroupClass::Set_Billboard(bool shouldBillboard)
  622. {
  623. Billboard = shouldBillboard;
  624. }
  625. /**************************************************************************
  626. * PointGroupClass::Get_Billboard -- Get whether to Billboard. *
  627. * *
  628. * INPUT: *
  629. * *
  630. * OUTPUT: *
  631. * *
  632. * WARNINGS: *
  633. * *
  634. * HISTORY: *
  635. * 04/25/2002 JM : Created. *
  636. *========================================================================*/
  637. bool PointGroupClass::Get_Billboard(void)
  638. {
  639. return Billboard;
  640. }
  641. /**************************************************************************
  642. * PointGroupClass::Get_Frame_Row_Column_Count_Log2 -- what it says *
  643. * *
  644. * INPUT: *
  645. * *
  646. * OUTPUT: *
  647. * *
  648. * WARNINGS: *
  649. * *
  650. * HISTORY: *
  651. * 06/28/2000 NH : Created. *
  652. * 02/08/2001 HY : Upgraded to DX8 *
  653. *========================================================================*/
  654. unsigned char PointGroupClass::Get_Frame_Row_Column_Count_Log2(void)
  655. {
  656. return FrameRowColumnCountLog2;
  657. }
  658. /**************************************************************************
  659. * PointGroupClass::Set_Frame_Row_Column_Count_Log2 -- what it says. *
  660. * *
  661. * INPUT: *
  662. * *
  663. * OUTPUT: *
  664. * *
  665. * WARNINGS: *
  666. * *
  667. * HISTORY: *
  668. * 06/28/2000 NH : Created. *
  669. * 02/08/2001 HY : Upgraded to DX8 *
  670. *========================================================================*/
  671. void PointGroupClass::Set_Frame_Row_Column_Count_Log2(unsigned char frccl2)
  672. {
  673. FrameRowColumnCountLog2 = MIN(frccl2, 4);
  674. }
  675. /**************************************************************************
  676. * PointGroupClass::Get_Polygon_Count -- Get estimated polygon count. *
  677. * *
  678. * INPUT: *
  679. * *
  680. * OUTPUT: *
  681. * *
  682. * WARNINGS: *
  683. * *
  684. * HISTORY: *
  685. * 11/18/1998 NH : Created. *
  686. * 02/08/2001 HY : Upgraded to DX8 *
  687. *========================================================================*/
  688. int PointGroupClass::Get_Polygon_Count(void)
  689. {
  690. switch (PointMode) {
  691. case TRIS:
  692. case SCREENSPACE:
  693. return PointCount;
  694. break;
  695. case QUADS:
  696. return PointCount * 2;
  697. break;
  698. }
  699. WWASSERT(0);
  700. return 0;
  701. }
  702. /**************************************************************************
  703. * PointGroupClass::Render -- draw point group. *
  704. * *
  705. * INPUT: *
  706. * *
  707. * OUTPUT: *
  708. * *
  709. * WARNINGS: *
  710. * *
  711. * HISTORY: *
  712. * 12/10/1998 NH : Created. *
  713. * 02/08/2001 HY : Upgraded to DX8 *
  714. *========================================================================*/
  715. static SimpleVecClass<unsigned long> remap;
  716. void PointGroupClass::Render(RenderInfoClass &rinfo)
  717. {
  718. /// @todo lorenzen asks: is particle culling in the shader perhaps faster than in DoParticles? Fix winding and find out...
  719. // NB: the winding for pointgroups is wrong, but we
  720. // are disabling culling for particles anyway
  721. Shader.Set_Cull_Mode(ShaderClass::CULL_MODE_DISABLE);
  722. // If no points, do nothing:
  723. if (PointCount == 0) return;
  724. WWASSERT(PointLoc && PointLoc->Get_Array());
  725. // Process texture reductions:
  726. // if (Texture) Texture->Process_Reduction();
  727. // Pointers which point into existing buffers (member or static):
  728. Vector3 *current_loc = NULL;
  729. Vector4 *current_diffuse = NULL;
  730. float *current_size = NULL;
  731. unsigned char *current_orient = NULL;
  732. unsigned char *current_frame = NULL;
  733. // If there is a color or alpha array enable gradient in shader - otherwise disable.
  734. float value_255 = 0.9961f; //254 / 255
  735. bool default_white_opaque = ( DefaultPointColor.X > value_255 &&
  736. DefaultPointColor.Y > value_255 &&
  737. DefaultPointColor.Z > value_255 &&
  738. DefaultPointAlpha > value_255);
  739. // The reason we check for lack of texture here is that SR seems to render black triangles
  740. // rather than white triangles as would be expected) when there is no texture AND no gradient.
  741. if (PointDiffuse || !default_white_opaque || !Texture) {
  742. Shader.Set_Primary_Gradient(ShaderClass::GRADIENT_MODULATE);
  743. } else {
  744. Shader.Set_Primary_Gradient(ShaderClass::GRADIENT_DISABLE);
  745. }
  746. // If Texture is non-NULL enable texturing in shader - otherwise disable.
  747. if (Texture) {
  748. Shader.Set_Texturing(ShaderClass::TEXTURING_ENABLE);
  749. } else {
  750. Shader.Set_Texturing(ShaderClass::TEXTURING_DISABLE);
  751. }
  752. // If there is an active point table, use it to compress the point
  753. // locations/colors/alphas/sizes/orientations/frames.
  754. if (APT) {
  755. // Resize compressed result arrays if needed (2x guardband to prevent
  756. // frequent reallocations):
  757. /// @todo lorenzen sez: precompute pointers to indexed array elements, below
  758. if (compressed_loc.Length() < PointCount) {
  759. compressed_loc.Resize(PointCount * 2);
  760. }
  761. VectorProcessorClass::CopyIndexed(&compressed_loc[0],
  762. PointLoc->Get_Array(), APT->Get_Array(), PointCount);
  763. current_loc = &compressed_loc[0];
  764. if (PointDiffuse) {
  765. if (compressed_diffuse.Length() < PointCount) {
  766. compressed_diffuse.Resize(PointCount * 2);
  767. }
  768. VectorProcessorClass::CopyIndexed(&compressed_diffuse[0],
  769. PointDiffuse->Get_Array(), APT->Get_Array(), PointCount);
  770. current_diffuse = &compressed_diffuse[0];
  771. }
  772. if (PointSize) {
  773. if (compressed_size.Length() < PointCount) {
  774. compressed_size.Resize(PointCount * 2);
  775. }
  776. VectorProcessorClass::CopyIndexed(&compressed_size[0],
  777. PointSize->Get_Array(), APT->Get_Array(), PointCount);
  778. current_size = &compressed_size[0];
  779. }
  780. if (PointOrientation) {
  781. if (compressed_orient.Length() < PointCount) {
  782. compressed_orient.Resize(PointCount * 2);
  783. }
  784. VectorProcessorClass::CopyIndexed(&compressed_orient[0],
  785. PointOrientation->Get_Array(), APT->Get_Array(), PointCount);
  786. current_orient = &compressed_orient[0];
  787. }
  788. if (PointFrame) {
  789. if (compressed_frame.Length() < PointCount) {
  790. compressed_frame.Resize(PointCount * 2);
  791. }
  792. VectorProcessorClass::CopyIndexed(&compressed_frame[0],
  793. PointFrame->Get_Array(), APT->Get_Array(), PointCount);
  794. current_frame = &compressed_frame[0];
  795. }
  796. } else {
  797. current_loc = PointLoc->Get_Array();
  798. if (PointDiffuse) {
  799. current_diffuse = PointDiffuse->Get_Array();
  800. }
  801. if (PointSize) {
  802. current_size = PointSize->Get_Array();
  803. }
  804. if (PointOrientation) {
  805. current_orient = PointOrientation->Get_Array();
  806. }
  807. if (PointFrame) {
  808. current_frame = PointFrame->Get_Array();
  809. }
  810. }
  811. // Get the world and view matrices
  812. Matrix4 view;
  813. DX8Wrapper::Get_Transform(D3DTS_VIEW,view);
  814. // Transform the point locations from worldspace to camera space if needed
  815. // (i.e. if they are not already in camera space):
  816. // need to interrupt this processing. If we are not billboarding, then we need the actual position
  817. // of the vertice to lay it down flat.
  818. if (Get_Flag(TRANSFORM) && Billboard) {
  819. // Resize transformed location array if needed (2x guardband to prevent
  820. // frequent reallocations):
  821. if (transformed_loc.Length() < PointCount) {
  822. transformed_loc.Resize(PointCount * 2);
  823. }
  824. // Not using vector processor class because we are discarding w
  825. // Not using T&L in DX8 because we don't want DX8 to transform
  826. // 3 times per particle when we can do it once
  827. for (int i=0; i<PointCount; i++)
  828. {
  829. /// @todo lorenzen sez: use pointer arithmetic here and a fast while loop
  830. Vector4 result=view*current_loc[i];
  831. transformed_loc[i].X=result.X;
  832. transformed_loc[i].Y=result.Y;
  833. transformed_loc[i].Z=result.Z;
  834. }
  835. current_loc = &transformed_loc[0];
  836. } // if transform
  837. // Update the arrays with the offsets.
  838. int vnum, pnum;
  839. Update_Arrays(current_loc, current_diffuse, current_size, current_orient, current_frame,
  840. PointCount, PointLoc->Get_Count(), vnum, pnum);
  841. // the locations are now in view space
  842. // so set world and view matrices to identity and render
  843. Matrix4 identity(true);
  844. DX8Wrapper::Set_Transform(D3DTS_WORLD,identity);
  845. DX8Wrapper::Set_Transform(D3DTS_VIEW,identity);
  846. DX8Wrapper::Set_Material(PointMaterial);
  847. DX8Wrapper::Set_Shader(Shader);
  848. DX8Wrapper::Set_Texture(0,Texture);
  849. // Enable sorting if the primitives are translucent and alpha testing is not enabled.
  850. const bool sort = (Shader.Get_Dst_Blend_Func() != ShaderClass::DSTBLEND_ZERO) && (Shader.Get_Alpha_Test() == ShaderClass::ALPHATEST_DISABLE) && (WW3D::Is_Sorting_Enabled());
  851. IndexBufferClass *indexbuffer;
  852. int verticesperprimitive;/// lorenzen fixed
  853. int current;
  854. int delta;
  855. /// @todo lorenzen sez: if tri-based particles are not supported, elim this test
  856. if (PointMode == QUADS) {
  857. verticesperprimitive = 2;
  858. indexbuffer = sort ? static_cast <IndexBufferClass*> (SortingQuads) : static_cast <IndexBufferClass*> (Quads);
  859. } else {
  860. verticesperprimitive = 3;
  861. indexbuffer = sort ? static_cast <IndexBufferClass*> (SortingTris) : static_cast <IndexBufferClass*> (Tris);
  862. }
  863. current = 0;
  864. while (current<vnum)
  865. {
  866. delta=MIN(vnum-current,MAX_VB_SIZE);
  867. DynamicVBAccessClass PointVerts (sort ? BUFFER_TYPE_DYNAMIC_SORTING : BUFFER_TYPE_DYNAMIC_DX8, dynamic_fvf_type, delta);
  868. // Copy in the data to the VB
  869. {
  870. DynamicVBAccessClass::WriteLockClass Lock(&PointVerts);
  871. int i;
  872. unsigned char *vb=(unsigned char*)Lock.Get_Formatted_Vertex_Array();
  873. const FVFInfoClass& fvfinfo=PointVerts.FVF_Info();
  874. for (i = current; i < current + delta; i++)
  875. {
  876. /// @todo lorenzen sez: use pointer arithmetic throughout this block
  877. /// @todo lorenzen sez: delare thes locals outside this loop
  878. /// @todo lorenzen sez: use a fast while loop
  879. // Copy Locations
  880. *(Vector3*)(vb+fvfinfo.Get_Location_Offset())=VertexLoc[i];
  881. if (current_diffuse) {
  882. unsigned color=DX8Wrapper::Convert_Color_Clamp(VertexDiffuse[i]);
  883. *(unsigned int*)(vb+fvfinfo.Get_Diffuse_Offset())=color;
  884. }
  885. else
  886. *(unsigned int*)(vb+fvfinfo.Get_Diffuse_Offset())=
  887. DX8Wrapper::Convert_Color_Clamp(Vector4(DefaultPointColor[0],DefaultPointColor[1],DefaultPointColor[2],DefaultPointAlpha));
  888. *(Vector2*)(vb+fvfinfo.Get_Tex_Offset(0))=VertexUV[i];
  889. vb+=fvfinfo.Get_FVF_Size();
  890. }
  891. } // copy
  892. DX8Wrapper::Set_Index_Buffer (indexbuffer, 0);
  893. DX8Wrapper::Set_Vertex_Buffer (PointVerts);
  894. if ( sort )
  895. {
  896. SortingRendererClass::Insert_Triangles (0, delta / verticesperprimitive, 0, delta);
  897. }
  898. else
  899. {
  900. DX8Wrapper::Draw_Triangles (0, delta / verticesperprimitive, 0, delta);
  901. }
  902. current+=delta;
  903. } // loop while (current<vnum)
  904. // restore the matrices
  905. DX8Wrapper::Set_Transform(D3DTS_VIEW,view);
  906. }
  907. /**************************************************************************
  908. * PointGroupClass::Update_Arrays -- Update all arrays used in rendering *
  909. * *
  910. * INPUT: *
  911. * *
  912. * OUTPUT: *
  913. * *
  914. * WARNINGS: *
  915. * *
  916. * HISTORY: *
  917. * 11/17/1998 NH : Created. *
  918. *========================================================================*/
  919. void PointGroupClass::Update_Arrays(
  920. Vector3 *point_loc,
  921. Vector4 *point_diffuse,
  922. float *point_size,
  923. unsigned char *point_orientation,
  924. unsigned char *point_frame,
  925. int active_points,
  926. int total_points,
  927. int &vnum,
  928. int &pnum)
  929. {
  930. int verts_per_point = (PointMode == QUADS) ? 4 : 3;
  931. int polys_per_point = (PointMode == QUADS) ? 2 : 1;
  932. // total_vnum/pnum reflect the size of the point arrays passed to the
  933. // point group. These (instead of vnum/pnum, which reflect the number of
  934. // active points) are used for the resize logic - the idea is that these
  935. // numbers will vary less often than the active numbers.
  936. int total_vnum = verts_per_point * total_points;
  937. vnum = verts_per_point * active_points;
  938. pnum = polys_per_point * active_points;
  939. // Resize the arrays if they are too small. We only need to check the length of one array
  940. // since they always all have the same length.
  941. /// @todo lorenzen sez: precompute params below
  942. if (VertexLoc.Length() < total_vnum) {
  943. // Resize arrays (2x guardband to prevent frequent reallocations).
  944. VertexLoc.Resize(total_vnum * 2, false);
  945. VertexUV.Resize(total_vnum * 2, false);
  946. VertexDiffuse.Resize(total_vnum * 2, false);
  947. }
  948. int vert, i, j;
  949. /*
  950. ** Generate the vertex locations from the point locations (note that both are in camera space).
  951. ** Vertex locations depend on the point mode and the points' orientation and size
  952. */
  953. // This defines the loop we run: the LSB indicates whether there is a size override array, the
  954. // next bit indicates whether there is an orientation override array, and the higher bits
  955. // indicate the point mode.
  956. enum LoopSelectionEnum {
  957. TRIS_NOSIZE_NOORIENT = ((int)TRIS << 2) + 0,
  958. TRIS_SIZE_NOORIENT = ((int)TRIS << 2) + 1,
  959. TRIS_NOSIZE_ORIENT = ((int)TRIS << 2) + 2,
  960. TRIS_SIZE_ORIENT = ((int)TRIS << 2) + 3,
  961. QUADS_NOSIZE_NOORIENT = ((int)QUADS << 2) + 0,
  962. QUADS_SIZE_NOORIENT = ((int)QUADS << 2) + 1,
  963. QUADS_NOSIZE_ORIENT = ((int)QUADS << 2) + 2,
  964. QUADS_SIZE_ORIENT = ((int)QUADS << 2) + 3,
  965. SCREEN_NOSIZE_NOORIENT = ((int)SCREENSPACE << 2) + 0,
  966. SCREEN_SIZE_NOORIENT = ((int)SCREENSPACE << 2) + 1,
  967. SCREEN_NOSIZE_ORIENT = ((int)SCREENSPACE << 2) + 2,
  968. SCREEN_SIZE_ORIENT = ((int)SCREENSPACE << 2) + 3,
  969. };
  970. LoopSelectionEnum loop_sel = (LoopSelectionEnum)(((int)PointMode << 2) +
  971. (point_orientation ? 2 : 0) + (point_size ? 1 : 0));
  972. vert = 0;
  973. Vector3 *vertex_loc = &VertexLoc[0];
  974. /// @todo lorenzen sez: this switch statement may be done more compactly another way... look into it
  975. switch (loop_sel) {
  976. case TRIS_NOSIZE_NOORIENT:
  977. {
  978. // Setup constant vertex offsets (since size and orientation are invariants)
  979. Vector3 scaled_offset[3];
  980. scaled_offset[0] = _TriVertexLocationOrientationTable[DefaultPointOrientation][0] * DefaultPointSize;
  981. scaled_offset[1] = _TriVertexLocationOrientationTable[DefaultPointOrientation][1] * DefaultPointSize;
  982. scaled_offset[2] = _TriVertexLocationOrientationTable[DefaultPointOrientation][2] * DefaultPointSize;
  983. // Add vertex offsets to point locations to get vertex locations
  984. for (i = 0; i < active_points; i++) {
  985. vertex_loc[vert + 0] = point_loc[i] + scaled_offset[0];
  986. vertex_loc[vert + 1] = point_loc[i] + scaled_offset[1];
  987. vertex_loc[vert + 2] = point_loc[i] + scaled_offset[2];
  988. vert += 3;
  989. }
  990. }
  991. break;
  992. case TRIS_SIZE_NOORIENT:
  993. {
  994. // Scale vertex offsets and add them to point locations to get vertex locations
  995. for (i = 0; i < active_points; i++) {
  996. vertex_loc[vert + 0] = point_loc[i] +
  997. _TriVertexLocationOrientationTable[DefaultPointOrientation][0] * point_size[i];
  998. vertex_loc[vert + 1] = point_loc[i] +
  999. _TriVertexLocationOrientationTable[DefaultPointOrientation][1] * point_size[i];
  1000. vertex_loc[vert + 2] = point_loc[i] +
  1001. _TriVertexLocationOrientationTable[DefaultPointOrientation][2] * point_size[i];
  1002. vert += 3;
  1003. }
  1004. }
  1005. break;
  1006. case TRIS_NOSIZE_ORIENT:
  1007. {
  1008. // Scale vertex offsets and add them to point locations to get vertex locations
  1009. for (i = 0; i < active_points; i++) {
  1010. vertex_loc[vert + 0] = point_loc[i] +
  1011. _TriVertexLocationOrientationTable[point_orientation[i]][0] * DefaultPointSize;
  1012. vertex_loc[vert + 1] = point_loc[i] +
  1013. _TriVertexLocationOrientationTable[point_orientation[i]][1] * DefaultPointSize;
  1014. vertex_loc[vert + 2] = point_loc[i] +
  1015. _TriVertexLocationOrientationTable[point_orientation[i]][2] * DefaultPointSize;
  1016. vert += 3;
  1017. }
  1018. }
  1019. break;
  1020. case TRIS_SIZE_ORIENT:
  1021. {
  1022. // Scale vertex offsets and add them to point locations to get vertex locations
  1023. for (i = 0; i < active_points; i++) {
  1024. vertex_loc[vert + 0] = point_loc[i] +
  1025. _TriVertexLocationOrientationTable[point_orientation[i]][0] * point_size[i];
  1026. vertex_loc[vert + 1] = point_loc[i] +
  1027. _TriVertexLocationOrientationTable[point_orientation[i]][1] * point_size[i];
  1028. vertex_loc[vert + 2] = point_loc[i] +
  1029. _TriVertexLocationOrientationTable[point_orientation[i]][2] * point_size[i];
  1030. vert += 3;
  1031. }
  1032. }
  1033. break;
  1034. case QUADS_NOSIZE_NOORIENT:
  1035. {
  1036. // Setup constant vertex offsets (since size and orientation are invariants)
  1037. Vector3 scaled_offset[4];
  1038. scaled_offset[0] = _QuadVertexLocationOrientationTable[DefaultPointOrientation][0] * DefaultPointSize;
  1039. scaled_offset[1] = _QuadVertexLocationOrientationTable[DefaultPointOrientation][1] * DefaultPointSize;
  1040. scaled_offset[2] = _QuadVertexLocationOrientationTable[DefaultPointOrientation][2] * DefaultPointSize;
  1041. scaled_offset[3] = _QuadVertexLocationOrientationTable[DefaultPointOrientation][3] * DefaultPointSize;
  1042. // Add vertex offsets to point locations to get vertex locations
  1043. for (i = 0; i < active_points; i++) {
  1044. vertex_loc[vert + 0] = point_loc[i] + scaled_offset[0];
  1045. vertex_loc[vert + 1] = point_loc[i] + scaled_offset[1];
  1046. vertex_loc[vert + 2] = point_loc[i] + scaled_offset[2];
  1047. vertex_loc[vert + 3] = point_loc[i] + scaled_offset[3];
  1048. vert += 4;
  1049. }
  1050. }
  1051. break;
  1052. case QUADS_SIZE_NOORIENT:
  1053. {
  1054. // Scale vertex offsets and add them to point locations to get vertex locations
  1055. for (i = 0; i < active_points; i++) {
  1056. vertex_loc[vert + 0] = point_loc[i] +
  1057. _QuadVertexLocationOrientationTable[DefaultPointOrientation][0] * point_size[i];
  1058. vertex_loc[vert + 1] = point_loc[i] +
  1059. _QuadVertexLocationOrientationTable[DefaultPointOrientation][1] * point_size[i];
  1060. vertex_loc[vert + 2] = point_loc[i] +
  1061. _QuadVertexLocationOrientationTable[DefaultPointOrientation][2] * point_size[i];
  1062. vertex_loc[vert + 3] = point_loc[i] +
  1063. _QuadVertexLocationOrientationTable[DefaultPointOrientation][3] * point_size[i];
  1064. vert += 4;
  1065. }
  1066. }
  1067. break;
  1068. case QUADS_NOSIZE_ORIENT:
  1069. {
  1070. // Scale vertex offsets and add them to point locations to get vertex locations
  1071. for (i = 0; i < active_points; i++) {
  1072. vertex_loc[vert + 0] = point_loc[i] +
  1073. _QuadVertexLocationOrientationTable[point_orientation[i]][0] * DefaultPointSize;
  1074. vertex_loc[vert + 1] = point_loc[i] +
  1075. _QuadVertexLocationOrientationTable[point_orientation[i]][1] * DefaultPointSize;
  1076. vertex_loc[vert + 2] = point_loc[i] +
  1077. _QuadVertexLocationOrientationTable[point_orientation[i]][2] * DefaultPointSize;
  1078. vertex_loc[vert + 3] = point_loc[i] +
  1079. _QuadVertexLocationOrientationTable[point_orientation[i]][3] * DefaultPointSize;
  1080. vert += 4;
  1081. }
  1082. }
  1083. break;
  1084. case QUADS_SIZE_ORIENT:
  1085. {
  1086. Matrix4 view;
  1087. Vector4 result;
  1088. if (!Billboard) {
  1089. DX8Wrapper::Get_Transform(D3DTS_VIEW,view);
  1090. }
  1091. // Scale vertex offsets and add them to point locations to get vertex locations
  1092. for (i = 0; i < active_points; i++) {
  1093. if (!Billboard) {
  1094. // If we're not billboarding, then the coordinate we have is in screen space.
  1095. Matrix4 rotMat;
  1096. D3DXMatrixRotationZ(&(D3DXMATRIX&) rotMat, ((float)point_orientation[i] / 255.0f * 2 * D3DX_PI));
  1097. Vector4 orientedVecX = rotMat * GroundMultiplierX;
  1098. Vector4 orientedVecY = rotMat * GroundMultiplierY;
  1099. vertex_loc[vert + 0].X = point_loc[i].X + (orientedVecX.X + orientedVecY.X) * point_size[i];
  1100. vertex_loc[vert + 0].Y = point_loc[i].Y + (orientedVecX.Y + orientedVecY.Y) * point_size[i];
  1101. vertex_loc[vert + 0].Z = point_loc[i].Z;
  1102. vertex_loc[vert + 1].X = point_loc[i].X + (orientedVecX.X - orientedVecY.X) * point_size[i];
  1103. vertex_loc[vert + 1].Y = point_loc[i].Y + (orientedVecX.Y - orientedVecY.Y) * point_size[i];
  1104. vertex_loc[vert + 1].Z = point_loc[i].Z;
  1105. vertex_loc[vert + 2].X = point_loc[i].X + -(orientedVecX.X + orientedVecY.X) * point_size[i];
  1106. vertex_loc[vert + 2].Y = point_loc[i].Y + -(orientedVecX.Y + orientedVecY.Y) * point_size[i];
  1107. vertex_loc[vert + 2].Z = point_loc[i].Z;
  1108. vertex_loc[vert + 3].X = point_loc[i].X + (-orientedVecX.X + orientedVecY.X) * point_size[i];
  1109. vertex_loc[vert + 3].Y = point_loc[i].Y + (-orientedVecX.Y + orientedVecY.Y) * point_size[i];
  1110. vertex_loc[vert + 3].Z = point_loc[i].Z;
  1111. // now apply the view transform so that this data is in the format expected
  1112. // upon the functions return.
  1113. result = view*vertex_loc[vert + 0];
  1114. vertex_loc[vert + 0].X = result.X;
  1115. vertex_loc[vert + 0].Y = result.Y;
  1116. vertex_loc[vert + 0].Z = result.Z;
  1117. result = view*vertex_loc[vert + 1];
  1118. vertex_loc[vert + 1].X = result.X;
  1119. vertex_loc[vert + 1].Y = result.Y;
  1120. vertex_loc[vert + 1].Z = result.Z;
  1121. result = view*vertex_loc[vert + 2];
  1122. vertex_loc[vert + 2].X = result.X;
  1123. vertex_loc[vert + 2].Y = result.Y;
  1124. vertex_loc[vert + 2].Z = result.Z;
  1125. result = view*vertex_loc[vert + 3];
  1126. vertex_loc[vert + 3].X = result.X;
  1127. vertex_loc[vert + 3].Y = result.Y;
  1128. vertex_loc[vert + 3].Z = result.Z;
  1129. } else {
  1130. vertex_loc[vert + 0] = point_loc[i] +
  1131. _QuadVertexLocationOrientationTable[point_orientation[i]][0] * point_size[i];
  1132. vertex_loc[vert + 1] = point_loc[i] +
  1133. _QuadVertexLocationOrientationTable[point_orientation[i]][1] * point_size[i];
  1134. vertex_loc[vert + 2] = point_loc[i] +
  1135. _QuadVertexLocationOrientationTable[point_orientation[i]][2] * point_size[i];
  1136. vertex_loc[vert + 3] = point_loc[i] +
  1137. _QuadVertexLocationOrientationTable[point_orientation[i]][3] * point_size[i];
  1138. }
  1139. vert += 4;
  1140. }
  1141. }
  1142. break;
  1143. // Orientations are ignored for screensize pointgroups
  1144. case SCREEN_NOSIZE_NOORIENT:
  1145. case SCREEN_NOSIZE_ORIENT:
  1146. {
  1147. // Offsets need to be scaled to the current screen resolution
  1148. // First find x and y scale factors (sizes in pixels need to be
  1149. // normalized to 2D cam viewplane of -1,-1 to 1,1)
  1150. int xres, yres, bitdepth;
  1151. bool windowed;
  1152. WW3D::Get_Render_Target_Resolution(xres, yres, bitdepth, windowed);
  1153. float x_scale = (VPXMax - VPXMin) / xres;
  1154. float y_scale = (VPYMax - VPYMin) / yres;
  1155. Vector3 scaled_locs[2][3];
  1156. for (int i = 0; i < 2; i++) {
  1157. for (int j = 0; j < 3; j++) {
  1158. scaled_locs[i][j].X = _ScreenspaceVertexLocationSizeTable[i][j].X * x_scale;
  1159. scaled_locs[i][j].Y = _ScreenspaceVertexLocationSizeTable[i][j].Y * y_scale;
  1160. scaled_locs[i][j].Z = _ScreenspaceVertexLocationSizeTable[i][j].Z;
  1161. }
  1162. }
  1163. // Add vertex offsets to point locations to get vertex locations
  1164. int size_idx = (DefaultPointSize <= 1.0f) ? 0 : 1;
  1165. for (i = 0; i < active_points; i++) {
  1166. vertex_loc[vert + 0] = point_loc[i] + scaled_locs[size_idx][0];
  1167. vertex_loc[vert + 1] = point_loc[i] + scaled_locs[size_idx][1];
  1168. vertex_loc[vert + 2] = point_loc[i] + scaled_locs[size_idx][2];
  1169. vert += 3;
  1170. }
  1171. }
  1172. break;
  1173. case SCREEN_SIZE_NOORIENT:
  1174. case SCREEN_SIZE_ORIENT:
  1175. {
  1176. // Offsets need to be scaled to the current screen resolution
  1177. // First find x and y scale factors (sizes in pixels need to be
  1178. // normalized to 2D cam viewplane of -1,-1 to 1,1)
  1179. int xres, yres, bitdepth;
  1180. bool windowed;
  1181. WW3D::Get_Render_Target_Resolution(xres, yres, bitdepth, windowed);
  1182. float x_scale = (VPXMax - VPXMin) / xres;
  1183. float y_scale = (VPYMax - VPYMin) / yres;
  1184. Vector3 scaled_locs[2][3];
  1185. for (int i = 0; i < 2; i++) {
  1186. for (int j = 0; j < 3; j++) {
  1187. scaled_locs[i][j].X = _ScreenspaceVertexLocationSizeTable[i][j].X * x_scale;
  1188. scaled_locs[i][j].Y = _ScreenspaceVertexLocationSizeTable[i][j].Y * y_scale;
  1189. scaled_locs[i][j].Z = _ScreenspaceVertexLocationSizeTable[i][j].Z;
  1190. }
  1191. }
  1192. // Add vertex offsets to point locations to get vertex locations
  1193. for (i = 0; i < active_points; i++) {
  1194. int size_idx = (point_size[i] <= 1.0f) ? 0 : 1;
  1195. vertex_loc[vert + 0] = point_loc[i] + scaled_locs[size_idx][0];
  1196. vertex_loc[vert + 1] = point_loc[i] + scaled_locs[size_idx][1];
  1197. vertex_loc[vert + 2] = point_loc[i] + scaled_locs[size_idx][2];
  1198. vert += 3;
  1199. }
  1200. }
  1201. break;
  1202. default:
  1203. WWASSERT(0);
  1204. break;
  1205. }
  1206. /*
  1207. ** Fill the UV vertex array
  1208. */
  1209. unsigned int frame_mask = ~(0xFFFFFFFF << (FrameRowColumnCountLog2 + FrameRowColumnCountLog2));// To ensure frames in range
  1210. if (point_frame) {
  1211. /// @todo lorenzen sez: use pointer arithmetic below
  1212. // Fill UV array according to frame override array:
  1213. Vector2 *vertex_uv = &VertexUV[0];
  1214. if (PointMode != QUADS) {
  1215. // Modes with three vertices per point:
  1216. Vector2 *uv_ptr = _TriVertexUVFrameTable[FrameRowColumnCountLog2];
  1217. int vert = 0;
  1218. for (int i = 0; i < active_points; i++) {
  1219. int uv_idx = (point_frame[i] & frame_mask) * 3;
  1220. vertex_uv[vert++] = uv_ptr[uv_idx + 0];
  1221. vertex_uv[vert++] = uv_ptr[uv_idx + 1];
  1222. vertex_uv[vert++] = uv_ptr[uv_idx + 2];
  1223. }
  1224. } else {
  1225. // Modes with four vertices per point:
  1226. Vector2 *uv_ptr = _QuadVertexUVFrameTable[FrameRowColumnCountLog2];
  1227. int vert = 0;
  1228. for (int i = 0; i < active_points; i++) {
  1229. int uv_idx = (point_frame[i] & frame_mask) * 4;
  1230. vertex_uv[vert++] = uv_ptr[uv_idx + 0];
  1231. vertex_uv[vert++] = uv_ptr[uv_idx + 1];
  1232. vertex_uv[vert++] = uv_ptr[uv_idx + 2];
  1233. vertex_uv[vert++] = uv_ptr[uv_idx + 3];
  1234. }
  1235. }
  1236. } else {
  1237. /// @todo lorenzen sez: use pointer arithmetic below
  1238. // Fill UV array according to frame state:
  1239. Vector2 *vertex_uv = &VertexUV[0];
  1240. if (PointMode != QUADS) {
  1241. // Modes with three vertices per point:
  1242. Vector2 *uv_ptr = _TriVertexUVFrameTable[FrameRowColumnCountLog2] + ((DefaultPointFrame & frame_mask) * 3);
  1243. int vert = 0;
  1244. for (int i = 0; i < active_points; i++) {
  1245. vertex_uv[vert++] = uv_ptr[0];
  1246. vertex_uv[vert++] = uv_ptr[1];
  1247. vertex_uv[vert++] = uv_ptr[2];
  1248. }
  1249. } else {
  1250. // Modes with four vertices per point:
  1251. Vector2 *uv_ptr = _QuadVertexUVFrameTable[FrameRowColumnCountLog2] + ((DefaultPointFrame & frame_mask) * 4);
  1252. int vert = 0;
  1253. for (int i = 0; i < active_points; i++) {
  1254. vertex_uv[vert++] = uv_ptr[0];
  1255. vertex_uv[vert++] = uv_ptr[1];
  1256. vertex_uv[vert++] = uv_ptr[2];
  1257. vertex_uv[vert++] = uv_ptr[3];
  1258. }
  1259. }
  1260. }
  1261. /*
  1262. ** If we have a point color array, fill the vertex diffuse array from it.
  1263. */
  1264. /// @todo lorenzen sez: use a quicker, unwrapped loop, and pointer arithmetic
  1265. /// @todo lorenzen sez: this is a leaf function, dang it
  1266. vert = 0;
  1267. if (point_diffuse) {
  1268. Vector4* vertex_color = &VertexDiffuse[0];
  1269. for (i = 0; i < active_points; i++) {
  1270. for (j = 0; j < verts_per_point; j++) {
  1271. vertex_color[vert + j] = point_diffuse[i];
  1272. }
  1273. vert += verts_per_point;
  1274. }
  1275. }
  1276. }
  1277. /**************************************************************************
  1278. * PointGroupClass::_Init -- Create static data. *
  1279. * *
  1280. * INPUT: *
  1281. * *
  1282. * OUTPUT: *
  1283. * *
  1284. * WARNINGS: *
  1285. * *
  1286. * HISTORY: *
  1287. * 06/28/2000 NH : Created. *
  1288. *========================================================================*/
  1289. void PointGroupClass::_Init(void)
  1290. {
  1291. int i, j;
  1292. /*
  1293. ** Fill vertex location orientation tables
  1294. */
  1295. // Unrotated locations
  1296. Vector3 tri_locs[3] = {
  1297. Vector3(0.0f, -2.0f, 0.0f),
  1298. Vector3(-1.732f, 1.0f, 0.0f),
  1299. Vector3(1.732f, 1.0f, 0.0f)
  1300. };
  1301. Vector3 quad_locs[4] = {
  1302. Vector3(-0.5f, 0.5f, 0.0f),
  1303. Vector3(-0.5f, -0.5f, 0.0f),
  1304. Vector3(0.5f, -0.5f, 0.0f),
  1305. Vector3(0.5f, 0.5f, 0.0f)
  1306. };
  1307. /// @todo lorenzen sez: unwrap loop and use pointer arithmetic (if this gets called a lot)
  1308. float angle = 0.0f; // In radians
  1309. float angle_step = (WWMATH_PI * 2.0f) / 256.0f; // In radians
  1310. for (i = 0; i < 256; i++) {
  1311. float c = WWMath::Fast_Cos(angle);
  1312. float s = WWMath::Fast_Sin(angle);
  1313. for (j = 0; j < 3; j++) {
  1314. _TriVertexLocationOrientationTable[i][j].X = tri_locs[j].X * c - tri_locs[j].Y * s;
  1315. _TriVertexLocationOrientationTable[i][j].Y = tri_locs[j].X * s + tri_locs[j].Y * c;
  1316. _TriVertexLocationOrientationTable[i][j].Z = tri_locs[j].Z;
  1317. }
  1318. for (j = 0; j < 4; j++) {
  1319. _QuadVertexLocationOrientationTable[i][j].X = quad_locs[j].X * c - quad_locs[j].Y * s;
  1320. _QuadVertexLocationOrientationTable[i][j].Y = quad_locs[j].X * s + quad_locs[j].Y * c;
  1321. _QuadVertexLocationOrientationTable[i][j].Z = quad_locs[j].Z;
  1322. }
  1323. angle += angle_step;
  1324. }
  1325. /*
  1326. ** Fill frame UV tables
  1327. */
  1328. // Unscaled / untranslated UVs
  1329. Vector2 tri_uvs[3] = {
  1330. Vector2(0.5f, 0.0f),
  1331. Vector2(0.0f, 0.866f),
  1332. Vector2(1.0f, 0.866f)
  1333. };
  1334. Vector2 quad_uvs[4] = {
  1335. Vector2(0.0f, 0.0f),
  1336. Vector2(0.0f, 1.0f),
  1337. Vector2(1.0f, 1.0f),
  1338. Vector2(1.0f, 0.0f)
  1339. };
  1340. /// @todo lorenzen sez: umwrap and use pointers
  1341. for (i = 0; i < 5; i++) {
  1342. unsigned int rows = 1 << i;
  1343. unsigned int count = rows * rows;
  1344. Vector2 *tri_table = _TriVertexUVFrameTable[i] = W3DNEWARRAY Vector2[count * 3];
  1345. Vector2 *quad_table = _QuadVertexUVFrameTable[i] = W3DNEWARRAY Vector2[count * 4];
  1346. Vector2 corner(0.0f, 0.0f);
  1347. float scale = 1.0f / (float)rows;
  1348. int tri_idx = 0;
  1349. int quad_idx = 0;
  1350. for (unsigned int v = 0; v < rows; v++) {
  1351. for (unsigned int u = 0; u < rows; u++) {
  1352. tri_table[tri_idx++] = corner + (tri_uvs[0] * scale);
  1353. tri_table[tri_idx++] = corner + (tri_uvs[1] * scale);
  1354. tri_table[tri_idx++] = corner + (tri_uvs[2] * scale);
  1355. quad_table[quad_idx++] = corner + (quad_uvs[0] * scale);
  1356. quad_table[quad_idx++] = corner + (quad_uvs[1] * scale);
  1357. quad_table[quad_idx++] = corner + (quad_uvs[2] * scale);
  1358. quad_table[quad_idx++] = corner + (quad_uvs[3] * scale);
  1359. corner.X += scale;
  1360. }
  1361. corner.Y += scale;
  1362. corner.X = 0.0f;
  1363. }
  1364. }
  1365. // Create the IBs
  1366. Tris=NEW_REF(DX8IndexBufferClass,(MAX_TRI_IB_SIZE));
  1367. Quads=NEW_REF(DX8IndexBufferClass,(MAX_QUAD_IB_SIZE));
  1368. SortingTris=NEW_REF(SortingIndexBufferClass,(MAX_TRI_IB_SIZE));
  1369. SortingQuads=NEW_REF(SortingIndexBufferClass,(MAX_QUAD_IB_SIZE));
  1370. // Fill up the IBs
  1371. {
  1372. DX8IndexBufferClass::WriteLockClass locktris(Tris);
  1373. unsigned short *ib=locktris.Get_Index_Array();
  1374. for (i=0; i<MAX_TRI_IB_SIZE; i++) ib[i]=(unsigned short) i;
  1375. }
  1376. {
  1377. unsigned short vert=0;
  1378. DX8IndexBufferClass::WriteLockClass lockquads(Quads);
  1379. unsigned short *ib=lockquads.Get_Index_Array();
  1380. vert=0;
  1381. for (i=0; i<MAX_QUAD_IB_SIZE; i+=6)
  1382. {
  1383. /// @todo lorenzen sez: pointer arithmetic like "++ib=vert+1"
  1384. ib[i]=vert;
  1385. ib[i+1]=vert+1;
  1386. ib[i+2]=vert+2;
  1387. ib[i+3]=vert+2;
  1388. ib[i+4]=vert+3;
  1389. ib[i+5]=vert;
  1390. vert+=4;
  1391. }
  1392. }
  1393. {
  1394. SortingIndexBufferClass::WriteLockClass locktris(SortingTris);
  1395. unsigned short *ib=locktris.Get_Index_Array();
  1396. for (i=0; i<MAX_TRI_IB_SIZE; i++) ib[i]=(unsigned short) i;
  1397. }
  1398. {
  1399. unsigned short vert=0;
  1400. SortingIndexBufferClass::WriteLockClass lockquads(SortingQuads);
  1401. unsigned short *ib=lockquads.Get_Index_Array();
  1402. vert=0;
  1403. for (i=0; i<MAX_QUAD_IB_SIZE; i+=6)
  1404. {
  1405. /// @todo lorenzen sez: pointers!
  1406. ib[i]=vert;
  1407. ib[i+1]=vert+1;
  1408. ib[i+2]=vert+2;
  1409. ib[i+3]=vert+2;
  1410. ib[i+4]=vert+3;
  1411. ib[i+5]=vert;
  1412. vert+=4;
  1413. }
  1414. }
  1415. PointMaterial=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE);
  1416. }
  1417. /**************************************************************************
  1418. * PointGroupClass::_Shutdown -- Destroy static data. *
  1419. * *
  1420. * INPUT: *
  1421. * *
  1422. * OUTPUT: *
  1423. * *
  1424. * WARNINGS: *
  1425. * *
  1426. * HISTORY: *
  1427. * 06/28/2000 NH : Created. *
  1428. *========================================================================*/
  1429. void PointGroupClass::_Shutdown(void)
  1430. {
  1431. for (int i = 0; i < 5; i++) {
  1432. delete [] _TriVertexUVFrameTable[i];
  1433. delete [] _QuadVertexUVFrameTable[i];
  1434. }
  1435. REF_PTR_RELEASE(PointMaterial);
  1436. REF_PTR_RELEASE(SortingQuads);
  1437. REF_PTR_RELEASE(SortingTris);
  1438. REF_PTR_RELEASE(Quads);
  1439. REF_PTR_RELEASE(Tris);
  1440. transformed_loc.Clear();
  1441. VertexLoc.Clear();
  1442. VertexDiffuse.Clear();
  1443. VertexUV.Clear();
  1444. }
  1445. /**************************************************************************
  1446. * PointGroupClass::RenderVolumeParticles -- draw a point group.sandwich *
  1447. * *
  1448. * This is a specialized renderer. It will draw the particle repeatedly *
  1449. * while attenuating opacity appropriately, and bumping the z-position. *
  1450. * This is actually done by cloning the particle over and over at *
  1451. * successively closer positions to the camera. Very Slow! *
  1452. * *
  1453. * INPUT: *
  1454. * *
  1455. * OUTPUT: *
  1456. * *
  1457. * WARNINGS: USE SPARINGLY, IT IS EXPENSIVE!!!!! *
  1458. * *
  1459. * HISTORY: *
  1460. * 12/03/2002 Mark Lorenzen Created. *
  1461. * *
  1462. *========================================================================*/
  1463. #define MAX_VOLUME_PARTICLE_DEPTH ( 16 )
  1464. void PointGroupClass::RenderVolumeParticle(RenderInfoClass &rinfo, unsigned int depth )
  1465. {
  1466. if ( depth <= 1 ) //oops,wrong number
  1467. {
  1468. Render( rinfo );
  1469. return;
  1470. }
  1471. if ( depth > MAX_VOLUME_PARTICLE_DEPTH )
  1472. depth = MAX_VOLUME_PARTICLE_DEPTH; // sanity
  1473. Shader.Set_Cull_Mode(ShaderClass::CULL_MODE_DISABLE);
  1474. if (PointCount == 0)
  1475. return;
  1476. WWASSERT(PointLoc && PointLoc->Get_Array());
  1477. // Pointers which point into existing buffers (member or static):
  1478. Vector3 *current_loc = NULL;
  1479. Vector4 *current_diffuse = NULL;
  1480. float *current_size = NULL;
  1481. unsigned char *current_orient = NULL;
  1482. unsigned char *current_frame = NULL;
  1483. // If there is a color or alpha array enable gradient in shader - otherwise disable.
  1484. float value_255 = 0.9961f; //254 / 255
  1485. bool default_white_opaque = ( DefaultPointColor.X > value_255 &&
  1486. DefaultPointColor.Y > value_255 &&
  1487. DefaultPointColor.Z > value_255 &&
  1488. DefaultPointAlpha > value_255);
  1489. // The reason we check for lack of texture here is that SR seems to render black triangles
  1490. // rather than white triangles as would be expected) when there is no texture AND no gradient.
  1491. if (PointDiffuse || !default_white_opaque || !Texture) {
  1492. Shader.Set_Primary_Gradient(ShaderClass::GRADIENT_MODULATE);
  1493. } else {
  1494. Shader.Set_Primary_Gradient(ShaderClass::GRADIENT_DISABLE);
  1495. }
  1496. // If Texture is non-NULL enable texturing in shader - otherwise disable.
  1497. if (Texture) {
  1498. Shader.Set_Texturing(ShaderClass::TEXTURING_ENABLE);
  1499. } else {
  1500. Shader.Set_Texturing(ShaderClass::TEXTURING_DISABLE);
  1501. }
  1502. // Get the world and view matrices
  1503. Matrix4 view;
  1504. DX8Wrapper::Get_Transform(D3DTS_VIEW,view);
  1505. //// VOLUME_PARTICLE LOOP ///////////////
  1506. for ( int t = 0; t < depth; ++t )
  1507. {
  1508. // If there is an active point table, use it to compress the point
  1509. // locations/colors/alphas/sizes/orientations/frames.
  1510. if (APT) {
  1511. // Resize compressed result arrays if needed (2x guardband to prevent
  1512. // frequent reallocations):
  1513. /// @todo lorenzen sez: precompute pointers to indexed array elements, below
  1514. if (compressed_loc.Length() < PointCount) {
  1515. compressed_loc.Resize(PointCount * 2);
  1516. }
  1517. VectorProcessorClass::CopyIndexed(&compressed_loc[0],
  1518. PointLoc->Get_Array(), APT->Get_Array(), PointCount);
  1519. current_loc = &compressed_loc[0];
  1520. if (PointDiffuse) {
  1521. if (compressed_diffuse.Length() < PointCount) {
  1522. compressed_diffuse.Resize(PointCount * 2);
  1523. }
  1524. VectorProcessorClass::CopyIndexed(&compressed_diffuse[0],
  1525. PointDiffuse->Get_Array(), APT->Get_Array(), PointCount);
  1526. current_diffuse = &compressed_diffuse[0];
  1527. }
  1528. if (PointSize) {
  1529. if (compressed_size.Length() < PointCount) {
  1530. compressed_size.Resize(PointCount * 2);
  1531. }
  1532. VectorProcessorClass::CopyIndexed(&compressed_size[0],
  1533. PointSize->Get_Array(), APT->Get_Array(), PointCount);
  1534. current_size = &compressed_size[0];
  1535. }
  1536. if (PointOrientation) {
  1537. if (compressed_orient.Length() < PointCount) {
  1538. compressed_orient.Resize(PointCount * 2);
  1539. }
  1540. VectorProcessorClass::CopyIndexed(&compressed_orient[0],
  1541. PointOrientation->Get_Array(), APT->Get_Array(), PointCount);
  1542. current_orient = &compressed_orient[0];
  1543. }
  1544. if (PointFrame) {
  1545. if (compressed_frame.Length() < PointCount) {
  1546. compressed_frame.Resize(PointCount * 2);
  1547. }
  1548. VectorProcessorClass::CopyIndexed(&compressed_frame[0],
  1549. PointFrame->Get_Array(), APT->Get_Array(), PointCount);
  1550. current_frame = &compressed_frame[0];
  1551. }
  1552. } else {
  1553. current_loc = PointLoc->Get_Array();
  1554. if (PointDiffuse) {
  1555. current_diffuse = PointDiffuse->Get_Array();
  1556. }
  1557. if (PointSize) {
  1558. current_size = PointSize->Get_Array();
  1559. }
  1560. if (PointOrientation) {
  1561. current_orient = PointOrientation->Get_Array();
  1562. }
  1563. if (PointFrame) {
  1564. current_frame = PointFrame->Get_Array();
  1565. }
  1566. }
  1567. // Transform the point locations from worldspace to camera space if needed
  1568. // (i.e. if they are not already in camera space):
  1569. // need to interrupt this processing. If we are not billboarding, then we need the actual position
  1570. // of the vertice to lay it down flat.
  1571. if (Get_Flag(TRANSFORM) && Billboard) {
  1572. // Resize transformed location array if needed (2x guardband to prevent
  1573. // frequent reallocations):
  1574. if (transformed_loc.Length() < PointCount) {
  1575. transformed_loc.Resize(PointCount * 2);
  1576. }
  1577. // Not using vector processor class because we are discarding w
  1578. // Not using T&L in DX8 because we don't want DX8 to transform
  1579. // 3 times per particle when we can do it once
  1580. float recipDepth = 0.1f / (float)depth;
  1581. float shiftInc = ( t * *current_size * recipDepth );
  1582. Vector3 volumeLayerShift;
  1583. Vector3 cameraPosition = rinfo.Camera.Get_Position();
  1584. for (int i=0; i<PointCount; i++)
  1585. {
  1586. /// @todo lorenzen sez: use pointer arithmetic here and a fast while loop
  1587. Vector3 cameraToPointDelta;
  1588. Vector3::Subtract( cameraPosition, current_loc[i], &cameraToPointDelta );
  1589. cameraToPointDelta.Normalize();
  1590. cameraToPointDelta.X *= shiftInc;
  1591. cameraToPointDelta.Y *= shiftInc;
  1592. cameraToPointDelta.Z *= shiftInc;
  1593. Vector3 temp;
  1594. temp.X = current_loc[i].X + cameraToPointDelta.X;
  1595. temp.Y = current_loc[i].Y + cameraToPointDelta.Y;
  1596. temp.Z = current_loc[i].Z + cameraToPointDelta.Z;
  1597. Vector4 result= view * temp;
  1598. transformed_loc[i].X=result.X;
  1599. transformed_loc[i].Y=result.Y;
  1600. transformed_loc[i].Z=result.Z;
  1601. }
  1602. current_loc = &transformed_loc[0];
  1603. } // if transform
  1604. // Update the arrays with the offsets.
  1605. int vnum, pnum;
  1606. //float attenuator = 1.0f - (1.0f/(float)depth);
  1607. //current_diffuse->X *= attenuator;
  1608. //current_diffuse->Y *= attenuator;
  1609. //current_diffuse->Z *= attenuator;
  1610. //current_diffuse->W *= attenuator;
  1611. Update_Arrays(current_loc, current_diffuse, current_size, current_orient, current_frame,
  1612. PointCount, PointLoc->Get_Count(), vnum, pnum);
  1613. // the locations are now in view space
  1614. // so set world and view matrices to identity and render
  1615. Matrix4 identity(true);
  1616. DX8Wrapper::Set_Transform(D3DTS_WORLD,identity);
  1617. DX8Wrapper::Set_Transform(D3DTS_VIEW,identity);
  1618. DX8Wrapper::Set_Material(PointMaterial);
  1619. DX8Wrapper::Set_Shader(Shader);
  1620. DX8Wrapper::Set_Texture(0,Texture);
  1621. // Enable sorting if the primitives are translucent and alpha testing is not enabled.
  1622. const bool sort = (Shader.Get_Dst_Blend_Func() != ShaderClass::DSTBLEND_ZERO) && (Shader.Get_Alpha_Test() == ShaderClass::ALPHATEST_DISABLE) && (WW3D::Is_Sorting_Enabled());
  1623. IndexBufferClass *indexbuffer;
  1624. int verticesperprimitive;/// lorenzen fixed
  1625. int current;
  1626. int delta;
  1627. /// @todo lorenzen sez: if tri-based particles are not supported, elim this test
  1628. if (PointMode == QUADS) {
  1629. verticesperprimitive = 2;
  1630. indexbuffer = sort ? static_cast <IndexBufferClass*> (SortingQuads) : static_cast <IndexBufferClass*> (Quads);
  1631. } else {
  1632. verticesperprimitive = 3;
  1633. indexbuffer = sort ? static_cast <IndexBufferClass*> (SortingTris) : static_cast <IndexBufferClass*> (Tris);
  1634. }
  1635. float nudge = 0;
  1636. current = 0;
  1637. while (current<vnum)
  1638. {
  1639. delta=MIN(vnum-current,MAX_VB_SIZE);
  1640. DynamicVBAccessClass PointVerts (sort ? BUFFER_TYPE_DYNAMIC_SORTING : BUFFER_TYPE_DYNAMIC_DX8, dynamic_fvf_type, delta);
  1641. // Copy in the data to the VB
  1642. {
  1643. DynamicVBAccessClass::WriteLockClass Lock(&PointVerts);
  1644. int i;
  1645. unsigned char *vb=(unsigned char*)Lock.Get_Formatted_Vertex_Array();
  1646. const FVFInfoClass& fvfinfo = PointVerts.FVF_Info();
  1647. for (i = current; i < current + delta; i++)
  1648. {
  1649. /// @todo lorenzen sez: use pointer arithmetic throughout this block
  1650. /// @todo lorenzen sez: delare thes locals outside this loop
  1651. /// @todo lorenzen sez: use a fast while loop
  1652. // Copy Locations
  1653. *(Vector3*)(vb+fvfinfo.Get_Location_Offset()) = VertexLoc[i];
  1654. if (current_diffuse) {
  1655. unsigned color=DX8Wrapper::Convert_Color_Clamp(VertexDiffuse[i]);
  1656. *(unsigned int*)(vb+fvfinfo.Get_Diffuse_Offset())=color;
  1657. }
  1658. else
  1659. *(unsigned int*)(vb+fvfinfo.Get_Diffuse_Offset())=
  1660. DX8Wrapper::Convert_Color_Clamp(Vector4(DefaultPointColor[0],DefaultPointColor[1],DefaultPointColor[2],DefaultPointAlpha));
  1661. *(Vector2*)(vb+fvfinfo.Get_Tex_Offset(0))=VertexUV[i];
  1662. vb+=fvfinfo.Get_FVF_Size();
  1663. }
  1664. } // copy
  1665. DX8Wrapper::Set_Index_Buffer (indexbuffer, 0);
  1666. DX8Wrapper::Set_Vertex_Buffer (PointVerts);
  1667. /// @todo lorenzen sez: precompute these params, above
  1668. if ( sort )
  1669. SortingRendererClass::Insert_Triangles (0, delta / verticesperprimitive, 0, delta);
  1670. else
  1671. DX8Wrapper::Draw_Triangles (0, delta / verticesperprimitive, 0, delta);
  1672. current+=delta;
  1673. } // loop while (current<vnum)
  1674. }// next volume layer
  1675. // restore the matrices
  1676. DX8Wrapper::Set_Transform(D3DTS_VIEW,view);
  1677. }