linegrp.cpp 14 KB

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