W3DScene.cpp 76 KB

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