sortingrenderer.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752
  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 : ww3d *
  23. * *
  24. * $Archive:: /Commando/Code/ww3d2/sortingrenderer.cpp $*
  25. * *
  26. * Original Author:: Greg Hjelstrom *
  27. * *
  28. * Author : Kenny Mitchell *
  29. * *
  30. * $Modtime:: 06/27/02 1:27p $*
  31. * *
  32. * $Revision:: 2 $*
  33. * *
  34. * 06/26/02 KM Matrix name change to avoid MAX conflicts *
  35. * 06/27/02 KM Changes to max texture stage caps *
  36. *---------------------------------------------------------------------------------------------*
  37. * Functions: *
  38. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  39. #include "sortingrenderer.h"
  40. #include "dx8vertexbuffer.h"
  41. #include "dx8indexbuffer.h"
  42. #include "dx8wrapper.h"
  43. #include "vertmaterial.h"
  44. #include "texture.h"
  45. #include "d3d8.h"
  46. #include "D3dx8math.h"
  47. #include "statistics.h"
  48. #include <wwprofile.h>
  49. #include <algorithm>
  50. #ifdef _INTERNAL
  51. // for occasional debugging...
  52. // #pragma optimize("", off)
  53. // #pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  54. #endif
  55. bool SortingRendererClass::_EnableTriangleDraw=true;
  56. static unsigned DEFAULT_SORTING_POLY_COUNT = 16384; // (count * 3) must be less than 65536
  57. static unsigned DEFAULT_SORTING_VERTEX_COUNT = 32768; // count must be less than 65536
  58. void SortingRendererClass::SetMinVertexBufferSize( unsigned val )
  59. {
  60. DEFAULT_SORTING_VERTEX_COUNT = val;
  61. DEFAULT_SORTING_POLY_COUNT = val/2; //typically have 2:1 vertex:triangle ratio.
  62. }
  63. struct ShortVectorIStruct
  64. {
  65. unsigned short i;
  66. unsigned short j;
  67. unsigned short k;
  68. };
  69. struct TempIndexStruct
  70. {
  71. ShortVectorIStruct tri;
  72. unsigned short idx;
  73. float z;
  74. };
  75. bool operator <(const TempIndexStruct &l, const TempIndexStruct &r) { return l.z < r.z; }
  76. bool operator <=(const TempIndexStruct &l, const TempIndexStruct &r) { return l.z <= r.z; }
  77. bool operator >(const TempIndexStruct &l, const TempIndexStruct &r) { return l.z > r.z; }
  78. bool operator >=(const TempIndexStruct &l, const TempIndexStruct &r) { return l.z >= r.z; }
  79. bool operator ==(const TempIndexStruct &l, const TempIndexStruct &r) { return l.z == r.z; }
  80. // ----------------------------------------------------------------------------
  81. static
  82. void InsertionSort(TempIndexStruct *begin, TempIndexStruct *end)
  83. {
  84. for (TempIndexStruct *iter = begin + 1; iter < end; ++iter) {
  85. TempIndexStruct val = iter[0];
  86. TempIndexStruct *insert = iter;
  87. while (insert != begin && insert[-1] > val) {
  88. insert[0] = insert[-1];
  89. insert -= 1;
  90. }
  91. insert[0] = val;
  92. }
  93. }
  94. // ----------------------------------------------------------------------------
  95. static
  96. void Sort(TempIndexStruct *begin, TempIndexStruct *end)
  97. {
  98. const int diff = end - begin;
  99. if (diff <= 16) {
  100. // Insertion sort has less overhead for small arrays
  101. InsertionSort(begin, end);
  102. } else {
  103. // Choose the median of begin, mid, and (end - 1) as the partitioning element.
  104. // Rearrange so that *(begin + 1) <= *begin <= *(end - 1). These will be guard
  105. // elements.
  106. TempIndexStruct *mid = begin + diff/2;
  107. std::swap(mid[0], begin[1]);
  108. if (begin[1] > end[-1]) {
  109. std::swap(begin[1], end[-1]);
  110. }
  111. if (begin[0] > end[-1]) {
  112. std::swap(begin[0], end[-1]);
  113. } // end[-1] has the largest element
  114. if (begin[1] > begin[0]) {
  115. std::swap(begin[1], begin[0]);
  116. } // begin[0] has the middle element and begin[1] has the smallest element
  117. // *begin is now the partitioning element
  118. TempIndexStruct *begin1 = begin + 1; // TODO: Temp fix until I find out who is passing me NaN
  119. TempIndexStruct *end1 = end - 1; // TODO: Temp fix until I find out who is passing me NaN
  120. TempIndexStruct *left = begin + 1;
  121. TempIndexStruct *right = end - 1;
  122. for (;;) {
  123. #if 0 // TODO: Temp fix until I find out who is passing me NaN.
  124. do ++left; while (left[0] < begin[0]); // Scan up to find element >= than partition
  125. do --right; while (right[0] > begin[0]); // Scan down to find element <= than partition
  126. #else
  127. do ++left; while (left < end1 && left[0] < begin[0]); // Scan up to find element >= than partition
  128. do --right; while (right > begin1 && right[0] > begin[0]); // Scan down to find element <= than partition
  129. #endif
  130. if (right < left) break; // Pointers crossed. Partitioning completed.
  131. std::swap(left[0], right[0]); // Exchange elements.
  132. }
  133. std::swap(begin[0], right[0]); // Insert partition element
  134. // Sort the smaller subarray first then the larger
  135. if (right - begin > end - (right + 1)) {
  136. Sort(right + 1, end);
  137. Sort(begin, right);
  138. } else {
  139. Sort(begin, right);
  140. Sort(right + 1, end);
  141. }
  142. }
  143. }
  144. // ----------------------------------------------------------------------------
  145. class SortingNodeStruct : public DLNodeClass<SortingNodeStruct>
  146. {
  147. W3DMPO_GLUE(SortingNodeStruct)
  148. public:
  149. RenderStateStruct sorting_state;
  150. SphereClass bounding_sphere;
  151. Vector3 transformed_center;
  152. unsigned short start_index; // First index used in the ib
  153. unsigned short polygon_count; // Polygon count to process (3 indices = one polygon)
  154. unsigned short min_vertex_index; // First index used in the vb
  155. unsigned short vertex_count; // Number of vertices used in vb
  156. };
  157. static DLListClass<SortingNodeStruct> sorted_list;
  158. static DLListClass<SortingNodeStruct> clean_list;
  159. static unsigned total_sorting_vertices;
  160. static SortingNodeStruct* Get_Sorting_Struct()
  161. {
  162. SortingNodeStruct* state=clean_list.Head();
  163. if (state) {
  164. state->Remove();
  165. return state;
  166. }
  167. state=W3DNEW SortingNodeStruct();
  168. return state;
  169. }
  170. // ----------------------------------------------------------------------------
  171. //
  172. // Temporary arrays for the sorting system
  173. //
  174. // ----------------------------------------------------------------------------
  175. static TempIndexStruct* temp_index_array;
  176. static unsigned temp_index_array_count;
  177. static TempIndexStruct* Get_Temp_Index_Array(unsigned count)
  178. {
  179. if (count < DEFAULT_SORTING_POLY_COUNT)
  180. count = DEFAULT_SORTING_POLY_COUNT;
  181. if (count>temp_index_array_count) {
  182. delete[] temp_index_array;
  183. temp_index_array=W3DNEWARRAY TempIndexStruct[count];
  184. temp_index_array_count=count;
  185. }
  186. return temp_index_array;
  187. }
  188. // ----------------------------------------------------------------------------
  189. //
  190. // Insert triangles to the sorting system.
  191. //
  192. // ----------------------------------------------------------------------------
  193. void SortingRendererClass::Insert_Triangles(
  194. const SphereClass& bounding_sphere,
  195. unsigned short start_index,
  196. unsigned short polygon_count,
  197. unsigned short min_vertex_index,
  198. unsigned short vertex_count)
  199. {
  200. if (!WW3D::Is_Sorting_Enabled()) {
  201. DX8Wrapper::Draw_Triangles(start_index,polygon_count,min_vertex_index,vertex_count);
  202. return;
  203. }
  204. SNAPSHOT_SAY(("SortingRenderer::Insert(start_i: %d, polygons : %d, min_vi: %d, vertex_count: %d)\n",
  205. start_index,polygon_count,min_vertex_index,vertex_count));
  206. DX8_RECORD_SORTING_RENDER(polygon_count,vertex_count);
  207. SortingNodeStruct* state=Get_Sorting_Struct();
  208. DX8Wrapper::Get_Render_State(state->sorting_state);
  209. WWASSERT(
  210. ((state->sorting_state.index_buffer_type==BUFFER_TYPE_SORTING || state->sorting_state.index_buffer_type==BUFFER_TYPE_DYNAMIC_SORTING) &&
  211. (state->sorting_state.vertex_buffer_types[0]==BUFFER_TYPE_SORTING || state->sorting_state.vertex_buffer_types[0]==BUFFER_TYPE_DYNAMIC_SORTING)));
  212. state->bounding_sphere=bounding_sphere;
  213. state->start_index=start_index;
  214. state->polygon_count=polygon_count;
  215. state->min_vertex_index=min_vertex_index;
  216. state->vertex_count=vertex_count;
  217. SortingVertexBufferClass* vertex_buffer=static_cast<SortingVertexBufferClass*>(state->sorting_state.vertex_buffers[0]);
  218. WWASSERT(vertex_buffer);
  219. WWASSERT(state->vertex_count<=vertex_buffer->Get_Vertex_Count());
  220. D3DXMATRIX mtx=(D3DXMATRIX&)state->sorting_state.world*(D3DXMATRIX&)state->sorting_state.view;
  221. D3DXVECTOR3 vec=(D3DXVECTOR3&)state->bounding_sphere.Center;
  222. D3DXVECTOR4 transformed_vec;
  223. D3DXVec3Transform(
  224. &transformed_vec,
  225. &vec,
  226. &mtx);
  227. state->transformed_center=Vector3(transformed_vec[0],transformed_vec[1],transformed_vec[2]);
  228. /// @todo lorenzen sez use a bucket sort here... and stop copying so much data so many times
  229. SortingNodeStruct* node=sorted_list.Head();
  230. while (node) {
  231. if (state->transformed_center.Z>node->transformed_center.Z) {
  232. if (sorted_list.Head()==sorted_list.Tail())
  233. sorted_list.Add_Head(state);
  234. else
  235. state->Insert_Before(node);
  236. break;
  237. }
  238. node=node->Succ();
  239. }
  240. if (!node) sorted_list.Add_Tail(state);
  241. #ifdef WWDEBUG
  242. unsigned short* indices=NULL;
  243. SortingIndexBufferClass* index_buffer=static_cast<SortingIndexBufferClass*>(state->sorting_state.index_buffer);
  244. WWASSERT(index_buffer);
  245. indices=index_buffer->index_buffer;
  246. WWASSERT(indices);
  247. indices+=state->start_index;
  248. indices+=state->sorting_state.iba_offset;
  249. for (int i=0;i<state->polygon_count;++i) {
  250. unsigned short idx1=indices[i*3]-state->min_vertex_index;
  251. unsigned short idx2=indices[i*3+1]-state->min_vertex_index;
  252. unsigned short idx3=indices[i*3+2]-state->min_vertex_index;
  253. WWASSERT(idx1<state->vertex_count);
  254. WWASSERT(idx2<state->vertex_count);
  255. WWASSERT(idx3<state->vertex_count);
  256. }
  257. #endif // WWDEBUG
  258. }
  259. // ----------------------------------------------------------------------------
  260. //
  261. // Insert triangles to the sorting system, with no bounding information.
  262. //
  263. // ----------------------------------------------------------------------------
  264. void SortingRendererClass::Insert_Triangles(
  265. unsigned short start_index,
  266. unsigned short polygon_count,
  267. unsigned short min_vertex_index,
  268. unsigned short vertex_count)
  269. {
  270. SphereClass sphere(Vector3(0.0f,0.0f,0.0f),0.0f);
  271. Insert_Triangles(sphere,start_index,polygon_count,min_vertex_index,vertex_count);
  272. }
  273. // ----------------------------------------------------------------------------
  274. //
  275. // Flush all sorting polygons.
  276. //
  277. // ----------------------------------------------------------------------------
  278. void Release_Refs(SortingNodeStruct* state)
  279. {
  280. int i;
  281. for (i=0;i<MAX_VERTEX_STREAMS;++i) {
  282. REF_PTR_RELEASE(state->sorting_state.vertex_buffers[i]);
  283. }
  284. REF_PTR_RELEASE(state->sorting_state.index_buffer);
  285. REF_PTR_RELEASE(state->sorting_state.material);
  286. for (i=0;i<DX8Wrapper::Get_Current_Caps()->Get_Max_Textures_Per_Pass();++i)
  287. {
  288. REF_PTR_RELEASE(state->sorting_state.Textures[i]);
  289. }
  290. }
  291. static unsigned overlapping_node_count;
  292. static unsigned overlapping_polygon_count;
  293. static unsigned overlapping_vertex_count;
  294. static const unsigned MAX_OVERLAPPING_NODES=4096;
  295. static SortingNodeStruct* overlapping_nodes[MAX_OVERLAPPING_NODES];
  296. // ----------------------------------------------------------------------------
  297. void SortingRendererClass::Insert_To_Sorting_Pool(SortingNodeStruct* state)
  298. {
  299. if (overlapping_node_count>=MAX_OVERLAPPING_NODES) {
  300. Release_Refs(state);
  301. WWASSERT(0);
  302. return;
  303. }
  304. overlapping_nodes[overlapping_node_count]=state;
  305. overlapping_vertex_count+=state->vertex_count;
  306. overlapping_polygon_count+=state->polygon_count;
  307. overlapping_node_count++;
  308. }
  309. // ----------------------------------------------------------------------------
  310. //static unsigned prevLight = 0xffffffff;
  311. static void Apply_Render_State(RenderStateStruct& render_state)
  312. {
  313. DX8Wrapper::Set_Shader(render_state.shader);
  314. DX8Wrapper::Set_Material(render_state.material);
  315. for (int i=0;i<DX8Wrapper::Get_Current_Caps()->Get_Max_Textures_Per_Pass();++i)
  316. {
  317. DX8Wrapper::Set_Texture(i,render_state.Textures[i]);
  318. }
  319. DX8Wrapper::_Set_DX8_Transform(D3DTS_WORLD,render_state.world);
  320. DX8Wrapper::_Set_DX8_Transform(D3DTS_VIEW,render_state.view);
  321. if (!render_state.material->Get_Lighting())
  322. return;
  323. //prevLight = render_state.lightsHash;
  324. if (render_state.LightEnable[0])
  325. {
  326. DX8Wrapper::Set_DX8_Light(0,&render_state.Lights[0]);
  327. if (render_state.LightEnable[1])
  328. {
  329. DX8Wrapper::Set_DX8_Light(1,&render_state.Lights[1]);
  330. if (render_state.LightEnable[2])
  331. {
  332. DX8Wrapper::Set_DX8_Light(2,&render_state.Lights[2]);
  333. if (render_state.LightEnable[3])
  334. DX8Wrapper::Set_DX8_Light(3,&render_state.Lights[3]);
  335. else
  336. DX8Wrapper::Set_DX8_Light(3,NULL);
  337. }
  338. else
  339. DX8Wrapper::Set_DX8_Light(2,NULL);
  340. }
  341. else
  342. DX8Wrapper::Set_DX8_Light(1,NULL);
  343. }
  344. else
  345. DX8Wrapper::Set_DX8_Light(0,NULL);
  346. }
  347. // ----------------------------------------------------------------------------
  348. void SortingRendererClass::Flush_Sorting_Pool()
  349. {
  350. if (!overlapping_node_count) return;
  351. SNAPSHOT_SAY(("SortingSystem - Flush \n"));
  352. // Fill dynamic index buffer with sorting index buffer vertices
  353. TempIndexStruct* tis=Get_Temp_Index_Array(overlapping_polygon_count);
  354. unsigned vertexAllocCount = overlapping_vertex_count;
  355. if (DynamicVBAccessClass::Get_Default_Vertex_Count() < DEFAULT_SORTING_VERTEX_COUNT)
  356. vertexAllocCount = DEFAULT_SORTING_VERTEX_COUNT; //make sure that we force the DX8 dynamic vertex buffer to maximum size
  357. if (overlapping_vertex_count > vertexAllocCount)
  358. vertexAllocCount = overlapping_vertex_count;
  359. WWASSERT(DEFAULT_SORTING_VERTEX_COUNT == 1 || vertexAllocCount <= DEFAULT_SORTING_VERTEX_COUNT);
  360. DynamicVBAccessClass dyn_vb_access(BUFFER_TYPE_DYNAMIC_DX8,dynamic_fvf_type,vertexAllocCount/*overlapping_vertex_count*/);
  361. {
  362. DynamicVBAccessClass::WriteLockClass lock(&dyn_vb_access);
  363. VertexFormatXYZNDUV2* dest_verts=(VertexFormatXYZNDUV2 *)lock.Get_Formatted_Vertex_Array();
  364. unsigned polygon_array_offset=0;
  365. unsigned vertex_array_offset=0;
  366. for (unsigned node_id=0;node_id<overlapping_node_count;++node_id) {
  367. SortingNodeStruct* state=overlapping_nodes[node_id];
  368. VertexFormatXYZNDUV2* src_verts=NULL;
  369. SortingVertexBufferClass* vertex_buffer=static_cast<SortingVertexBufferClass*>(state->sorting_state.vertex_buffers[0]);
  370. WWASSERT(vertex_buffer);
  371. src_verts=vertex_buffer->VertexBuffer;
  372. WWASSERT(src_verts);
  373. src_verts+=state->sorting_state.vba_offset;
  374. src_verts+=state->sorting_state.index_base_offset;
  375. src_verts+=state->min_vertex_index;
  376. // If you have a crash in here and "dest_verts" points to illegal memory area,
  377. // it is because D3D is in illegal state, and the only known cure is rebooting.
  378. // This illegal state is usually caused by Quake3-engine powered games such as MOHAA.
  379. memcpy(dest_verts, src_verts, sizeof(VertexFormatXYZNDUV2)*state->vertex_count);
  380. dest_verts += state->vertex_count;
  381. D3DXMATRIX d3d_mtx=(D3DXMATRIX&)state->sorting_state.world*(D3DXMATRIX&)state->sorting_state.view;
  382. const Matrix4x4& mtx=(const Matrix4x4&)d3d_mtx;
  383. unsigned short* indices=NULL;
  384. SortingIndexBufferClass* index_buffer=static_cast<SortingIndexBufferClass*>(state->sorting_state.index_buffer);
  385. WWASSERT(index_buffer);
  386. indices=index_buffer->index_buffer;
  387. WWASSERT(indices);
  388. indices+=state->start_index;
  389. indices+=state->sorting_state.iba_offset;
  390. if (mtx[0][2] == 0.0f && mtx[1][2] == 0.0f && mtx[3][2] == 0.0f && mtx[2][2] == 1.0f) {
  391. // The common case for particle systems.
  392. for (int i=0;i<state->polygon_count;++i) {
  393. unsigned short idx1=indices[i*3]-state->min_vertex_index;
  394. unsigned short idx2=indices[i*3+1]-state->min_vertex_index;
  395. unsigned short idx3=indices[i*3+2]-state->min_vertex_index;
  396. WWASSERT(idx1<state->vertex_count);
  397. WWASSERT(idx2<state->vertex_count);
  398. WWASSERT(idx3<state->vertex_count);
  399. const VertexFormatXYZNDUV2 *v1 = src_verts + idx1;
  400. const VertexFormatXYZNDUV2 *v2 = src_verts + idx2;
  401. const VertexFormatXYZNDUV2 *v3 = src_verts + idx3;
  402. unsigned array_index=i+polygon_array_offset;
  403. WWASSERT(array_index<overlapping_polygon_count);
  404. TempIndexStruct *tis_ptr = tis + array_index;
  405. tis_ptr->tri.i = idx1 + vertex_array_offset;
  406. tis_ptr->tri.j = idx2 + vertex_array_offset;
  407. tis_ptr->tri.k = idx3 + vertex_array_offset;
  408. tis_ptr->idx = node_id;
  409. tis_ptr->z = (v1->z + v2->z + v3->z)/3.0f;
  410. DEBUG_ASSERTCRASH((! _isnan(tis_ptr->z) && _finite(tis_ptr->z)), ("Triangle has invalid center"));
  411. }
  412. } else {
  413. for (int i=0;i<state->polygon_count;++i) {
  414. unsigned short idx1=indices[i*3]-state->min_vertex_index;
  415. unsigned short idx2=indices[i*3+1]-state->min_vertex_index;
  416. unsigned short idx3=indices[i*3+2]-state->min_vertex_index;
  417. WWASSERT(idx1<state->vertex_count);
  418. WWASSERT(idx2<state->vertex_count);
  419. WWASSERT(idx3<state->vertex_count);
  420. const VertexFormatXYZNDUV2 *v1 = src_verts + idx1;
  421. const VertexFormatXYZNDUV2 *v2 = src_verts + idx2;
  422. const VertexFormatXYZNDUV2 *v3 = src_verts + idx3;
  423. unsigned array_index=i+polygon_array_offset;
  424. WWASSERT(array_index<overlapping_polygon_count);
  425. TempIndexStruct *tis_ptr = tis + array_index;
  426. tis_ptr->tri.i = idx1 + vertex_array_offset;
  427. tis_ptr->tri.j = idx2 + vertex_array_offset;
  428. tis_ptr->tri.k = idx3 + vertex_array_offset;
  429. tis_ptr->idx = node_id;
  430. tis_ptr->z = (mtx[0][2]*(v1->x + v2->x + v3->x) +
  431. mtx[1][2]*(v1->y + v2->y + v3->y) +
  432. mtx[2][2]*(v1->z + v2->z + v3->z))/3.0f + mtx[3][2];
  433. DEBUG_ASSERTCRASH((! _isnan(tis_ptr->z) && _finite(tis_ptr->z)), ("Triangle has invalid center"));
  434. }
  435. }
  436. state->min_vertex_index=vertex_array_offset;
  437. polygon_array_offset+=state->polygon_count;
  438. vertex_array_offset+=state->vertex_count;
  439. }
  440. }
  441. Sort(tis, tis + overlapping_polygon_count);
  442. /* ///@todo: Add code to break up rendering into multiple index buffer fills to allow more than 65536/3 triangles. -MW
  443. int total_overlapping_polygon_count = overlapping_polygon_count;
  444. while ( > 0)
  445. {
  446. if ((total_overlapping_polygon_count*3) > 65535)
  447. { //overflowed the index buffer, must break into multiple batches
  448. overlapping_polygon_count = 65535/3;
  449. }
  450. else
  451. overlapping_polygon_count = total_overlapping_polygon_count;
  452. //insert rendering code here!!
  453. total_overlapping_polygon_count -= overlapping_polygon_count;
  454. }
  455. */
  456. unsigned polygonAllocCount = overlapping_polygon_count;
  457. if ((unsigned)(DynamicIBAccessClass::Get_Default_Index_Count()/3) < DEFAULT_SORTING_POLY_COUNT)
  458. polygonAllocCount = DEFAULT_SORTING_POLY_COUNT; //make sure that we force the DX8 index buffer to maximum size
  459. if (overlapping_polygon_count > polygonAllocCount)
  460. polygonAllocCount = overlapping_polygon_count;
  461. WWASSERT(DEFAULT_SORTING_POLY_COUNT <= 1 || polygonAllocCount <= DEFAULT_SORTING_POLY_COUNT);
  462. DynamicIBAccessClass dyn_ib_access(BUFFER_TYPE_DYNAMIC_DX8,polygonAllocCount*3);
  463. {
  464. DynamicIBAccessClass::WriteLockClass lock(&dyn_ib_access);
  465. ShortVectorIStruct* sorted_polygon_index_array=(ShortVectorIStruct*)lock.Get_Index_Array();
  466. try {
  467. for (unsigned a=0;a<overlapping_polygon_count;++a) {
  468. sorted_polygon_index_array[a]=tis[a].tri;
  469. }
  470. IndexBufferExceptionFunc();
  471. } catch(...) {
  472. IndexBufferExceptionFunc();
  473. }
  474. }
  475. // Set index buffer and render!
  476. DX8Wrapper::Set_Index_Buffer(dyn_ib_access,0); // Override with this buffer (do something to prevent need for this!)
  477. DX8Wrapper::Set_Vertex_Buffer(dyn_vb_access); // Override with this buffer (do something to prevent need for this!)
  478. DX8Wrapper::Apply_Render_State_Changes();
  479. unsigned count_to_render=1;
  480. unsigned start_index=0;
  481. unsigned node_id=tis[0].idx;
  482. for (unsigned i=1;i<overlapping_polygon_count;++i) {
  483. if (node_id!=tis[i].idx) {
  484. SortingNodeStruct* state=overlapping_nodes[node_id];
  485. Apply_Render_State(state->sorting_state);
  486. DX8Wrapper::Draw_Triangles(
  487. start_index*3,
  488. count_to_render,
  489. state->min_vertex_index,
  490. state->vertex_count);
  491. count_to_render=0;
  492. start_index=i;
  493. node_id=tis[i].idx;
  494. }
  495. count_to_render++; //keep track of number of polygons of same kind
  496. }
  497. // Render any remaining polygons...
  498. if (count_to_render) {
  499. SortingNodeStruct* state=overlapping_nodes[node_id];
  500. Apply_Render_State(state->sorting_state);
  501. DX8Wrapper::Draw_Triangles(
  502. start_index*3,
  503. count_to_render,
  504. state->min_vertex_index,
  505. state->vertex_count);
  506. }
  507. // Release all references and return nodes back to the clean list for the frame...
  508. for (node_id=0;node_id<overlapping_node_count;++node_id) {
  509. SortingNodeStruct* state=overlapping_nodes[node_id];
  510. Release_Refs(state);
  511. clean_list.Add_Head(state);
  512. }
  513. overlapping_node_count=0;
  514. overlapping_polygon_count=0;
  515. overlapping_vertex_count=0;
  516. SNAPSHOT_SAY(("SortingSystem - Done flushing\n"));
  517. }
  518. // ----------------------------------------------------------------------------
  519. void SortingRendererClass::Flush()
  520. {
  521. WWPROFILE("SortingRenderer::Flush");
  522. Matrix4x4 old_view;
  523. Matrix4x4 old_world;
  524. DX8Wrapper::Get_Transform(D3DTS_VIEW,old_view);
  525. DX8Wrapper::Get_Transform(D3DTS_WORLD,old_world);
  526. while (SortingNodeStruct* state=sorted_list.Head()) {
  527. state->Remove();
  528. if ((state->sorting_state.index_buffer_type==BUFFER_TYPE_SORTING || state->sorting_state.index_buffer_type==BUFFER_TYPE_DYNAMIC_SORTING) &&
  529. (state->sorting_state.vertex_buffer_types[0]==BUFFER_TYPE_SORTING || state->sorting_state.vertex_buffer_types[0]==BUFFER_TYPE_DYNAMIC_SORTING)) {
  530. Insert_To_Sorting_Pool(state);
  531. }
  532. else {
  533. DX8Wrapper::Set_Render_State(state->sorting_state);
  534. DX8Wrapper::Draw_Triangles(state->start_index,state->polygon_count,state->min_vertex_index,state->vertex_count);
  535. DX8Wrapper::Release_Render_State();
  536. Release_Refs(state);
  537. clean_list.Add_Head(state);
  538. }
  539. }
  540. bool old_enable=DX8Wrapper::_Is_Triangle_Draw_Enabled();
  541. DX8Wrapper::_Enable_Triangle_Draw(_EnableTriangleDraw);
  542. Flush_Sorting_Pool();
  543. DX8Wrapper::_Enable_Triangle_Draw(old_enable);
  544. DX8Wrapper::Set_Index_Buffer(0,0);
  545. DX8Wrapper::Set_Vertex_Buffer(0);
  546. total_sorting_vertices=0;
  547. DynamicIBAccessClass::_Reset(false);
  548. DynamicVBAccessClass::_Reset(false);
  549. DX8Wrapper::Set_Transform(D3DTS_VIEW,old_view);
  550. DX8Wrapper::Set_Transform(D3DTS_WORLD,old_world);
  551. }
  552. // ----------------------------------------------------------------------------
  553. void SortingRendererClass::Deinit()
  554. {
  555. SortingNodeStruct *head = NULL;
  556. //
  557. // Flush the sorted list
  558. //
  559. while ((head = sorted_list.Head ()) != NULL) {
  560. sorted_list.Remove_Head ();
  561. delete head;
  562. }
  563. //
  564. // Flush the clean list
  565. //
  566. while ((head = clean_list.Head ()) != NULL) {
  567. clean_list.Remove_Head ();
  568. delete head;
  569. }
  570. delete[] temp_index_array;
  571. temp_index_array=NULL;
  572. temp_index_array_count=0;
  573. }
  574. // ----------------------------------------------------------------------------
  575. //
  576. // Insert a VolumeParticle triangle into the sorting system.
  577. //
  578. // ----------------------------------------------------------------------------
  579. void SortingRendererClass::Insert_VolumeParticle(
  580. const SphereClass& bounding_sphere,
  581. unsigned short start_index,
  582. unsigned short polygon_count,
  583. unsigned short min_vertex_index,
  584. unsigned short vertex_count,
  585. unsigned short layerCount)
  586. {
  587. if (!WW3D::Is_Sorting_Enabled()) {
  588. DX8Wrapper::Draw_Triangles(start_index,polygon_count,min_vertex_index,vertex_count);
  589. return;
  590. }
  591. //FOR VOLUME_PARTICLE LOGIC:
  592. // WE MUST MULTIPLY THE VERTCOUNT AND POLYCOUNT BY THE VOLUME_PARTICLE DEPTH
  593. DX8_RECORD_SORTING_RENDER( polygon_count * layerCount,vertex_count * layerCount);//THIS IS VOLUME_PARTICLE SPECIFIC
  594. SortingNodeStruct* state=Get_Sorting_Struct();
  595. DX8Wrapper::Get_Render_State(state->sorting_state);
  596. WWASSERT(
  597. ((state->sorting_state.index_buffer_type==BUFFER_TYPE_SORTING || state->sorting_state.index_buffer_type==BUFFER_TYPE_DYNAMIC_SORTING) &&
  598. (state->sorting_state.vertex_buffer_types[0]==BUFFER_TYPE_SORTING || state->sorting_state.vertex_buffer_types[0]==BUFFER_TYPE_DYNAMIC_SORTING)));
  599. state->bounding_sphere=bounding_sphere;
  600. state->start_index=start_index;
  601. state->min_vertex_index=min_vertex_index;
  602. state->polygon_count=polygon_count * layerCount;//THIS IS VOLUME_PARTICLE SPECIFIC
  603. state->vertex_count=vertex_count * layerCount;//THIS IS VOLUME_PARTICLE SPECIFIC
  604. SortingVertexBufferClass* vertex_buffer=static_cast<SortingVertexBufferClass*>(state->sorting_state.vertex_buffers[0]);
  605. WWASSERT(vertex_buffer);
  606. WWASSERT(state->vertex_count<=vertex_buffer->Get_Vertex_Count());
  607. // Transform the center point to view space for sorting
  608. D3DXMATRIX mtx=(D3DXMATRIX&)state->sorting_state.world*(D3DXMATRIX&)state->sorting_state.view;
  609. D3DXVECTOR3 vec=(D3DXVECTOR3&)state->bounding_sphere.Center;
  610. D3DXVECTOR4 transformed_vec;
  611. D3DXVec3Transform(
  612. &transformed_vec,
  613. &vec,
  614. &mtx);
  615. state->transformed_center=Vector3(transformed_vec[0],transformed_vec[1],transformed_vec[2]);
  616. // BUT WHAT IS THE DEAL WITH THE VERTCOUNT AND POLYCOUNT BEING N BUT TRANSFORMED CENTER COUNT == 1
  617. //THE TRANSFORMED CENTER[2] IS THE ZBUFFER DEPTH
  618. /// @todo lorenzen sez use a bucket sort here... and stop copying so much data so many times
  619. SortingNodeStruct* node=sorted_list.Head();
  620. while (node) {
  621. if (state->transformed_center.Z>node->transformed_center.Z) {
  622. if (sorted_list.Head()==sorted_list.Tail())
  623. sorted_list.Add_Head(state);
  624. else
  625. state->Insert_Before(node);
  626. break;
  627. }
  628. node=node->Succ();
  629. }
  630. if (!node) sorted_list.Add_Tail(state);
  631. }