pointgr.cpp 81 KB

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