W3DScene.cpp 68 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: W3DScene.cpp /////////////////////////////////////////////////////////
  24. //
  25. // Scene manger for display using W3DDispaly. A scene manager can customize
  26. // the rendering process, culling, material passes ...
  27. //
  28. // Author: Colin Day, April 2001
  29. //
  30. ///////////////////////////////////////////////////////////////////////////////
  31. // SYSTEM INCLUDES ////////////////////////////////////////////////////////////
  32. #include <stdlib.h>
  33. // USER INCLUDES //////////////////////////////////////////////////////////////
  34. #include "Lib/BaseType.h"
  35. #include "Common/GlobalData.h"
  36. #include "Common/PerfTimer.h"
  37. #include "Common/Player.h"
  38. #include "Common/PlayerList.h"
  39. #include "GameLogic/Object.h"
  40. #include "GameLogic/GameLogic.h"
  41. #include "GameClient/Drawable.h"
  42. #include "GameClient/ParticleSys.h"
  43. #include "GameClient/Color.h"
  44. #include "GameClient/View.h"
  45. #include "W3DDevice/GameClient/HeightMap.h"
  46. #include "W3DDevice/GameClient/W3DScene.h"
  47. #include "W3DDevice/GameClient/W3DDynamicLight.h"
  48. #include "W3DDevice/GameClient/W3DGranny.h"
  49. #include "W3DDevice/GameClient/W3DShadow.h"
  50. #include "W3DDevice/GameClient/W3DStatusCircle.h"
  51. #include "W3DDevice/GameClient/W3DCustomScene.h"
  52. #include "W3DDevice/GameClient/W3DShroud.h"
  53. #include "WW3D2/camera.h"
  54. #include "WW3D2/dx8renderer.h"
  55. #include "WW3D2/sortingrenderer.h"
  56. #include "WW3D2/dx8wrapper.h"
  57. #include "WW3D2/Light.h"
  58. #include "WW3D2/matpass.h"
  59. #include "WW3D2/shader.h"
  60. #include "WW3D2/DX8Caps.h"
  61. #include "WW3D2/colorspace.h"
  62. #ifdef _INTERNAL
  63. // for occasional debugging...
  64. //#pragma optimize("", off)
  65. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  66. #endif
  67. ///////////////////////////////////////////////////////////////////////////////
  68. // DEFINITIONS ////////////////////////////////////////////////////////////////
  69. ///////////////////////////////////////////////////////////////////////////////
  70. ///@todo: Remove these globals since we no longer need W3D to call them for us.
  71. extern void DoTrees(RenderInfoClass & rinfo);
  72. extern void DoShadows(RenderInfoClass & rinfo, Bool stencilPass);
  73. extern void DoParticles(RenderInfoClass & rinfo);
  74. // No texturing, no zbuffer reading/writing, primary gradient, no
  75. // blending, no fogging - mostly for use in solid-colored opaque objects.
  76. #define SC_PLAYER_COLOR ( SHADE_CNST(ShaderClass::PASS_ALWAYS, ShaderClass::DEPTH_WRITE_DISABLE, ShaderClass::COLOR_WRITE_ENABLE, \
  77. ShaderClass::SRCBLEND_ONE, ShaderClass::DSTBLEND_ZERO, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, \
  78. ShaderClass::TEXTURING_DISABLE, ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_ENABLE, \
  79. ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) )
  80. static ShaderClass PlayerColorShader(SC_PLAYER_COLOR);
  81. //=============================================================================
  82. // RTS3DScene::RTS3DScene
  83. //=============================================================================
  84. /** */
  85. //=============================================================================
  86. RTS3DScene::RTS3DScene()
  87. {
  88. setName("RTS3DScene");
  89. m_drawTerrainOnly = false;
  90. m_numGlobalLights=0;
  91. for (Int i=0; i<LightEnvironmentClass::MAX_LIGHTS; i++)
  92. { m_globalLight[i]=NULL;
  93. m_infantryLight[i]=NEW_REF( LightClass, (LightClass::DIRECTIONAL) );
  94. }
  95. m_scratchLight = NEW_REF( LightClass, (LightClass::DIRECTIONAL) );
  96. // REF_PTR_SET(m_globalLight[lightIndex], pLight);
  97. #if defined(_DEBUG) || defined(_INTERNAL)
  98. if (TheGlobalData->m_shroudOn)
  99. m_shroudMaterialPass = NEW_REF(W3DShroudMaterialPassClass,());
  100. else
  101. m_shroudMaterialPass = NULL;
  102. #else
  103. m_shroudMaterialPass = NEW_REF(W3DShroudMaterialPassClass,());
  104. #endif
  105. m_maskMaterialPass = NEW_REF(W3DMaskMaterialPassClass,());
  106. m_customPassMode = SCENE_PASS_DEFAULT;
  107. m_heatVisionMaterialPass = NEW_REF(MaterialPassClass,());
  108. m_heatVisionOnlyPass = NEW_REF(MaterialPassClass,());
  109. VertexMaterialClass *heatVisionMtl = NEW_REF(VertexMaterialClass,());
  110. heatVisionMtl->Set_Lighting(true);
  111. heatVisionMtl->Set_Ambient(0,0,0);
  112. heatVisionMtl->Set_Diffuse(0.02f,0.01f,0.00f);
  113. heatVisionMtl->Set_Emissive(0.5f,0.2f,0.0f);
  114. m_heatVisionMaterialPass->Set_Material(heatVisionMtl);
  115. ShaderClass heatVisionShader=ShaderClass::_PresetAdditiveSolidShader;
  116. heatVisionShader.Set_Depth_Compare(ShaderClass::PASS_EQUAL);
  117. m_heatVisionMaterialPass->Set_Shader(heatVisionShader);
  118. heatVisionMtl->Release_Ref();
  119. heatVisionShader.Set_Depth_Compare(ShaderClass::PASS_LEQUAL);
  120. heatVisionShader.Set_Depth_Mask(ShaderClass::DEPTH_WRITE_DISABLE);
  121. m_heatVisionOnlyPass->Set_Material(heatVisionMtl);
  122. m_heatVisionOnlyPass->Set_Shader(heatVisionShader);
  123. //Allocate memory to hold queue of visible renderobjects that need to be drawn last
  124. //because they are forced translucent.
  125. m_translucentObjectsCount = 0;
  126. if (TheGlobalData && TheGlobalData->m_maxVisibleTranslucentObjects)
  127. m_translucentObjectsBuffer = NEW RenderObjClass* [TheGlobalData->m_maxVisibleTranslucentObjects];
  128. else
  129. m_translucentObjectsBuffer = NULL;
  130. m_numPotentialOccluders=0;
  131. m_numPotentialOccludees=0;
  132. m_numNonOccluderOrOccludee=0;
  133. m_occludedObjectsCount=0;
  134. m_potentialOccluders=NULL;
  135. m_potentialOccludees=NULL;
  136. m_nonOccludersOrOccludees=NULL;
  137. //Modify the shader to make occlusion transparent
  138. ShaderClass shader = PlayerColorShader;
  139. shader.Set_Src_Blend_Func(ShaderClass::SRCBLEND_SRC_ALPHA);
  140. shader.Set_Dst_Blend_Func(ShaderClass::DSTBLEND_ONE_MINUS_SRC_ALPHA);
  141. m_potentialOccluders = NEW RenderObjClass* [TheGlobalData->m_maxVisibleOccluderObjects];
  142. m_potentialOccludees = NEW RenderObjClass* [TheGlobalData->m_maxVisibleOccludeeObjects];
  143. m_nonOccludersOrOccludees = NEW RenderObjClass* [TheGlobalData->m_maxVisibleNonOccluderOrOccludeeObjects];
  144. #ifdef USE_NON_STENCIL_OCCLUSION
  145. for (i=0; i<MAX_PLAYER_COUNT; i++)
  146. { m_occludedMaterialPass[i]=NEW_REF(MaterialPassClass,());
  147. VertexMaterialClass * vmtl = NEW_REF(VertexMaterialClass,());
  148. vmtl->Set_Lighting(true);
  149. vmtl->Set_Ambient(0,0,0); //we're only using emissive so kill all other lights.
  150. vmtl->Set_Diffuse(0,0,0);
  151. m_occludedMaterialPass[i]->Set_Material(vmtl);
  152. m_occludedMaterialPass[i]->Set_Shader(shader);
  153. vmtl->Release_Ref(); //material pass is holding the pointer so release ref.
  154. }
  155. #else
  156. for (i=0; i<MAX_PLAYER_COUNT; i++)
  157. m_occludedMaterialPass[i]=NULL;
  158. #endif
  159. } // end RTS3DScene
  160. //=============================================================================
  161. // RTS3DScene::~RTS3DScene
  162. //=============================================================================
  163. /** */
  164. //=============================================================================
  165. RTS3DScene::~RTS3DScene()
  166. {
  167. for (Int i=0; i<LightEnvironmentClass::MAX_LIGHTS; i++)
  168. {
  169. REF_PTR_RELEASE(m_globalLight[i]);
  170. REF_PTR_RELEASE(m_infantryLight[i]);
  171. }
  172. REF_PTR_RELEASE(m_scratchLight);
  173. REF_PTR_RELEASE(m_shroudMaterialPass);
  174. REF_PTR_RELEASE(m_maskMaterialPass);
  175. REF_PTR_RELEASE(m_heatVisionMaterialPass);
  176. REF_PTR_RELEASE(m_heatVisionOnlyPass);
  177. if (m_translucentObjectsBuffer)
  178. delete [] m_translucentObjectsBuffer;
  179. if (m_nonOccludersOrOccludees)
  180. delete [] m_nonOccludersOrOccludees;
  181. if (m_potentialOccludees)
  182. delete [] m_potentialOccludees;
  183. if (m_potentialOccluders)
  184. delete [] m_potentialOccluders;
  185. for (i=0; i<MAX_PLAYER_COUNT; i++)
  186. { REF_PTR_RELEASE(m_occludedMaterialPass[i]);
  187. }
  188. } // end ~RTS3DScene
  189. void RTS3DScene::setGlobalLight(LightClass *pLight, Int lightIndex)
  190. {
  191. if (m_numGlobalLights < (lightIndex+1))
  192. m_numGlobalLights=(lightIndex+1);
  193. REF_PTR_SET(m_globalLight[lightIndex], pLight);
  194. }
  195. /**Find all objects which need to be drawn in a special way because they are occluded by other
  196. objects.
  197. @todo: Need some kind of scene subdivision or find way to use Partition manger to speed up the ray
  198. intersection tests. Maybe truncate the ray to terrain length before using it?
  199. */
  200. void RTS3DScene::flagOccludedObjects(CameraClass * camera)
  201. {
  202. Vector3 camPosition=camera->Get_Position();
  203. //Find which objects are actually occluded
  204. RenderObjClass **occludee=m_potentialOccludees;
  205. LineSegClass lineseg;
  206. CastResultStruct result;
  207. Bool hit=FALSE;
  208. Vector3 newEndPoint;
  209. result.ComputeContactPoint=false;
  210. RayCollisionTestClass raytest(lineseg,&result,COLLISION_TYPE_ALL,false,false);
  211. raytest.CollisionType=COLLISION_TYPE_ALL;
  212. m_occludedObjectsCount=0;
  213. for (Int i=0; i<m_numPotentialOccludees; i++,occludee++)
  214. {
  215. raytest.Ray.Set(camPosition,(*occludee)->Get_Position());
  216. RenderObjClass **occluder=m_potentialOccluders;
  217. //Check this object against all other possible blocking objects
  218. for (Int j=0; j<m_numPotentialOccluders; j++,occluder++)
  219. {
  220. // Do a quick ray-sphere test (Graphics Gems I, p388)
  221. RenderObjClass *robj=*occluder;
  222. const SphereClass *sphere = &robj->Get_Bounding_Sphere();
  223. // make a vector from the ray origin to the sphere center
  224. Vector3 sphere_vector(sphere->Center - raytest.Ray.Get_P0());
  225. // get the dot product between the sphere_vector and the ray vector
  226. Real Alpha = Vector3::Dot_Product(sphere_vector, raytest.Ray.Get_Dir());
  227. Real Beta = sphere->Radius * sphere->Radius - (Vector3::Dot_Product(sphere_vector, sphere_vector) - Alpha * Alpha);
  228. if(Beta < 0.0f)
  229. continue; //no intersection
  230. //Do a more accurate test against object geometry
  231. if (robj->Cast_Ray(raytest))
  232. {
  233. //Found an object closer than last closest object
  234. //Adjust our results and refine search
  235. raytest.CollidedRenderObj = robj;
  236. hit=TRUE;
  237. //reset the result space for next test
  238. result.StartBad = false; result.Fraction = 1.0f;
  239. break;
  240. }
  241. }
  242. if (hit)
  243. { //ocludee was blocked by something so flag it for custom rendering
  244. DrawableInfo *drawInfo=(DrawableInfo *)(*occludee)->Get_User_Data();
  245. drawInfo->m_flags |= DrawableInfo::ERF_IS_OCCLUDED;
  246. m_potentialOccludees[m_occludedObjectsCount++] = *occludee;
  247. }
  248. }
  249. }
  250. //=============================================================================
  251. // RTS3DScene::castRay
  252. //=============================================================================
  253. /** Does a ray intersection test against objects in our scene.
  254. By default, it only tests objects determined to be visible to the user.
  255. Setting testAll forces it to test all objects in the scene.
  256. CollisionType is used as a mask to ignore certain types of objects.
  257. */
  258. //=============================================================================
  259. Bool RTS3DScene::castRay(RayCollisionTestClass & raytest, Bool testAll, Int collisionType)
  260. {
  261. // this shouldn't be necessary here, and would be an undesirable performance hit.
  262. // if you ever add or modify code here, it MIGHT become necessary... so do so with caution. (srj)
  263. //#ifdef DIRTY_CONDITION_FLAGS
  264. // StDrawableDirtyStuffLocker lockDirtyStuff;
  265. //#endif
  266. //temporary results for each object tested
  267. CastResultStruct result;
  268. RayCollisionTestClass tempRayTest(raytest.Ray,&result);
  269. Vector3 newEndPoint;
  270. Bool hit=FALSE;
  271. tempRayTest.CollisionType = COLLISION_TYPE_ALL;
  272. //check if a mesh is translucent before colliding with it. Skips headlights, etc.
  273. tempRayTest.CheckTranslucent = true;
  274. RefRenderObjListIterator it(&RenderList);
  275. // select the first object
  276. it.First();
  277. while (!it.Is_Done())
  278. {
  279. // get the render object
  280. RenderObjClass * robj = it.Peek_Obj();
  281. it.Next();
  282. // only intersect if it was visible or if we must test all
  283. if(robj->Get_Collision_Type() & collisionType && (testAll || robj->Is_Really_Visible()))
  284. {
  285. // Do a quick ray-sphere test (Graphics Gems I, p388)
  286. const SphereClass *sphere = &robj->Get_Bounding_Sphere();
  287. // make a vector from the ray origin to the sphere center
  288. Vector3 sphere_vector(sphere->Center - tempRayTest.Ray.Get_P0());
  289. // get the dot product between the sphere_vector and the ray vector
  290. Real Alpha = Vector3::Dot_Product(sphere_vector, tempRayTest.Ray.Get_Dir());
  291. Real Beta = sphere->Radius * sphere->Radius - (Vector3::Dot_Product(sphere_vector, sphere_vector) - Alpha * Alpha);
  292. if(Beta < 0.0f)
  293. continue; //no intersection
  294. //Do a more accurate test against object geometry
  295. if (robj->Cast_Ray(tempRayTest))
  296. {
  297. //Found an object closer than last closest object
  298. //Adjust our results and refine search
  299. raytest.CollidedRenderObj = robj;
  300. hit=TRUE;
  301. //Refine search by making ray shorter
  302. tempRayTest.Ray.Compute_Point(tempRayTest.Result->Fraction,&newEndPoint);
  303. tempRayTest.Ray.Set(raytest.Ray.Get_P0(),newEndPoint);
  304. //intersection point is at the end of shortened ray, so adjust fraction to 1.0
  305. tempRayTest.Result->Fraction=1.0f;
  306. }
  307. }
  308. }
  309. //Store results of ray intersection test including a clipped ray that ends on object.
  310. raytest.Ray=tempRayTest.Ray;
  311. return hit;
  312. }
  313. //=============================================================================
  314. // RTS3DScene::Visibility_Check
  315. //=============================================================================
  316. /** Custom visibility check method for the RTS3DScene, we can put optimized
  317. * culling methods in here */
  318. //=============================================================================
  319. void RTS3DScene::Visibility_Check(CameraClass * camera)
  320. {
  321. #ifdef DIRTY_CONDITION_FLAGS
  322. StDrawableDirtyStuffLocker lockDirtyStuff;
  323. #endif
  324. RefRenderObjListIterator it(&RenderList);
  325. DrawableInfo *drawInfo = NULL;
  326. Drawable *draw = NULL;
  327. RenderObjClass * robj;
  328. m_numPotentialOccluders=0;
  329. m_numPotentialOccludees=0;
  330. m_translucentObjectsCount=0;
  331. m_numNonOccluderOrOccludee=0;
  332. Int currentFrame=0;
  333. if (TheGameLogic) currentFrame = TheGameLogic->getFrame();
  334. if (currentFrame <= TheGlobalData->m_defaultOcclusionDelay)
  335. currentFrame = TheGlobalData->m_defaultOcclusionDelay+1; //make sure occlusion is enabled when game starts (frame 0).
  336. if (ShaderClass::Is_Backface_Culling_Inverted())
  337. { //we are rendering reflections
  338. ///@todo: Have better flag to detect reflection pass
  339. // Loop over all top-level RenderObjects in this scene. If the bounding sphere is not in front
  340. // of all the frustum planes, it is invisible.
  341. for (it.First(); !it.Is_Done(); it.Next()) {
  342. robj = it.Peek_Obj();
  343. draw=NULL;
  344. drawInfo = (DrawableInfo *)robj->Get_User_Data();
  345. if (drawInfo)
  346. draw=drawInfo->m_drawable;
  347. if( draw )
  348. {
  349. if (robj->Is_Force_Visible()) {
  350. robj->Set_Visible(true);
  351. } else {
  352. robj->Set_Visible(draw->getDrawsInMirror() && !camera->Cull_Sphere(robj->Get_Bounding_Sphere()));
  353. }
  354. }
  355. else
  356. { //perform normal culling on non-drawables
  357. if (robj->Is_Force_Visible()) {
  358. robj->Set_Visible(true);
  359. } else {
  360. robj->Set_Visible(!camera->Cull_Sphere(robj->Get_Bounding_Sphere()));
  361. }
  362. }
  363. }
  364. }
  365. else
  366. {
  367. // Loop over all top-level RenderObjects in this scene. If the bounding sphere is not in front
  368. // of all the frustum planes, it is invisible.
  369. for (it.First(); !it.Is_Done(); it.Next()) {
  370. robj = it.Peek_Obj();
  371. if (robj->Is_Force_Visible()) {
  372. robj->Set_Visible(true);
  373. } else if (robj->Is_Hidden()) {
  374. robj->Set_Visible(false);
  375. } else {
  376. bool isVisible=!camera->Cull_Sphere(robj->Get_Bounding_Sphere());
  377. if (isVisible)
  378. { //need to keep track of occluders and ocludees for subsequent code.
  379. drawInfo = (DrawableInfo *)robj->Get_User_Data();
  380. if (drawInfo && (draw=drawInfo->m_drawable) != NULL)
  381. {
  382. if (draw->isDrawableEffectivelyHidden() || draw->getFullyObscuredByShroud())
  383. { robj->Set_Visible(false);
  384. continue;
  385. }
  386. //assume normal rendering.
  387. drawInfo->m_flags = DrawableInfo::ERF_IS_NORMAL; //clear any rendering flags that may be in effect.
  388. if (draw->getEffectiveOpacity() != 1.0f && m_translucentObjectsCount < TheGlobalData->m_maxVisibleTranslucentObjects)
  389. { drawInfo->m_flags = DrawableInfo::ERF_IS_TRANSLUCENT; //object is translucent
  390. m_translucentObjectsBuffer[m_translucentObjectsCount++] = robj;
  391. }
  392. else
  393. if (TheGlobalData->m_enableBehindBuildingMarkers && TheGameLogic->getShowBehindBuildingMarkers())
  394. {
  395. //visible drawable. Check if it's either an occluder or occludee
  396. if (draw->isKindOf(KINDOF_STRUCTURE) && m_numPotentialOccluders < TheGlobalData->m_maxVisibleOccluderObjects)
  397. { //object which could occlude other objects that need to be visible.
  398. m_potentialOccluders[m_numPotentialOccluders++]=robj;
  399. drawInfo->m_flags |= DrawableInfo::ERF_POTENTIAL_OCCLUDER;
  400. }
  401. else
  402. if (draw->getObject() &&
  403. (draw->isKindOf(KINDOF_SCORE) || draw->isKindOf(KINDOF_SCORE_CREATE) || draw->isKindOf(KINDOF_SCORE_DESTROY) || draw->isKindOf(KINDOF_MP_COUNT_FOR_VICTORY)) &&
  404. (draw->getObject()->getSafeOcclusionFrame()) <= currentFrame && m_numPotentialOccludees < TheGlobalData->m_maxVisibleOccludeeObjects)
  405. { //object which could be occluded but still needs to be visible.
  406. m_potentialOccludees[m_numPotentialOccludees++]=robj;
  407. drawInfo->m_flags |= DrawableInfo::ERF_POTENTIAL_OCCLUDEE;
  408. }
  409. else
  410. if (drawInfo->m_flags == DrawableInfo::ERF_IS_NORMAL && m_numNonOccluderOrOccludee < TheGlobalData->m_maxVisibleNonOccluderOrOccludeeObjects)
  411. { //regular object with no custom effects but still needs to be delayed to get the occlusion feature to work correctly.
  412. m_nonOccludersOrOccludees[m_numNonOccluderOrOccludee++]=robj;
  413. drawInfo->m_flags |= DrawableInfo::ERF_IS_NON_OCCLUDER_OR_OCCLUDEE;
  414. }
  415. }
  416. }
  417. }
  418. robj->Set_Visible(isVisible);
  419. }
  420. ///@todo: We're not using LOD yet so I disabled this code. MW
  421. // Also, should check how multiple passes (reflections) get along
  422. // with the LOD manager - we're rendering double the load it thinks we are.
  423. // Prepare visible objects for LOD:
  424. // if (robj->Is_Really_Visible()) {
  425. // robj->Prepare_LOD(*camera);
  426. // }
  427. }
  428. }
  429. Visibility_Checked = true;
  430. }
  431. //============================================================================
  432. // RTS3DScene::renderSingleDrawable
  433. //=============================================================================
  434. /** Renders a single drawable entity. */
  435. //=============================================================================
  436. void RTS3DScene::renderSpecificDrawables(RenderInfoClass &rinfo, Int numDrawable, Drawable **theDrawables)
  437. {
  438. #ifdef DIRTY_CONDITION_FLAGS
  439. StDrawableDirtyStuffLocker lockDirtyStuff;
  440. #endif
  441. Int localPlayerIndex = ThePlayerList ? ThePlayerList->getLocalPlayer()->getPlayerIndex() : 0;
  442. RefRenderObjListIterator it(&UpdateList);
  443. // loop through all render objects in the list:
  444. for (it.First(&RenderList); !it.Is_Done();)
  445. {
  446. RenderObjClass *robj;
  447. // get the render object
  448. robj = it.Peek_Obj();
  449. it.Next(); //advance to next object in case this one gets deleted during renderOneObject().
  450. DrawableInfo *drawInfo = (DrawableInfo *)robj->Get_User_Data();
  451. Drawable *draw=NULL;
  452. if (drawInfo)
  453. draw = drawInfo->m_drawable;
  454. if (!draw) continue;
  455. Bool match = false;
  456. for (Int i = 0; i<numDrawable; i++) {
  457. if (theDrawables[i] == draw) {
  458. match = true;
  459. break;
  460. }
  461. }
  462. if (match) {
  463. renderOneObject(rinfo, robj, localPlayerIndex);
  464. }
  465. }
  466. }
  467. //============================================================================
  468. // RTS3DScene::renderOneObject
  469. //=============================================================================
  470. /** Renders a single drawable entity. */
  471. //=============================================================================
  472. void RTS3DScene::renderOneObject(RenderInfoClass &rinfo, RenderObjClass *robj, Int localPlayerIndex)
  473. {
  474. Drawable *draw = NULL;
  475. DrawableInfo *drawInfo = NULL;
  476. Bool drawableHidden=FALSE;
  477. Object* obj = NULL;
  478. ObjectShroudStatus ss=OBJECTSHROUD_INVALID;
  479. Bool doExtraMaterialPop=FALSE;
  480. Bool doExtraFlagsPop=FALSE;
  481. LightClass **sceneLights=m_globalLight;
  482. if (robj->Class_ID() == RenderObjClass::CLASSID_IMAGE3D )
  483. { robj->Render(rinfo); //notify decals system that this track is visible
  484. return; //decals are not lit by this system yet so skip rest of lighting
  485. }
  486. LightEnvironmentClass lightEnv;
  487. SphereClass sph = robj->Get_Bounding_Sphere();
  488. drawInfo = (DrawableInfo *)robj->Get_User_Data();
  489. if (drawInfo)
  490. { draw = drawInfo->m_drawable;
  491. //If we have a drawInfo but not drawable, we must be dealing with
  492. //a ghost object which is always fogged.
  493. if (!draw)
  494. ss = OBJECTSHROUD_FOGGED;
  495. }
  496. // all this ambient business no longer handles the tinting and flashing stuff,
  497. // but it does still light the drawable explicitly, and can be fudged like this
  498. // infantry test does, here...
  499. // the tint has been delegated to the getTint() stuff, below... MLorenzen
  500. Vector3 ambient = Get_Ambient_Light();
  501. if (draw && (drawableHidden=draw->isDrawableEffectivelyHidden()) != TRUE)
  502. {
  503. #ifdef NOT_IN_USE
  504. const Vector3* drawAmbient = draw->getAmbientLight();
  505. if (drawAmbient)
  506. ambient.Add(ambient, *drawAmbient, &ambient);
  507. #endif
  508. obj = draw->getObject();
  509. if (obj) {
  510. ss = obj->getShroudedStatus(localPlayerIndex);
  511. // For objects like planes, that pop out of the shroud, fire, then head back,
  512. // we keep drawing them for 2 seconds after they return to the fogged area,
  513. // so the player can see them and missiles chasing them. jba.
  514. if (ss == OBJECTSHROUD_CLEAR) {
  515. draw->setShroudClearFrame(TheGameLogic->getFrame());
  516. } else if (ss >= OBJECTSHROUD_FOGGED && draw->getShroudClearFrame()!=0) {
  517. UnsignedInt limit = 2*LOGICFRAMES_PER_SECOND;
  518. if (obj->isEffectivelyDead()) {
  519. limit += 3*LOGICFRAMES_PER_SECOND;
  520. }
  521. if (TheGameLogic->getFrame() < limit + draw->getShroudClearFrame()) {
  522. // It's been less than 2 seconds since we could see them clear, so keep showing them.
  523. ss = OBJECTSHROUD_PARTIAL_CLEAR;
  524. }
  525. }
  526. if (!robj->Peek_Scene())
  527. return; //this object was removed by the getShroudedStatus() call.
  528. }
  529. else
  530. { //drawable with no object so no way to know if it's shrouded.
  531. ss = OBJECTSHROUD_CLEAR; //assume not shrouded/fogged.
  532. //Check to see if there is another unrelated object which controls the shroud status
  533. //(Hack for prison camps which contain enemy prisoner drawables)
  534. if (drawInfo->m_shroudStatusObjectID != INVALID_ID)
  535. { Object *shroudObject=TheGameLogic->findObjectByID(drawInfo->m_shroudStatusObjectID);
  536. if (shroudObject && shroudObject->getShroudedStatus(localPlayerIndex) >= OBJECTSHROUD_FOGGED)
  537. ss = OBJECTSHROUD_SHROUDED; //we will assume that drawables without objects are 'particle' like and therefore don't need drawing if fogged/shrouded.
  538. }
  539. }
  540. if (draw->isKindOf(KINDOF_INFANTRY))
  541. { ambient = m_infantryAmbient;
  542. sceneLights = m_infantryLight;
  543. }
  544. lightEnv.Reset(sph.Center, ambient);
  545. // HANDLE THE SPECIAL DRAWABLE-LEVEL COLORING SETTINGS FIRST
  546. const Vector3 *tintColor = NULL;
  547. const Vector3 *selectionColor = NULL;
  548. tintColor = draw->getTintColor();
  549. selectionColor = draw->getSelectionColor();
  550. if ( tintColor || selectionColor )
  551. {
  552. Vector3 sumTint, temp, restore;
  553. sumTint.Set(0,0,0);
  554. if (tintColor)
  555. Vector3::Add(sumTint, *tintColor, &sumTint);
  556. if (selectionColor)
  557. Vector3::Add(sumTint, *selectionColor, &sumTint);
  558. for (Int globalLightIndex = 0; globalLightIndex < m_numGlobalLights; globalLightIndex++)
  559. {
  560. sceneLights[globalLightIndex]->Get_Diffuse( &temp );
  561. restore = temp;
  562. Vector3::Add(temp, sumTint, &temp);
  563. sceneLights[globalLightIndex]->Set_Diffuse( temp );
  564. lightEnv.Add_Light(*sceneLights[globalLightIndex]);
  565. sceneLights[globalLightIndex]->Set_Diffuse( restore );
  566. } // next light
  567. temp = lightEnv.Get_Equivalent_Ambient();
  568. Vector3::Add(sumTint, temp, &temp );
  569. lightEnv.Set_Output_Ambient( temp );
  570. }
  571. else // no funny coloring going on, so just add the lights normally
  572. {
  573. for (Int globalLightIndex = 0; globalLightIndex < m_numGlobalLights; globalLightIndex++)
  574. {
  575. lightEnv.Add_Light(*sceneLights[globalLightIndex]);
  576. }
  577. }
  578. //Apply custom render pass for any drawables with heatvision enabled
  579. if (draw->getHeatVisionOpacity() != 0 )
  580. {
  581. rinfo.materialPassEmissiveOverride = draw->getHeatVisionOpacity();
  582. if (draw->getStealthLook() == STEALTHLOOK_VISIBLE_DETECTED )
  583. {
  584. // THIS WILL EXPLICITLY SKIP THE FIRST PASS SO THAT HEATVISION ONLY WILL RENDER
  585. rinfo.Push_Override_Flags(RenderInfoClass::RINFO_OVERRIDE_ADDITIONAL_PASSES_ONLY);
  586. rinfo.Push_Material_Pass(m_heatVisionOnlyPass);
  587. doExtraFlagsPop=TRUE;
  588. }
  589. else
  590. {
  591. //THIS CALLS FOR THE HEATVISION TO RENDER
  592. rinfo.Push_Material_Pass(m_heatVisionMaterialPass);
  593. }
  594. doExtraMaterialPop=TRUE;
  595. }
  596. }
  597. else
  598. { //either no drawable or it is hidden
  599. if (drawableHidden)
  600. return; //don't bother with anything else
  601. //Render object without a drawable. Must be either some fluff/debug object or a ghostObject.
  602. if (ss == OBJECTSHROUD_FOGGED)
  603. { //Must be ghost object because we don't fog normal things. Fogged objects always have a predefined
  604. //lighting environment applied which emulates the look of fog.
  605. rinfo.light_environment = &m_foggedLightEnv;
  606. robj->Render(rinfo);
  607. rinfo.light_environment = NULL;
  608. return;
  609. }
  610. else
  611. { lightEnv.Reset(sph.Center, ambient);
  612. for (Int globalLightIndex = 0; globalLightIndex < m_numGlobalLights; globalLightIndex++)
  613. lightEnv.Add_Light(*m_globalLight[globalLightIndex]);
  614. }
  615. }
  616. if (!drawableHidden)
  617. {
  618. //standard scene lights
  619. RefRenderObjListIterator it2(&LightList);
  620. for (it2.First(); !it2.Is_Done(); it2.Next())
  621. {
  622. LightClass *pLight = (LightClass*)it2.Peek_Obj();
  623. SphereClass lSph = pLight->Get_Bounding_Sphere();
  624. Bool cull = (pLight->Get_Type() == LightClass::POINT && !Spheres_Intersect(sph, lSph));
  625. if (!cull) {
  626. lightEnv.Add_Light(*pLight);
  627. }
  628. }
  629. // dynamic lights
  630. RefRenderObjListIterator dynaLightIt(&m_dynamicLightList);
  631. for (dynaLightIt.First(); !dynaLightIt.Is_Done(); dynaLightIt.Next())
  632. {
  633. W3DDynamicLight* pDyna = (W3DDynamicLight*)dynaLightIt.Peek_Obj();
  634. if (!pDyna->isEnabled()) {
  635. continue;
  636. }
  637. SphereClass lSph = pDyna->Get_Bounding_Sphere();
  638. if (pDyna->Get_Type() == LightClass::POINT && !Spheres_Intersect(sph, lSph)) {
  639. continue;
  640. }
  641. lightEnv.Add_Light(*(LightClass*)dynaLightIt.Peek_Obj());
  642. }
  643. lightEnv.Pre_Render_Update(rinfo.Camera.Get_Transform());
  644. rinfo.light_environment = &lightEnv;
  645. if (drawInfo)
  646. {
  647. #if defined(_DEBUG) || defined(_INTERNAL)
  648. if (!TheGlobalData->m_shroudOn)
  649. ss = OBJECTSHROUD_CLEAR;
  650. #endif
  651. if (m_customPassMode == SCENE_PASS_DEFAULT)
  652. {
  653. if (ss <= OBJECTSHROUD_CLEAR)
  654. robj->Render(rinfo);
  655. else
  656. {
  657. rinfo.Push_Material_Pass(m_shroudMaterialPass);
  658. robj->Render(rinfo);
  659. rinfo.Pop_Material_Pass();
  660. }
  661. }
  662. else
  663. if (m_maskMaterialPass)
  664. { rinfo.Push_Material_Pass(m_maskMaterialPass);
  665. rinfo.Push_Override_Flags(RenderInfoClass::RINFO_OVERRIDE_ADDITIONAL_PASSES_ONLY);
  666. robj->Render(rinfo);
  667. rinfo.Pop_Override_Flags();
  668. rinfo.Pop_Material_Pass();
  669. }
  670. }//drawInfo exists so rendering a drawable.
  671. else
  672. {
  673. robj->Render(rinfo);
  674. }
  675. }//drawable or robj is not hidden
  676. rinfo.light_environment = NULL;
  677. if (doExtraMaterialPop) //check if there is an extra material on the stack from the heatvision effect.
  678. rinfo.Pop_Material_Pass();
  679. if (doExtraFlagsPop)
  680. rinfo.Pop_Override_Flags(); //flags used to disable base pass and only render custom heat vision pass.
  681. }
  682. //DECLARE_PERF_TIMER(translucentRender)
  683. /**Draw everything that was submitted from this scene*/
  684. void RTS3DScene::Flush(RenderInfoClass & rinfo)
  685. {
  686. //don't draw shadows in this mode because they interfere with destination alpha or are invisible (wireframe)
  687. if (m_customPassMode == SCENE_PASS_DEFAULT && Get_Extra_Pass_Polygon_Mode() == EXTRA_PASS_DISABLE)
  688. DoShadows(rinfo, false); //draw all non-stencil shadows (decals) since they fall under other objects.
  689. TheDX8MeshRenderer.Flush(); //draw all non-translucent objects.
  690. //draw all non-translucent objects which were separated because they are hidden and need custom rendering.
  691. #ifdef USE_NON_STENCIL_OCCLUSION
  692. flushOccludedObjects(rinfo);
  693. #else
  694. if (DX8Wrapper::Has_Stencil())
  695. flushOccludedObjectsIntoStencil(rinfo);
  696. #endif
  697. // Draw the trees last so they alpha blend onto everything correctly.
  698. DoTrees(rinfo);
  699. //don't draw shadows in this mode because they interfere with destination alpha
  700. if (m_customPassMode == SCENE_PASS_DEFAULT && Get_Extra_Pass_Polygon_Mode() == EXTRA_PASS_DISABLE)
  701. DoShadows(rinfo, true); //draw all stencil shadows
  702. WW3D::Render_And_Clear_Static_Sort_Lists(rinfo); //draws things like water
  703. if (m_customPassMode == SCENE_PASS_DEFAULT && Get_Extra_Pass_Polygon_Mode() == EXTRA_PASS_DISABLE)
  704. flushTranslucentObjects(rinfo); //draw all translucent meshes which don't need per-poly sorting.
  705. {
  706. //USE_PERF_TIMER(translucentRender)
  707. //don't draw transparent in this mode because they interfere with destination alpha
  708. if (m_customPassMode == SCENE_PASS_DEFAULT && Get_Extra_Pass_Polygon_Mode() == EXTRA_PASS_DISABLE)
  709. DoParticles(rinfo); //queue up particles for rendering.
  710. SortingRendererClass::Flush(); //draw sorted translucent polys like particles.
  711. }
  712. TheDX8MeshRenderer.Clear_Pending_Delete_Lists();
  713. }
  714. /**Generate a predefined light environment(s) that will be applied to many objects. Useful for things like totally fogged
  715. objects and most generaic map objects that are not lit by dynamic lights.*/
  716. void RTS3DScene::updateFixedLightEnvironments(RenderInfoClass & rinfo)
  717. {
  718. //Figure out how dimly lit fogged objects should be compared to fully lit.
  719. Real foggedLightFrac = (Real)TheGlobalData->m_fogAlpha/(Real)TheGlobalData->m_clearAlpha;
  720. Vector3 oldDiffuse;
  721. Real infantryLightScale;
  722. if( TheGlobalData->m_scriptOverrideInfantryLightScale != -1.0f )
  723. infantryLightScale = TheGlobalData->m_scriptOverrideInfantryLightScale;
  724. else
  725. infantryLightScale = TheGlobalData->m_infantryLightScale[TheGlobalData->m_timeOfDay];
  726. //Generate the default light environment
  727. m_defaultLightEnv.Reset(Vector3(0,0,0), Get_Ambient_Light());
  728. m_foggedLightEnv.Reset(Vector3(0,0,0), Get_Ambient_Light()*foggedLightFrac);
  729. for (Int globalLightIndex = 0; globalLightIndex < m_numGlobalLights; globalLightIndex++)
  730. { m_defaultLightEnv.Add_Light(*m_globalLight[globalLightIndex]);
  731. //copy default lighting for infantry so we can tweak it.
  732. *m_infantryLight[globalLightIndex]=*m_globalLight[globalLightIndex];
  733. m_globalLight[globalLightIndex]->Get_Diffuse(&oldDiffuse);
  734. m_infantryLight[globalLightIndex]->Set_Diffuse(oldDiffuse*infantryLightScale);
  735. m_globalLight[globalLightIndex]->Get_Ambient(&oldDiffuse);
  736. m_infantryLight[globalLightIndex]->Set_Ambient(oldDiffuse*infantryLightScale);
  737. m_infantryLight[globalLightIndex]->Set_Transform(m_globalLight[globalLightIndex]->Get_Transform());
  738. //copy the normal light for fog so we can modify it
  739. m_scratchLight->Set_Transform(m_globalLight[globalLightIndex]->Get_Transform());
  740. //modify light with attenuated value to adjust for fog.
  741. m_globalLight[globalLightIndex]->Get_Diffuse(&oldDiffuse);
  742. m_scratchLight->Set_Diffuse(oldDiffuse*foggedLightFrac);
  743. m_globalLight[globalLightIndex]->Get_Ambient(&oldDiffuse);
  744. m_scratchLight->Set_Ambient(oldDiffuse*foggedLightFrac);
  745. m_foggedLightEnv.Add_Light(*m_scratchLight);
  746. }
  747. m_defaultLightEnv.Pre_Render_Update(rinfo.Camera.Get_Transform());
  748. m_foggedLightEnv.Pre_Render_Update(rinfo.Camera.Get_Transform());
  749. m_infantryAmbient = Get_Ambient_Light();// * infantryLightScale; //for now don't adjust ambient so that we don't lose directional lighting.
  750. }
  751. /**Generate custom rendering passes for each potential player color. This is currently only used
  752. to render occluded objects using the color of the player*/
  753. void RTS3DScene::updatePlayerColorPasses(void)
  754. {
  755. #ifdef USE_NON_STENCIL_OCCLUSION
  756. Vector3 hsv,rgb;
  757. if (TheGlobalData->m_enableBehindBuildingMarkers && TheGameLogic->getShowBehindBuildingMarkers())
  758. {
  759. Int numPlayers=ThePlayerList->getPlayerCount();
  760. for (Int i=0; i<numPlayers; i++)
  761. { Player *player=ThePlayerList->getNthPlayer(i);
  762. Int playerIndex=player->getPlayerIndex();
  763. Real red,green,blue,alpha;
  764. GameGetColorComponentsReal(player->getPlayerColor(),&red,&green,&blue,&alpha);
  765. RGB_To_HSV(hsv,Vector3(red,green,blue));
  766. hsv.Z*=TheGlobalData->m_occludedLuminanceScale;
  767. HSV_To_RGB(rgb,hsv);
  768. VertexMaterialClass *vmat=m_occludedMaterialPass[playerIndex]->Peek_Material();
  769. vmat->Set_Emissive(rgb);
  770. }
  771. }
  772. #endif
  773. }
  774. #define ZBias 0.0001f
  775. //DECLARE_PERF_TIMER(NonTerrainRender)
  776. void RTS3DScene::Render(RenderInfoClass & rinfo)
  777. {
  778. //USE_PERF_TIMER(NonTerrainRender)
  779. DX8Wrapper::Set_Fog(FogEnabled, FogColor, FogStart, FogEnd);
  780. //Override the behind building selection if it's not available on current hardware (needs stencil).
  781. TheWritableGlobalData->m_enableBehindBuildingMarkers = TheWritableGlobalData->m_enableBehindBuildingMarkers && DX8Wrapper::Has_Stencil();
  782. if (Get_Extra_Pass_Polygon_Mode() == EXTRA_PASS_DISABLE)
  783. {
  784. if (m_customPassMode == SCENE_PASS_DEFAULT)
  785. { //Regular rendering pass with no effects
  786. updatePlayerColorPasses();///@todo: this probably doesn't need to be done each frame.
  787. updateFixedLightEnvironments(rinfo);
  788. Customized_Render(rinfo);
  789. Flush(rinfo);
  790. }
  791. else
  792. if (m_customPassMode == SCENE_PASS_ALPHA_MASK)
  793. {
  794. //a projected alpha texture which will later be used to determine where
  795. //wireframe should be visible.
  796. ///@todo: Clearing to black may not be needed if the scene already did the clear.
  797. DX8Wrapper::Set_DX8_Render_State(D3DRS_COLORWRITEENABLE,D3DCOLORWRITEENABLE_ALPHA);
  798. DX8Wrapper::Set_DX8_Render_State (D3DRS_ZBIAS, 0);
  799. //Since all objects will be rendered with same material, disable resetting until all are done.
  800. m_maskMaterialPass->setAllowUninstall(FALSE);
  801. Customized_Render(rinfo); //render mask into alpha channel and fill z-buffer with depth values.
  802. Flush(rinfo);
  803. m_maskMaterialPass->setAllowUninstall(TRUE);
  804. m_maskMaterialPass->UnInstall_Materials();
  805. DX8Wrapper::Set_DX8_Render_State(D3DRS_COLORWRITEENABLE,D3DCOLORWRITEENABLE_BLUE|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_RED);
  806. ShaderClass::Invalidate();
  807. }
  808. }
  809. else
  810. {
  811. Bool old_enable=WW3D::Is_Texturing_Enabled();
  812. if (Get_Extra_Pass_Polygon_Mode() == EXTRA_PASS_CLEAR_LINE)
  813. { //render scene with solid black color but have destination alpha store
  814. //a projected alpha texture which will later be used to determine where
  815. //wireframe should be visible.
  816. ///@todo: Clearing to black may not be needed if the scene already did the clear.
  817. DX8Wrapper::Clear(true, false, Vector3(0.0f,0.0f,0.0f),1.0f); // Clear color but not z
  818. DX8Wrapper::Set_DX8_Render_State(D3DRS_COLORWRITEENABLE,D3DCOLORWRITEENABLE_ALPHA);
  819. DX8Wrapper::Set_DX8_Render_State (D3DRS_ZBIAS, 0);
  820. //We're only filling the z-buffer so ignore normal textures and state changes to speed things up.
  821. m_customPassMode = SCENE_PASS_ALPHA_MASK;
  822. m_maskMaterialPass->setAllowUninstall(FALSE);
  823. Customized_Render(rinfo); //render mask into alpha channel and fill z-buffer with depth values.
  824. Flush(rinfo);
  825. m_maskMaterialPass->setAllowUninstall(TRUE);
  826. m_maskMaterialPass->UnInstall_Materials();
  827. DX8Wrapper::Set_DX8_Render_State(D3DRS_COLORWRITEENABLE,D3DCOLORWRITEENABLE_BLUE|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_RED);
  828. WW3D::Enable_Coloring(0xff008000);
  829. WW3D::Enable_Texturing(false);
  830. DX8Wrapper::Set_DX8_Render_State(D3DRS_FILLMODE,D3DFILL_WIREFRAME);
  831. //Move maximum z-buffer value in a little to shift all z-values closer
  832. //and thus forcing line to appear on top of previous pass.
  833. Real nearZ,farZ;
  834. rinfo.Camera.Get_Zbuffer_Range(nearZ, farZ);
  835. rinfo.Camera.Set_Zbuffer_Range(nearZ, farZ-ZBias);
  836. rinfo.Camera.Apply();
  837. // DX8Wrapper::Set_DX8_Render_State (D3DRS_ZBIAS, 4);
  838. Customized_Render(rinfo); //render wireframe where z-test passes
  839. Flush(rinfo);
  840. DX8Wrapper::Set_DX8_Render_State(D3DRS_FILLMODE,D3DFILL_SOLID);
  841. rinfo.Camera.Set_Zbuffer_Range(nearZ, farZ);
  842. rinfo.Camera.Apply();
  843. // DX8Wrapper::Set_DX8_Render_State (D3DRS_ZBIAS, 0);
  844. WW3D::Enable_Texturing(old_enable);
  845. WW3D::Enable_Coloring(0);
  846. ShaderClass::Invalidate();
  847. }
  848. else
  849. { //old W3D custom rendering code.
  850. //Disable writes to color buffer to save memory bandwidth - we only need Z.
  851. DX8Wrapper::Set_DX8_Render_State(D3DRS_COLORWRITEENABLE,0);
  852. DX8Wrapper::Set_DX8_Render_State (D3DRS_ZBIAS, 0);
  853. Customized_Render(rinfo);
  854. Flush(rinfo);
  855. //Re-enable writes to color buffer.
  856. DX8Wrapper::Set_DX8_Render_State(D3DRS_COLORWRITEENABLE,D3DCOLORWRITEENABLE_BLUE|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_RED);
  857. switch (Get_Extra_Pass_Polygon_Mode()) {
  858. case EXTRA_PASS_LINE:
  859. WW3D::Enable_Texturing(false);
  860. DX8Wrapper::Set_DX8_Render_State(D3DRS_FILLMODE,D3DFILL_WIREFRAME);
  861. DX8Wrapper::Set_DX8_Render_State (D3DRS_ZBIAS, 7);
  862. Customized_Render(rinfo);
  863. break;
  864. case EXTRA_PASS_CLEAR_LINE:
  865. DX8Wrapper::Clear(true, false, Vector3(0.0f,0.0f,0.0f), 0.0f); // Clear color but not z
  866. WW3D::Enable_Texturing(false);
  867. WW3D::Enable_Coloring(0xff008000);
  868. DX8Wrapper::Set_DX8_Render_State(D3DRS_FILLMODE,D3DFILL_WIREFRAME);
  869. DX8Wrapper::Set_DX8_Render_State (D3DRS_ZBIAS, 7);
  870. Customized_Render(rinfo);
  871. break;
  872. }
  873. Flush(rinfo);
  874. DX8Wrapper::Set_DX8_Render_State(D3DRS_FILLMODE,D3DFILL_SOLID);
  875. DX8Wrapper::Set_DX8_Render_State (D3DRS_ZBIAS, 0);
  876. WW3D::Enable_Texturing(old_enable);
  877. WW3D::Enable_Coloring(0);
  878. ShaderClass::Invalidate();
  879. }
  880. }
  881. }
  882. //=============================================================================
  883. // RTS3DScene::Customized_Renderer
  884. //=============================================================================
  885. /** Custom render method for the RTS3DScene, custom render properties for our
  886. * particular game go here */
  887. //=============================================================================
  888. void RTS3DScene::Customized_Render( RenderInfoClass &rinfo )
  889. {
  890. #ifdef DIRTY_CONDITION_FLAGS
  891. StDrawableDirtyStuffLocker lockDirtyStuff;
  892. #endif
  893. RenderObjClass *terrainObject=NULL,*robj;
  894. m_translucentObjectsCount = 0; //start of new frame so no translucent objects
  895. m_occludedObjectsCount = 0;
  896. Int localPlayerIndex = ThePlayerList ? ThePlayerList->getLocalPlayer()->getPlayerIndex() : 0;
  897. #define USE_LIGHT_ENV 1
  898. if (!Visibility_Checked) {
  899. // set the visibility bit in all render objects in all layers.
  900. Visibility_Check(&rinfo.Camera);
  901. #ifdef USE_NON_STENCIL_OCCLUSION
  902. flagOccludedObjects(&rinfo.Camera);
  903. #endif
  904. }
  905. Visibility_Checked = false;
  906. RefRenderObjListIterator it(&UpdateList);
  907. // allow all objects in the update list to do their "every frame" processing
  908. for (it.First(); !it.Is_Done(); it.Next()) {
  909. RenderObjClass * robj = it.Peek_Obj();
  910. if (robj->Class_ID() == RenderObjClass::CLASSID_TILEMAP)
  911. terrainObject=robj; //found terrain object, store for later.
  912. if (!ShaderClass::Is_Backface_Culling_Inverted()) {
  913. // If we are doing water mirror, we draw with backface culling inverted. In this case,
  914. // we only want to call On_Frame_Update if we aren't drawing water, as otherwise
  915. // we get 2 frame updates per frame, and it screws up the particle emitters.
  916. it.Peek_Obj()->On_Frame_Update();
  917. }
  918. }
  919. //terrain needs to be rendered first
  920. if (terrainObject) // Don't check visibility - terrain is always visible. jba.
  921. {
  922. robj=terrainObject;
  923. rinfo.light_environment = NULL; // Terrain is self lit.
  924. rinfo.Camera.Set_User_Data(this); //pass the scene to terrain via user data.
  925. if (m_customPassMode == SCENE_PASS_DEFAULT && m_shroudMaterialPass)
  926. {
  927. rinfo.Push_Material_Pass(m_shroudMaterialPass);
  928. robj->Render(rinfo);
  929. rinfo.Pop_Material_Pass();
  930. }
  931. else
  932. if (m_customPassMode == SCENE_PASS_ALPHA_MASK && m_maskMaterialPass)
  933. {
  934. rinfo.Push_Material_Pass(m_maskMaterialPass);
  935. robj->Render(rinfo);
  936. rinfo.Pop_Material_Pass();
  937. }
  938. else
  939. robj->Render(rinfo);
  940. }
  941. if (m_drawTerrainOnly) {
  942. return;
  943. }
  944. #ifdef EXTENDED_STATS
  945. if (DX8Wrapper::stats.m_disableObjects) {
  946. return;
  947. }
  948. #endif
  949. // loop through all render objects in the list:
  950. for (it.First(&RenderList); !it.Is_Done();)
  951. {
  952. // get the render object
  953. robj = it.Peek_Obj();
  954. it.Next(); //advance to next object in case this one gets deleted during renderOneObject().
  955. if (robj->Class_ID() == RenderObjClass::CLASSID_TILEMAP)
  956. continue; //we already rendered terrain
  957. if (robj->Is_Really_Visible()) {
  958. DrawableInfo *drawInfo = (DrawableInfo *)robj->Get_User_Data();
  959. Drawable *draw=NULL;
  960. if (drawInfo)
  961. draw = drawInfo->m_drawable;
  962. #ifdef USE_NON_STENCIL_OCCLUSION
  963. if (!(draw && drawInfo->m_flags & DrawableInfo::ERF_DELAYED_RENDER)) //model rendering is delayed for some reason until end of normal scene
  964. #else
  965. if (!(draw && drawInfo->m_flags & (DrawableInfo::ERF_DELAYED_RENDER|DrawableInfo::ERF_POTENTIAL_OCCLUDER|DrawableInfo::ERF_IS_NON_OCCLUDER_OR_OCCLUDEE))) //in this mode we delay almost all objects in order to do correct sorting with stencil.
  966. #endif
  967. renderOneObject(rinfo, robj, localPlayerIndex);
  968. }
  969. }
  970. #ifdef INCLUDE_GRANNY_IN_BUILD
  971. if (TheGrannyRenderObjSystem)
  972. { //we only want to update granny animations once per frame, so only queue
  973. //them up if this is not a mirror pass.
  974. if (!ShaderClass::Is_Backface_Culling_Inverted())
  975. TheGrannyRenderObjSystem->queueUpdate();
  976. TheGrannyRenderObjSystem->Flush();
  977. }
  978. #endif
  979. //Tell shadow manager to render shadows at the end of this frame
  980. //Don't draw shadows if there is no terrain present.
  981. if (TheW3DShadowManager && terrainObject && !ShaderClass::Is_Backface_Culling_Inverted() &&
  982. Get_Extra_Pass_Polygon_Mode() == EXTRA_PASS_DISABLE)
  983. TheW3DShadowManager->queueShadows(TRUE);
  984. // only render particles once per frame
  985. if (terrainObject != NULL && TheParticleSystemManager != NULL &&
  986. Get_Extra_Pass_Polygon_Mode() == EXTRA_PASS_DISABLE)
  987. { TheParticleSystemManager->queueParticleRender();
  988. }
  989. } // end Customized_Renderer
  990. /**Convert a player index to a color index, we use this because color indices are
  991. assigned in left-right binary flipped fashion so as not to occupy lower bits unless
  992. necessary. This is used because lower bits are free for use by stencil shadow
  993. rendering*/
  994. #define NUMBER_PLAYER_COLOR_BITS 4 //need 4 bits to encode 8 players because indices start at 1 (not 0).
  995. Int playerIndexToColorIndex(Int playerIndex)
  996. {
  997. Int tmp=playerIndex;
  998. Int result=0;
  999. Int flippedPosition;
  1000. //Player index is stored in 4 bits
  1001. for (Int i=0; i<NUMBER_PLAYER_COLOR_BITS; i++)
  1002. {
  1003. flippedPosition = NUMBER_PLAYER_COLOR_BITS-1-i; //correct position of bit after it's flipped left/right
  1004. if (flippedPosition > i)
  1005. { //shifting left
  1006. result |= (tmp & (1<<i))<<(flippedPosition-i);
  1007. }
  1008. else
  1009. { //shifting right
  1010. result |= (tmp & (1<<i))>>(i-flippedPosition);
  1011. }
  1012. }
  1013. return result;
  1014. }
  1015. /**Utility function used to render a full screen quad with the specified color and
  1016. stencil mask*/
  1017. void renderStenciledPlayerColor( UnsignedInt color, UnsignedInt stencilRef, Bool clear=FALSE)
  1018. {
  1019. struct _TRANSLITVERTEX {
  1020. Vector4 p;
  1021. DWORD color; // diffuse color
  1022. } v[4];
  1023. Int xpos, ypos, width, height;
  1024. TheTacticalView->getOrigin(&xpos,&ypos);
  1025. width=TheTacticalView->getWidth();
  1026. height=TheTacticalView->getHeight();
  1027. v[0].p.Set(xpos+width, ypos+height, 0.0f, 1.0f );
  1028. v[1].p.Set(xpos+width, 0, 0.0f, 1.0f );
  1029. v[2].p.Set(xpos, ypos+height, 0.0f, 1.0f );
  1030. v[3].p.Set(xpos, 0, 0.0f, 1.0f );
  1031. v[0].color = color;
  1032. v[1].color = color;
  1033. v[2].color = color;
  1034. v[3].color = color;
  1035. DX8Wrapper::Set_Shader(PlayerColorShader);
  1036. VertexMaterialClass *vmat=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE);
  1037. DX8Wrapper::Set_Material(vmat);
  1038. REF_PTR_RELEASE(vmat);
  1039. DX8Wrapper::Apply_Render_State_Changes(); //force update all renderstates
  1040. LPDIRECT3DDEVICE8 m_pDev=DX8Wrapper::_Get_D3D_Device8();
  1041. if (!m_pDev)
  1042. return; //need device to render anything.
  1043. //draw polygons like this is very inefficient but for only 2 triangles, it's
  1044. //not worth bothering with index/vertex buffers.
  1045. m_pDev->SetVertexShader(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
  1046. // Set stencil states
  1047. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILENABLE, TRUE );
  1048. DX8Wrapper::Set_DX8_Render_State(D3DRS_ZENABLE, TRUE );
  1049. DWORD oldColorWriteEnable=0x12345678;
  1050. if (clear)
  1051. { //we want to clear the stencil buffer to some known value whereever a player index is stored
  1052. Int occludedMask=TheW3DShadowManager->getStencilShadowMask();
  1053. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILREF, 0x80808080 );
  1054. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILMASK, occludedMask ); //isolate bits containing occluder|playerIndex
  1055. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILWRITEMASK,0xffffffff );
  1056. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILFUNC, D3DCMP_LESS ); //only draw to pixels that match the reference value
  1057. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILZFAIL, D3DSTENCILOP_REPLACE );
  1058. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE ); //pixels which had occluded player colors, get MSB set.
  1059. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILFAIL, D3DSTENCILOP_ZERO ); //pixels which had no occluded player colors are cleared.
  1060. DX8Wrapper::Set_DX8_Render_State(D3DRS_ZFUNC, D3DCMP_NEVER ); //fail all access to the frame buffer to improve memory bandwidth
  1061. //disable writes to color buffer
  1062. if (DX8Caps::Get_Default_Caps().PrimitiveMiscCaps & D3DPMISCCAPS_COLORWRITEENABLE)
  1063. { DX8Wrapper::_Get_D3D_Device8()->GetRenderState(D3DRS_COLORWRITEENABLE, &oldColorWriteEnable);
  1064. DX8Wrapper::Set_DX8_Render_State(D3DRS_COLORWRITEENABLE,0);
  1065. }
  1066. else
  1067. { //device does not support disabling writes to color buffer so fake it through alpha blending
  1068. DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHABLENDENABLE, TRUE);
  1069. DX8Wrapper::Set_DX8_Render_State(D3DRS_SRCBLEND, D3DBLEND_ZERO );
  1070. DX8Wrapper::Set_DX8_Render_State(D3DRS_DESTBLEND, D3DBLEND_ONE );
  1071. }
  1072. }
  1073. else
  1074. { DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILREF, stencilRef );
  1075. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILMASK, 0xffffffff );
  1076. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILWRITEMASK,0xffffffff );
  1077. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILFUNC, D3DCMP_EQUAL );
  1078. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP );
  1079. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP );
  1080. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP );
  1081. //Make occluded pixels transparent
  1082. DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHABLENDENABLE, TRUE);
  1083. DX8Wrapper::Set_DX8_Render_State(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
  1084. DX8Wrapper::Set_DX8_Render_State(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
  1085. }
  1086. if (DX8Wrapper::_Is_Triangle_Draw_Enabled())
  1087. m_pDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v, sizeof(_TRANSLITVERTEX));
  1088. // turn off the stencil buffer
  1089. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILENABLE, FALSE );
  1090. DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHABLENDENABLE, FALSE); //restore shader state
  1091. DX8Wrapper::Set_DX8_Render_State(D3DRS_SRCBLEND, D3DBLEND_ONE );
  1092. DX8Wrapper::Set_DX8_Render_State(D3DRS_DESTBLEND, D3DBLEND_ZERO );
  1093. DX8Wrapper::Set_DX8_Render_State(D3DRS_ZFUNC, D3DCMP_ALWAYS);
  1094. if (oldColorWriteEnable != 0x12345678)
  1095. DX8Wrapper::Set_DX8_Render_State(D3DRS_COLORWRITEENABLE,oldColorWriteEnable);
  1096. } // end renderStencilShadows
  1097. #define MAX_VISIBLE_OCCLUDED_PLAYER_OBJECTS 512 //maximum number of occluded objects permitted per player
  1098. void RTS3DScene::flushOccludedObjectsIntoStencil(RenderInfoClass & rinfo)
  1099. {
  1100. RenderObjClass *robj;
  1101. Drawable *draw;
  1102. RenderObjClass *playerObjects[MAX_PLAYER_COUNT][MAX_VISIBLE_OCCLUDED_PLAYER_OBJECTS];
  1103. RenderObjClass **lastPlayerObject[MAX_PLAYER_COUNT];
  1104. Int playerColorIndex[MAX_PLAYER_COUNT];
  1105. Int visiblePlayerColors[MAX_PLAYER_COUNT]; ///<color assigned to each of the visible players
  1106. Int numObjects;
  1107. Vector3 hsv,rgb;
  1108. Int usedPlayerColorIndex=1;
  1109. Int numVisiblePlayerColors=0;
  1110. //Clear pointers into temporary arrays where each player's objects will be stored.
  1111. //We do this so that all objects are sorted by color which reduces the number of
  1112. //state changes needed when drawing them.
  1113. for (Int i=0; i<MAX_PLAYER_COUNT; i++)
  1114. { lastPlayerObject[i]=&playerObjects[i][0];
  1115. playerColorIndex[i]=-1;
  1116. }
  1117. //Assume no player colors are visible and all stencil bits are free for use by shadows.
  1118. TheW3DShadowManager->setStencilShadowMask(0);
  1119. Int localPlayerIndex = ThePlayerList ? ThePlayerList->getLocalPlayer()->getPlayerIndex() : 0;
  1120. if (m_numPotentialOccludees && m_numPotentialOccluders)
  1121. {
  1122. //bucket sort all possibly occluded objects by player index/color.
  1123. for (Int i=0; i<m_numPotentialOccludees; i++)
  1124. {
  1125. robj=m_potentialOccludees[i];
  1126. draw = ((DrawableInfo *)robj->Get_User_Data())->m_drawable;
  1127. Object *object=draw->getObject();
  1128. Int index=object->getControllingPlayer()->getPlayerIndex();
  1129. if ((lastPlayerObject[index]-&playerObjects[index][0]) >= MAX_VISIBLE_OCCLUDED_PLAYER_OBJECTS)
  1130. {
  1131. DEBUG_ASSERTCRASH(FALSE,("Exceeded Maximum Number of potentially occluded models"));
  1132. continue;
  1133. }
  1134. *lastPlayerObject[index] = robj;
  1135. lastPlayerObject[index]++; //increment to next object
  1136. }
  1137. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILENABLE, TRUE );
  1138. DX8Wrapper::Set_DX8_Render_State(D3DRS_ZENABLE, TRUE );
  1139. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILMASK, 0xffffffff);
  1140. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILWRITEMASK, 0xffffffff);
  1141. //Always store player index into stencil unless it is occluded by another
  1142. //player's potentially occluded objects.
  1143. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILFUNC, D3DCMP_ALWAYS );
  1144. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP );
  1145. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP );
  1146. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE );
  1147. //Find out which player indices are actually used and remap them to
  1148. //a color index. Render all objects using the same color index at once.
  1149. //We render potential occludees first because this allows them to z-sort correctly
  1150. //when they are behind an occluder.
  1151. for (i=0; i<MAX_PLAYER_COUNT; i++)
  1152. {
  1153. if ((numObjects=lastPlayerObject[i]-&playerObjects[i][0]) != 0)
  1154. {
  1155. //this player has some objects so draw them using his color index.
  1156. if (playerColorIndex[i]==-1) //color index not assigned yet?
  1157. { //assign a new color index to this player
  1158. playerColorIndex[i]=playerIndexToColorIndex(usedPlayerColorIndex++);
  1159. //assign a color to this index by copying it from the controlling player
  1160. //of all objects in this list.
  1161. draw = ((DrawableInfo *)playerObjects[i][0]->Get_User_Data())->m_drawable;
  1162. Object *object=draw->getObject();
  1163. Int color=object->getControllingPlayer()->getPlayerColor();
  1164. RGB_To_HSV(hsv,Vector3(((color>>16)&0xff)/255.0f,((color>>8)&0xff)/255.0f,(color &0xff)/255.0f));
  1165. hsv.Z*=TheGlobalData->m_occludedLuminanceScale;
  1166. HSV_To_RGB(rgb,hsv);
  1167. visiblePlayerColors[numVisiblePlayerColors++]=DX8Wrapper::Convert_Color(rgb,0.5f);
  1168. }
  1169. Int thisPlayerColorIndex=playerColorIndex[i];
  1170. //Store this object's color index into bits 3-6 of stencil buffer
  1171. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILREF, thisPlayerColorIndex<<3);
  1172. //Render all of this player's objects for which we care when they are occluded.
  1173. RenderObjClass **renderList=&playerObjects[i][0];
  1174. for (Int j=0; j<numObjects; j++)
  1175. {
  1176. renderOneObject(rinfo, (*renderList), localPlayerIndex);
  1177. renderList++; //advance to next object
  1178. }
  1179. TheDX8MeshRenderer.Flush(); //render all the submitted meshes using current stencil function
  1180. }
  1181. }
  1182. //Stencil buffer is now filled with color indices of potentially occluded objects. We now draw
  1183. //non-occluder or occludee objects such as small rocks, shrubs, etc. which we don't care about
  1184. //but need to render here so that they don't interfere with building occlusion.
  1185. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILENABLE, FALSE ); //these objects are not stored in stencil
  1186. RenderObjClass **nonOccluderOrOccludeeList=m_nonOccludersOrOccludees;
  1187. for (i=0; i<m_numNonOccluderOrOccludee; i++)
  1188. {
  1189. renderOneObject(rinfo, (*nonOccluderOrOccludeeList), localPlayerIndex);
  1190. nonOccluderOrOccludeeList++; //advance to next one
  1191. }
  1192. TheDX8MeshRenderer.Flush(); //render all the submitted meshes using current stencil function
  1193. //Stencil buffer is now filled with color indices of potentially occluded objects. We now draw
  1194. //occluder objects so they cover up and modify stencil MSB wherever they are in front of other objects.
  1195. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILENABLE, TRUE );
  1196. DX8Wrapper::Set_DX8_Render_State(D3DRS_ZENABLE, TRUE );
  1197. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILREF, 0xffffffff);
  1198. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILMASK, 0xffffffff); //isolate lowest player color
  1199. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILWRITEMASK, 0x80); //only write to MSB
  1200. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILFUNC, D3DCMP_ALWAYS ); //check if player colors stored in pixel
  1201. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP );
  1202. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP );
  1203. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE );
  1204. //Render all potential occluders on top of already rendered potential occludees.
  1205. RenderObjClass **occluderList=m_potentialOccluders;
  1206. for (i=0; i<m_numPotentialOccluders; i++)
  1207. {
  1208. renderOneObject(rinfo, (*occluderList), localPlayerIndex);
  1209. occluderList++; //advance to next one
  1210. }
  1211. TheDX8MeshRenderer.Flush(); //render all the submitted meshes using current stencil function
  1212. //We now have a stencil buffer where pixels that are occluded have a bit pattern of 1INDX000.
  1213. //INDX contains the occluded player's color index. We walk through all the player colors and
  1214. //draw them wherever the stencil matches the color's index.
  1215. Int usedPlayerColorBits=0;
  1216. for (i=0; i<numVisiblePlayerColors; i++)
  1217. {
  1218. Int color=visiblePlayerColors[i];
  1219. Int stencilRef=(playerIndexToColorIndex(i+1)<<3)|0x80;
  1220. renderStenciledPlayerColor(color,stencilRef);
  1221. usedPlayerColorBits |= stencilRef; //keep track of all bits used for occlusion/player colors.
  1222. }
  1223. TheW3DShadowManager->setStencilShadowMask(usedPlayerColorBits);
  1224. if (numVisiblePlayerColors >= 8 && TheGlobalData->m_useShadowVolumes)
  1225. { //for cases where we have 8 or more visible players, we're only left with 3 bits to store
  1226. //stencil shadows. That's probably not enough since it will only allow 7 overlapping shadows.
  1227. //So we clear the stencil buffer, leaving only the MSB set on any occluded player pixels so that
  1228. //shadow code knows not to overwrite these pixels.
  1229. renderStenciledPlayerColor(0,0, TRUE);
  1230. TheW3DShadowManager->setStencilShadowMask(0x80808080); //msb indicates occluded player pixels so ignore it when filling screen with shadow
  1231. }
  1232. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILENABLE, FALSE );
  1233. }
  1234. else
  1235. if (m_numNonOccluderOrOccludee || m_numPotentialOccluders || m_numPotentialOccludees)
  1236. { //no occluded objects so don't need to render anything special. Just draw the queued up
  1237. //objects like normal because they were skipped in the main scene traversal.
  1238. RenderObjClass **occludeeList=m_potentialOccludees;
  1239. for (i=0; i<m_numPotentialOccludees; i++)
  1240. {
  1241. renderOneObject(rinfo, (*occludeeList), localPlayerIndex);
  1242. occludeeList++; //advance to next one
  1243. }
  1244. RenderObjClass **occluderList=m_potentialOccluders;
  1245. for (i=0; i<m_numPotentialOccluders; i++)
  1246. {
  1247. renderOneObject(rinfo, (*occluderList), localPlayerIndex);
  1248. occluderList++; //advance to next one
  1249. }
  1250. RenderObjClass **nonOccluderOrOccludeeList=m_nonOccludersOrOccludees;
  1251. for (i=0; i<m_numNonOccluderOrOccludee; i++)
  1252. {
  1253. renderOneObject(rinfo, (*nonOccluderOrOccludeeList), localPlayerIndex);
  1254. nonOccluderOrOccludeeList++; //advance to next one
  1255. }
  1256. TheDX8MeshRenderer.Flush(); //render all the submitted meshes using current stencil function
  1257. }
  1258. //Reset scene ambient because we sometimes mess around with it to make objects
  1259. //glow, etc. when processing drawables. This is a good place to do it because this
  1260. //function gets called right after we flush regular render objects.
  1261. DX8Wrapper::Set_DX8_Render_State(D3DRS_AMBIENT,DX8Wrapper::Convert_Color(this->Get_Ambient_Light(),0.0f));
  1262. }
  1263. /*Version which does not require stencil buffer*/
  1264. void RTS3DScene::flushOccludedObjects(RenderInfoClass & rinfo)
  1265. {
  1266. RenderObjClass *robj;
  1267. Drawable *draw;
  1268. TheW3DShadowManager->setStencilShadowMask(0);
  1269. if (m_occludedObjectsCount)
  1270. {
  1271. Int localPlayerIndex = ThePlayerList ? ThePlayerList->getLocalPlayer()->getPlayerIndex() : 0;
  1272. if (DX8Wrapper::Has_Stencil()) //just in case we have shadows, disable them over occluded pixels.
  1273. {
  1274. //Set all stencil pixels of potentially occluded objects to 128.
  1275. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILENABLE, TRUE );
  1276. DX8Wrapper::Set_DX8_Render_State(D3DRS_ZENABLE, TRUE );
  1277. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILREF, 128 );
  1278. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILMASK, 0xffffffff );
  1279. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILWRITEMASK,0xffffffff );
  1280. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP );
  1281. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP );
  1282. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE );
  1283. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILFUNC, D3DCMP_ALWAYS );
  1284. }
  1285. //First draw all the solid colored models
  1286. ///@todo: Optimize this so that the extra passes don't actually install the material since it's all the same.
  1287. rinfo.Push_Override_Flags(RenderInfoClass::RINFO_OVERRIDE_ADDITIONAL_PASSES_ONLY); //disable textures
  1288. for (Int i=0; i<m_occludedObjectsCount; i++)
  1289. {
  1290. robj=m_potentialOccludees[i];
  1291. draw = ((DrawableInfo *)robj->Get_User_Data())->m_drawable;
  1292. Object *object=draw->getObject();
  1293. Int index=object->getControllingPlayer()->getPlayerIndex();
  1294. rinfo.Push_Material_Pass(m_occludedMaterialPass[index]);
  1295. robj->Render(rinfo);
  1296. rinfo.Pop_Material_Pass();
  1297. }
  1298. rinfo.Pop_Override_Flags();
  1299. TheDX8MeshRenderer.Flush();
  1300. //Now draw the normal models so they cover up the colored models on any pixels that
  1301. //Now draw the normal models so they cover up the colored models on any pixels that
  1302. //Normal models will clear stencil value from 128 back to 0 where the object pixels are
  1303. //not occluded but will leave 128 in stencil where still occluded.
  1304. if (DX8Wrapper::Has_Stencil())
  1305. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILREF, 0 );
  1306. for (i=0; i<m_occludedObjectsCount; i++)
  1307. {
  1308. robj=m_potentialOccludees[i];
  1309. renderOneObject(rinfo, robj, localPlayerIndex);//WW3D::Render(*robj,rinfo);
  1310. }
  1311. //Flush all the submitted translucent objects.
  1312. TheDX8MeshRenderer.Flush();
  1313. m_occludedObjectsCount = 0;
  1314. DX8Wrapper::Set_DX8_Render_State(D3DRS_STENCILENABLE, FALSE );
  1315. TheW3DShadowManager->setStencilShadowMask(0x80808080); //upper MSB always contains flag indicating occluded player color.
  1316. }
  1317. //Reset scene ambient because we sometimes mess around with it to make objects
  1318. //glow, etc. when processing drawables. This is a good place to do it because this
  1319. //function gets called right after we flush regular render objects.
  1320. DX8Wrapper::Set_DX8_Render_State(D3DRS_AMBIENT,DX8Wrapper::Convert_Color(this->Get_Ambient_Light(),0.0f));
  1321. }
  1322. void RTS3DScene::flushTranslucentObjects(RenderInfoClass & rinfo)
  1323. {
  1324. RenderObjClass *robj;
  1325. Drawable *draw;
  1326. if (m_translucentObjectsCount)
  1327. {
  1328. Int localPlayerIndex = ThePlayerList ? ThePlayerList->getLocalPlayer()->getPlayerIndex() : 0;
  1329. for (Int i=0; i<m_translucentObjectsCount; i++)
  1330. {
  1331. robj=m_translucentObjectsBuffer[i];
  1332. draw = ((DrawableInfo *)robj->Get_User_Data())->m_drawable;
  1333. rinfo.alphaOverride = draw->getEffectiveOpacity();
  1334. renderOneObject(rinfo, robj, localPlayerIndex);//WW3D::Render(*robj,rinfo);
  1335. }
  1336. //Flush all the submitted translucent objects.
  1337. TheDX8MeshRenderer.Flush();
  1338. WW3D::Render_And_Clear_Static_Sort_Lists(rinfo); //draws things like water
  1339. rinfo.alphaOverride = 1.0f; //disable forced alpha
  1340. m_translucentObjectsCount = 0;
  1341. }
  1342. //Reset scene ambient because we sometimes mess around with it to make objects
  1343. //glow, etc. when processing drawables. This is a good place to do it because this
  1344. //function gets called right after we flush regular render objects.
  1345. DX8Wrapper::Set_DX8_Render_State(D3DRS_AMBIENT,DX8Wrapper::Convert_Color(this->Get_Ambient_Light(),0.0f));
  1346. }
  1347. //=============================================================================
  1348. // RTS3DScene::createLightsIterator
  1349. //=============================================================================
  1350. /** Returns an iterator of the lights in the scene. */
  1351. //=============================================================================
  1352. RefRenderObjListIterator * RTS3DScene::createLightsIterator(void)
  1353. {
  1354. RefRenderObjListIterator * it = NEW RefRenderObjListIterator(&LightList); // poolify
  1355. return it;
  1356. }
  1357. //=============================================================================
  1358. // RTS3DScene::destroyLightsIterator
  1359. //=============================================================================
  1360. /** Destroys the iterator returned by createLightsIterator. */
  1361. //=============================================================================
  1362. void RTS3DScene::destroyLightsIterator(RefRenderObjListIterator * it)
  1363. {
  1364. delete it;
  1365. }
  1366. //=============================================================================
  1367. // RTS3DScene::addDynamicLight
  1368. //=============================================================================
  1369. /** Adds a dynamic light. */
  1370. //=============================================================================
  1371. void RTS3DScene::addDynamicLight(W3DDynamicLight * obj)
  1372. {
  1373. m_dynamicLightList.Add(obj);
  1374. UpdateList.Add(obj);
  1375. }
  1376. //=============================================================================
  1377. // RTS3DScene::addDynamicLight
  1378. //=============================================================================
  1379. /** Adds a dynamic light. */
  1380. //=============================================================================
  1381. W3DDynamicLight * RTS3DScene::getADynamicLight(void)
  1382. {
  1383. RefRenderObjListIterator dynaLightIt(&m_dynamicLightList);
  1384. W3DDynamicLight *pLight;
  1385. for (dynaLightIt.First(); !dynaLightIt.Is_Done(); dynaLightIt.Next())
  1386. {
  1387. pLight = (W3DDynamicLight*)dynaLightIt.Peek_Obj();
  1388. if (!pLight->isEnabled()) {
  1389. pLight->setEnabled(true);
  1390. return(pLight);
  1391. }
  1392. }
  1393. pLight = NEW_REF(W3DDynamicLight, ());
  1394. addDynamicLight( pLight );
  1395. pLight->Release_Ref();
  1396. pLight->setEnabled(true);
  1397. return(pLight);
  1398. }
  1399. //=============================================================================
  1400. // RTS3DScene::removeDynamicLight
  1401. //=============================================================================
  1402. /** Removes a dynamic light. */
  1403. //=============================================================================
  1404. void RTS3DScene::removeDynamicLight(W3DDynamicLight * obj)
  1405. {
  1406. m_dynamicLightList.Remove(obj);
  1407. }
  1408. //=============================================================================
  1409. // RTS3DScene::doRender
  1410. //=============================================================================
  1411. /** Render the scene */
  1412. //=============================================================================
  1413. void RTS3DScene::doRender( CameraClass * cam )
  1414. {
  1415. m_camera = cam;
  1416. DRAW();
  1417. m_camera = NULL;
  1418. } // end Customized_Render
  1419. //=============================================================================
  1420. // RTS3DScene::draw
  1421. //=============================================================================
  1422. /** Customized render for the 2d scene management */
  1423. //=============================================================================
  1424. void RTS3DScene::draw( )
  1425. {
  1426. if (m_camera == NULL) {
  1427. DEBUG_CRASH(("Null m_camera in RTS3DScene::draw"));
  1428. return;
  1429. }
  1430. WW3D::Render( this, m_camera );
  1431. } // end Customized_Render
  1432. ///////////////////////////////////////////////////////////////////////////////
  1433. ///////////////////////////////////////////////////////////////////////////////
  1434. ///////////////////////////////////////////////////////////////////////////////
  1435. //=============================================================================
  1436. // RTS2DScene::RTS2DScene
  1437. //=============================================================================
  1438. /** */
  1439. //=============================================================================
  1440. RTS2DScene::RTS2DScene()
  1441. {
  1442. setName("RTS2DScene");
  1443. m_status = NEW_REF( W3DStatusCircle, () );
  1444. Add_Render_Object( m_status );
  1445. } // end RTS2DScene
  1446. //=============================================================================
  1447. // RTS2DScene::~RTS2DScene
  1448. //=============================================================================
  1449. /** */
  1450. //=============================================================================
  1451. RTS2DScene::~RTS2DScene()
  1452. {
  1453. this->Remove_Render_Object(m_status);
  1454. REF_PTR_RELEASE(m_status);
  1455. } // end ~RTS2DScene
  1456. //=============================================================================
  1457. // RTS2DScene::Custimized_Render
  1458. //=============================================================================
  1459. /** Customized render for the 2d scene management */
  1460. //=============================================================================
  1461. void RTS2DScene::Customized_Render( RenderInfoClass &rinfo )
  1462. {
  1463. // call simple scene class renderer
  1464. SimpleSceneClass::Customized_Render( rinfo );
  1465. } // end Customized_Render
  1466. //=============================================================================
  1467. // RTS2DScene::doRender
  1468. //=============================================================================
  1469. /** Render the scene */
  1470. //=============================================================================
  1471. void RTS2DScene::doRender( CameraClass * cam )
  1472. {
  1473. m_camera = cam;
  1474. DRAW();
  1475. m_camera = NULL;
  1476. } // end Customized_Render
  1477. //=============================================================================
  1478. // RTS2DScene::draw
  1479. //=============================================================================
  1480. /** Customized render for the 2d scene management */
  1481. //=============================================================================
  1482. void RTS2DScene::draw( )
  1483. {
  1484. if (m_camera == NULL) {
  1485. DEBUG_CRASH(("Null m_camera in RTS2DScene::draw"));
  1486. return;
  1487. }
  1488. WW3D::Render( this, m_camera );
  1489. } // end Customized_Render
  1490. ///////////////////////////////////////////////////////////////////////////////
  1491. ///////////////////////////////////////////////////////////////////////////////
  1492. ///////////////////////////////////////////////////////////////////////////////
  1493. //=============================================================================
  1494. // RTS3DInterfaceScene::RTS3DInterfaceScene
  1495. //=============================================================================
  1496. /** */
  1497. //=============================================================================
  1498. RTS3DInterfaceScene::RTS3DInterfaceScene()
  1499. {
  1500. } // end RTS3DInterfaceScene
  1501. //=============================================================================
  1502. // RTS3DInterfaceScene::~RTS3DInterfaceScene
  1503. //=============================================================================
  1504. /** */
  1505. //=============================================================================
  1506. RTS3DInterfaceScene::~RTS3DInterfaceScene()
  1507. {
  1508. } // end ~RTS3DInterfaceScene
  1509. //=============================================================================
  1510. // RTS3DInterfaceScene::Custimized_Render
  1511. //=============================================================================
  1512. /** Customized render for the 3d interface scene management */
  1513. //=============================================================================
  1514. void RTS3DInterfaceScene::Customized_Render( RenderInfoClass &rinfo )
  1515. {
  1516. // call simple scene class renderer
  1517. SimpleSceneClass::Customized_Render( rinfo );
  1518. } // end Customized_Render