linegrp.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Linegroup.cpp *
  23. * *
  24. * $Archive:: /VSS_Sync/ww3d2/linegrp.cpp $*
  25. * *
  26. * Original Author:: Hector Yee *
  27. * *
  28. * $Author:: Vss_sync $*
  29. * *
  30. * $Modtime:: 10/26/01 3:12p $*
  31. * *
  32. * $Revision:: 1 $*
  33. * *
  34. *---------------------------------------------------------------------------------------------*
  35. * Functions: *
  36. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  37. #include "sharebuf.h"
  38. #include "linegrp.h"
  39. #include "texture.h"
  40. #include "vertmaterial.h"
  41. #include "dx8wrapper.h"
  42. #include "wwmath.h"
  43. #include "rinfo.h"
  44. #include "camera.h"
  45. #include "dx8indexbuffer.h"
  46. #include "dx8vertexbuffer.h"
  47. #include "sortingrenderer.h"
  48. // Line groups are a rendering primitive similar to point groups
  49. // They are tetrahedra which are aligned with the view plane with their centers
  50. // at StartLineLoc. The apex of the tetrahedron is at EndLineLoc.
  51. // They can be individually colored LineDiffuse
  52. // and the LineUCoord determines the U coordinate of the texture to use
  53. // the V coordinate is always 0 at the flat end of the tetrahedron
  54. // and 1 at the apex
  55. LineGroupClass::LineGroupClass(void) :
  56. StartLineLoc(NULL),
  57. EndLineLoc(NULL),
  58. LineDiffuse(NULL),
  59. TailDiffuse(NULL),
  60. ALT(NULL),
  61. LineSize(NULL),
  62. LineUCoord(NULL),
  63. LineCount(0),
  64. Texture(NULL),
  65. Flags(0),
  66. Shader(ShaderClass::_PresetAdditiveSpriteShader),
  67. DefaultLineSize(0.0f),
  68. DefaultLineColor(1.0f, 1.0f, 1.0f),
  69. DefaultLineAlpha(1.0f),
  70. DefaultLineUCoord(0.0f),
  71. DefaultTailDiffuse(0.0f, 0.0f, 0.0f, 0.0f),
  72. LineMode(TETRAHEDRON)
  73. {
  74. }
  75. LineGroupClass::~LineGroupClass(void)
  76. {
  77. REF_PTR_RELEASE(StartLineLoc);
  78. REF_PTR_RELEASE(EndLineLoc);
  79. REF_PTR_RELEASE(LineDiffuse);
  80. REF_PTR_RELEASE(TailDiffuse);
  81. REF_PTR_RELEASE(ALT);
  82. REF_PTR_RELEASE(LineSize);
  83. REF_PTR_RELEASE(LineUCoord);
  84. REF_PTR_RELEASE(Texture);
  85. }
  86. void LineGroupClass::Set_Arrays(
  87. ShareBufferClass<Vector3> *startlocs,
  88. ShareBufferClass<Vector3> *endlocs,
  89. ShareBufferClass<Vector4> *diffuse,
  90. ShareBufferClass<Vector4> *taildiffuse,
  91. ShareBufferClass<unsigned int> *alt,
  92. ShareBufferClass<float> *sizes,
  93. ShareBufferClass<float> *ucoords,
  94. int active_line_count
  95. )
  96. {
  97. // The Line locations arrays are NOT optional!
  98. WWASSERT(startlocs);
  99. WWASSERT(endlocs);
  100. // Ensure lengths of all arrays are the same:
  101. WWASSERT(startlocs->Get_Count() == endlocs->Get_Count());
  102. WWASSERT(!diffuse || startlocs->Get_Count() == diffuse->Get_Count());
  103. WWASSERT(!alt || startlocs->Get_Count() == alt->Get_Count());
  104. WWASSERT(!sizes || startlocs->Get_Count() == sizes->Get_Count());
  105. WWASSERT(!ucoords || startlocs->Get_Count() == ucoords->Get_Count());
  106. WWASSERT(!taildiffuse || startlocs->Get_Count() == taildiffuse->Get_Count());
  107. REF_PTR_SET(StartLineLoc,startlocs);
  108. REF_PTR_SET(EndLineLoc,endlocs);
  109. REF_PTR_SET(LineDiffuse,diffuse);
  110. REF_PTR_SET(TailDiffuse,taildiffuse);
  111. REF_PTR_SET(ALT,alt);
  112. REF_PTR_SET(LineSize,sizes);
  113. REF_PTR_SET(LineUCoord,ucoords);
  114. if (ALT) {
  115. LineCount = active_line_count;
  116. } else {
  117. LineCount = (active_line_count >= 0) ? active_line_count : StartLineLoc->Get_Count();
  118. }
  119. }
  120. void LineGroupClass::Set_Line_Size(float size)
  121. {
  122. DefaultLineSize = size;
  123. }
  124. float LineGroupClass::Get_Line_Size(void)
  125. {
  126. return DefaultLineSize;
  127. }
  128. void LineGroupClass::Set_Line_Color(const Vector3 &color)
  129. {
  130. DefaultLineColor = color;
  131. }
  132. Vector3 LineGroupClass::Get_Line_Color(void)
  133. {
  134. return DefaultLineColor;
  135. }
  136. void LineGroupClass::Set_Tail_Diffuse(const Vector4 &tdiffuse)
  137. {
  138. DefaultTailDiffuse = tdiffuse;
  139. }
  140. Vector4 LineGroupClass::Get_Tail_Diffuse(void)
  141. {
  142. return DefaultTailDiffuse;
  143. }
  144. void LineGroupClass::Set_Line_Alpha(float alpha)
  145. {
  146. DefaultLineAlpha = alpha;
  147. }
  148. float LineGroupClass::Get_Line_Alpha(void)
  149. {
  150. return DefaultLineAlpha;
  151. }
  152. void LineGroupClass::Set_Line_UCoord(float ucoord)
  153. {
  154. DefaultLineUCoord = ucoord;
  155. }
  156. float LineGroupClass::Get_Line_UCoord(void)
  157. {
  158. return DefaultLineUCoord;
  159. }
  160. void LineGroupClass::Set_Flag(FlagsType flag, bool on)
  161. {
  162. if (on) Flags |= 1 << flag;
  163. else
  164. Flags &= ~(1 << flag);
  165. }
  166. int LineGroupClass::Get_Flag(FlagsType flag)
  167. {
  168. return (Flags >> flag) & 0x1;
  169. }
  170. void LineGroupClass::Set_Texture(TextureClass* texture)
  171. {
  172. REF_PTR_SET(Texture,texture);
  173. }
  174. TextureClass * LineGroupClass::Get_Texture(void)
  175. {
  176. if (Texture) Texture->Add_Ref();
  177. return Texture;
  178. }
  179. TextureClass * LineGroupClass::Peek_Texture(void)
  180. {
  181. return Texture;
  182. }
  183. void LineGroupClass::Set_Shader(const ShaderClass &shader)
  184. {
  185. Shader = shader;
  186. }
  187. ShaderClass LineGroupClass::Get_Shader(void)
  188. {
  189. return Shader;
  190. }
  191. void LineGroupClass::Set_Line_Mode(LineModeType linemode)
  192. {
  193. LineMode = linemode;
  194. }
  195. LineGroupClass::LineModeType LineGroupClass::Get_Line_Mode(void)
  196. {
  197. return LineMode;
  198. }
  199. void LineGroupClass::Render(RenderInfoClass &rinfo)
  200. {
  201. int i;
  202. // If no lines, do nothing:
  203. if (LineCount == 0) return;
  204. // Shader handling
  205. Shader.Set_Cull_Mode(ShaderClass::CULL_MODE_ENABLE);
  206. // If there is a color or alpha array enable gradient in shader - otherwise disable.
  207. float value_255 = 0.9961f; //254 / 255
  208. bool default_white_opaque = ( DefaultLineColor.X > value_255 &&
  209. DefaultLineColor.Y > value_255 &&
  210. DefaultLineColor.Z > value_255 &&
  211. DefaultLineAlpha > value_255);
  212. if (LineDiffuse || !default_white_opaque || !Texture) {
  213. Shader.Set_Primary_Gradient(ShaderClass::GRADIENT_MODULATE);
  214. } else {
  215. Shader.Set_Primary_Gradient(ShaderClass::GRADIENT_DISABLE);
  216. }
  217. // If Texture is non-NULL enable texturing in shader - otherwise disable.
  218. if (Texture) {
  219. Shader.Set_Texturing(ShaderClass::TEXTURING_ENABLE);
  220. } else {
  221. Shader.Set_Texturing(ShaderClass::TEXTURING_DISABLE);
  222. }
  223. VertexMaterialClass * linemat = VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE);
  224. DX8Wrapper::Set_Material(linemat);
  225. DX8Wrapper::Set_Shader(Shader);
  226. DX8Wrapper::Set_Texture(0, Texture);
  227. REF_PTR_RELEASE(linemat);
  228. WWASSERT(StartLineLoc && StartLineLoc->Get_Array());
  229. WWASSERT(EndLineLoc && EndLineLoc->Get_Array());
  230. // Enable sorting if the primitives are translucent and alpha testing is not enabled.
  231. const bool sort = (Shader.Get_Dst_Blend_Func() != ShaderClass::DSTBLEND_ZERO) && (Shader.Get_Alpha_Test() == ShaderClass::ALPHATEST_DISABLE) && (WW3D::Is_Sorting_Enabled());
  232. // the 3 offsets in view space
  233. const static Vector3 offset_a = Vector3(WWMath::Cos(WWMATH_PI / 2), WWMath::Sin(WWMATH_PI /2 ), 0);
  234. const static Vector3 offset_b = Vector3(WWMath::Cos(7 * WWMATH_PI / 6), WWMath::Sin(7 * WWMATH_PI / 6), 0);
  235. const static Vector3 offset_c = Vector3(WWMath::Cos(11 * WWMATH_PI / 6), WWMath::Sin(11 * WWMATH_PI / 6), 0);
  236. static Vector3 offset[3];
  237. offset[0].Set(offset_a);
  238. offset[1].Set(offset_b);
  239. offset[2].Set(offset_c);
  240. // Save off the view matrix
  241. Matrix4 view;
  242. DX8Wrapper::Get_Transform(D3DTS_VIEW, view);
  243. Matrix4 identity(true);
  244. DX8Wrapper::Set_Transform(D3DTS_WORLD, identity);
  245. // if the points are in world space, transform the offsets
  246. if (Get_Flag(TRANSFORM)) {
  247. Matrix3D xform_mat;
  248. xform_mat = rinfo.Camera.Get_Transform();
  249. xform_mat.Set_Translation(Vector3(0, 0, 0));
  250. xform_mat.Get_Orthogonal_Inverse(xform_mat);
  251. for (i = 0; i < 3; i++) {
  252. Matrix3D::Transform_Vector(xform_mat, offset[i], &offset[i]);
  253. }
  254. } else {
  255. DX8Wrapper::Set_Transform(D3DTS_VIEW, identity);
  256. }
  257. int num_tris=0;
  258. int num_indices=0;
  259. int num_vertices=0;
  260. switch (LineMode) {
  261. case TETRAHEDRON:
  262. num_tris =4 * LineCount;
  263. num_indices =3 * num_tris;
  264. num_vertices =4 * LineCount;
  265. break;
  266. case PRISM:
  267. num_tris =8 * LineCount;
  268. num_indices =3 * num_tris;
  269. num_vertices =6 * LineCount;
  270. break;
  271. }
  272. // construct the tetrahedra in the index buffers
  273. // assume first vertex is the apex, followed by offset[0-3]
  274. DynamicIBAccessClass iba(sort?BUFFER_TYPE_DYNAMIC_SORTING:BUFFER_TYPE_DYNAMIC_DX8,num_indices);
  275. {
  276. DynamicIBAccessClass::WriteLockClass lock(&iba);
  277. unsigned short *ibptr = lock.Get_Index_Array();
  278. unsigned short j, idx;
  279. switch (LineMode) {
  280. case TETRAHEDRON:
  281. for (j=0; j<LineCount; j++) {
  282. idx = 4 * j;
  283. // apex, offset[1], offset[0]
  284. *ibptr++ = idx + 0;
  285. *ibptr++ = idx + 2;
  286. *ibptr++ = idx + 1;
  287. // apex, offset[2], offset[1]
  288. *ibptr++ = idx + 0;
  289. *ibptr++ = idx + 3;
  290. *ibptr++ = idx + 2;
  291. // apex, offset[0], offset[2]
  292. *ibptr++ = idx + 0;
  293. *ibptr++ = idx + 1;
  294. *ibptr++ = idx + 3;
  295. // offset[0-3]
  296. *ibptr++ = idx + 1;
  297. *ibptr++ = idx + 2;
  298. *ibptr++ = idx + 3;
  299. }
  300. break;
  301. case PRISM:
  302. for (j=0; j<LineCount; j++) {
  303. idx = 6 * j;
  304. // starting cap 0,1,2
  305. *ibptr++ = idx + 0;
  306. *ibptr++ = idx + 1;
  307. *ibptr++ = idx + 2;
  308. // left side
  309. *ibptr++ = idx + 0;
  310. *ibptr++ = idx + 3;
  311. *ibptr++ = idx + 1;
  312. *ibptr++ = idx + 1;
  313. *ibptr++ = idx + 3;
  314. *ibptr++ = idx + 4;
  315. // bottom side
  316. *ibptr++ = idx + 1;
  317. *ibptr++ = idx + 4;
  318. *ibptr++ = idx + 5;
  319. *ibptr++ = idx + 1;
  320. *ibptr++ = idx + 5;
  321. *ibptr++ = idx + 2;
  322. // right side
  323. *ibptr++ = idx + 0;
  324. *ibptr++ = idx + 2;
  325. *ibptr++ = idx + 5;
  326. *ibptr++ = idx + 0;
  327. *ibptr++ = idx + 5;
  328. *ibptr++ = idx + 3;
  329. // end cap
  330. *ibptr++ = idx + 3;
  331. *ibptr++ = idx + 5;
  332. *ibptr++ = idx + 4;
  333. }
  334. break;
  335. }
  336. } // writing to ib
  337. // make the vertex buffers
  338. DynamicVBAccessClass vba(sort ? BUFFER_TYPE_DYNAMIC_SORTING : BUFFER_TYPE_DYNAMIC_DX8,dynamic_fvf_type,num_vertices);
  339. {
  340. DynamicVBAccessClass::WriteLockClass lock(&vba);
  341. VertexFormatXYZNDUV2 *vb = lock.Get_Formatted_Vertex_Array();
  342. Vector3 loc, start, end;
  343. int point, j;
  344. float size = DefaultLineSize;
  345. Vector4 diffuse(DefaultLineColor.X, DefaultLineColor.Y, DefaultLineColor.Z, DefaultLineAlpha);
  346. float ucoord = DefaultLineUCoord;
  347. Vector4 taildiffuse = DefaultTailDiffuse;
  348. for (i = 0; i < LineCount; i++)
  349. {
  350. point = (ALT) ? ALT->Get_Element(i) : i;
  351. if (LineSize) size = LineSize->Get_Element(point);
  352. if (LineDiffuse) diffuse = LineDiffuse->Get_Element(point);
  353. if (LineUCoord) ucoord = LineUCoord->Get_Element(point);
  354. if (TailDiffuse) taildiffuse = TailDiffuse->Get_Element(point);
  355. end.Set(EndLineLoc->Get_Element(point));
  356. start.Set(StartLineLoc->Get_Element(point));
  357. switch (LineMode) {
  358. case TETRAHEDRON:
  359. // apex
  360. vb->x = end.X;
  361. vb->y = end.Y;
  362. vb->z = end.Z;
  363. vb->diffuse = DX8Wrapper::Convert_Color(taildiffuse);
  364. vb->u1 = ucoord;
  365. vb->v1 = 1.0f;
  366. vb++;
  367. for (j=0; j<3; j++) {
  368. loc.Set(start + size * offset[j]);
  369. vb->x = loc.X;
  370. vb->y = loc.Y;
  371. vb->z = loc.Z;
  372. vb->diffuse = DX8Wrapper::Convert_Color(diffuse);
  373. vb->u1 = ucoord;
  374. vb->v1 = 0.0f;
  375. vb++;
  376. }
  377. break;
  378. case PRISM:
  379. // start cap
  380. for (j = 0; j < 3; j++) {
  381. loc.Set(start + size * offset[j]);
  382. vb->x = loc.X;
  383. vb->y = loc.Y;
  384. vb->z = loc.Z;
  385. vb->diffuse = DX8Wrapper::Convert_Color(diffuse);
  386. vb->u1 = ucoord;
  387. vb->v1 = 0.0f;
  388. vb++;
  389. }
  390. // Do not merge loops. The vb has to be written in a specific order
  391. // (This is to optimize AGP memory write)
  392. // end cap
  393. for (j=0; j<3; j++) {
  394. loc.Set(end + size * offset[j]);
  395. vb->x = loc.X;
  396. vb->y = loc.Y;
  397. vb->z = loc.Z;
  398. vb->diffuse = DX8Wrapper::Convert_Color(taildiffuse);
  399. vb->u1 = ucoord;
  400. vb->v1 = 1.0f;
  401. vb++;
  402. }
  403. break;
  404. }
  405. }
  406. } // writing to vb
  407. DX8Wrapper::Set_Index_Buffer(iba, 0);
  408. DX8Wrapper::Set_Vertex_Buffer(vba);
  409. if (sort) {
  410. SortingRendererClass::Insert_Triangles(0, num_tris, 0, num_vertices);
  411. } else {
  412. DX8Wrapper::Draw_Triangles(0, num_tris, 0, num_vertices);
  413. }
  414. // restore the matrices
  415. DX8Wrapper::Set_Transform(D3DTS_VIEW, view);
  416. }
  417. int LineGroupClass::Get_Polygon_Count(void)
  418. {
  419. switch (LineMode) {
  420. case TETRAHEDRON:
  421. return LineCount * 4;
  422. break;
  423. case PRISM:
  424. return LineCount * 8;
  425. break;
  426. }
  427. WWASSERT(0);
  428. return 0;
  429. }