Renderer.cpp 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767
  1. //
  2. // Copyright (c) 2008-2014 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "Precompiled.h"
  23. #include "Camera.h"
  24. #include "CoreEvents.h"
  25. #include "DebugRenderer.h"
  26. #include "Geometry.h"
  27. #include "Graphics.h"
  28. #include "GraphicsEvents.h"
  29. #include "GraphicsImpl.h"
  30. #include "IndexBuffer.h"
  31. #include "Log.h"
  32. #include "Material.h"
  33. #include "OcclusionBuffer.h"
  34. #include "Octree.h"
  35. #include "Profiler.h"
  36. #include "Renderer.h"
  37. #include "RenderPath.h"
  38. #include "ResourceCache.h"
  39. #include "Scene.h"
  40. #include "Shader.h"
  41. #include "ShaderVariation.h"
  42. #include "Technique.h"
  43. #include "Texture2D.h"
  44. #include "TextureCube.h"
  45. #include "VertexBuffer.h"
  46. #include "View.h"
  47. #include "XMLFile.h"
  48. #include "Zone.h"
  49. #include "DebugNew.h"
  50. namespace Urho3D
  51. {
  52. static const float dirLightVertexData[] =
  53. {
  54. -1, 1, 0,
  55. 1, 1, 0,
  56. 1, -1, 0,
  57. -1, -1, 0,
  58. };
  59. static const unsigned short dirLightIndexData[] =
  60. {
  61. 0, 1, 2,
  62. 2, 3, 0,
  63. };
  64. static const float pointLightVertexData[] =
  65. {
  66. -0.423169f, -1.000000f, 0.423169f,
  67. -0.423169f, -1.000000f, -0.423169f,
  68. 0.423169f, -1.000000f, -0.423169f,
  69. 0.423169f, -1.000000f, 0.423169f,
  70. 0.423169f, 1.000000f, -0.423169f,
  71. -0.423169f, 1.000000f, -0.423169f,
  72. -0.423169f, 1.000000f, 0.423169f,
  73. 0.423169f, 1.000000f, 0.423169f,
  74. -1.000000f, 0.423169f, -0.423169f,
  75. -1.000000f, -0.423169f, -0.423169f,
  76. -1.000000f, -0.423169f, 0.423169f,
  77. -1.000000f, 0.423169f, 0.423169f,
  78. 0.423169f, 0.423169f, -1.000000f,
  79. 0.423169f, -0.423169f, -1.000000f,
  80. -0.423169f, -0.423169f, -1.000000f,
  81. -0.423169f, 0.423169f, -1.000000f,
  82. 1.000000f, 0.423169f, 0.423169f,
  83. 1.000000f, -0.423169f, 0.423169f,
  84. 1.000000f, -0.423169f, -0.423169f,
  85. 1.000000f, 0.423169f, -0.423169f,
  86. 0.423169f, -0.423169f, 1.000000f,
  87. 0.423169f, 0.423169f, 1.000000f,
  88. -0.423169f, 0.423169f, 1.000000f,
  89. -0.423169f, -0.423169f, 1.000000f
  90. };
  91. static const unsigned short pointLightIndexData[] =
  92. {
  93. 0, 1, 2,
  94. 0, 2, 3,
  95. 4, 5, 6,
  96. 4, 6, 7,
  97. 8, 9, 10,
  98. 8, 10, 11,
  99. 12, 13, 14,
  100. 12, 14, 15,
  101. 16, 17, 18,
  102. 16, 18, 19,
  103. 20, 21, 22,
  104. 20, 22, 23,
  105. 0, 10, 9,
  106. 0, 9, 1,
  107. 13, 2, 1,
  108. 13, 1, 14,
  109. 23, 0, 3,
  110. 23, 3, 20,
  111. 17, 3, 2,
  112. 17, 2, 18,
  113. 21, 7, 6,
  114. 21, 6, 22,
  115. 7, 16, 19,
  116. 7, 19, 4,
  117. 5, 8, 11,
  118. 5, 11, 6,
  119. 4, 12, 15,
  120. 4, 15, 5,
  121. 22, 11, 10,
  122. 22, 10, 23,
  123. 8, 15, 14,
  124. 8, 14, 9,
  125. 12, 19, 18,
  126. 12, 18, 13,
  127. 16, 21, 20,
  128. 16, 20, 17,
  129. 0, 23, 10,
  130. 1, 9, 14,
  131. 2, 13, 18,
  132. 3, 17, 20,
  133. 6, 11, 22,
  134. 5, 15, 8,
  135. 4, 19, 12,
  136. 7, 21, 16
  137. };
  138. static const float spotLightVertexData[] =
  139. {
  140. 0.00001f, 0.00001f, 0.00001f,
  141. 0.00001f, -0.00001f, 0.00001f,
  142. -0.00001f, -0.00001f, 0.00001f,
  143. -0.00001f, 0.00001f, 0.00001f,
  144. 1.00000f, 1.00000f, 0.99999f,
  145. 1.00000f, -1.00000f, 0.99999f,
  146. -1.00000f, -1.00000f, 0.99999f,
  147. -1.00000f, 1.00000f, 0.99999f,
  148. };
  149. static const unsigned short spotLightIndexData[] =
  150. {
  151. 3, 0, 1,
  152. 3, 1, 2,
  153. 0, 4, 5,
  154. 0, 5, 1,
  155. 3, 7, 4,
  156. 3, 4, 0,
  157. 7, 3, 2,
  158. 7, 2, 6,
  159. 6, 2, 1,
  160. 6, 1, 5,
  161. 7, 5, 4,
  162. 7, 6, 5
  163. };
  164. static const char* shadowVariations[] =
  165. {
  166. #ifdef USE_OPENGL
  167. // No specific hardware shadow compare variation on OpenGL, it is always supported
  168. "LQSHADOW ",
  169. "LQSHADOW ",
  170. "",
  171. ""
  172. #else
  173. // On Direct3D the quality is always "low" if not using hardware shadow compare
  174. "",
  175. "LQSHADOW HWSHADOW ",
  176. "",
  177. "HWSHADOW "
  178. #endif
  179. };
  180. static const char* geometryVSVariations[] =
  181. {
  182. "",
  183. "SKINNED ",
  184. "INSTANCED ",
  185. "BILLBOARD "
  186. };
  187. static const char* lightVSVariations[] =
  188. {
  189. "PERPIXEL DIRLIGHT ",
  190. "PERPIXEL SPOTLIGHT ",
  191. "PERPIXEL POINTLIGHT ",
  192. "PERPIXEL DIRLIGHT SPECULAR ",
  193. "PERPIXEL SPOTLIGHT SPECULAR ",
  194. "PERPIXEL POINTLIGHT SPECULAR ",
  195. "PERPIXEL DIRLIGHT SHADOW ",
  196. "PERPIXEL SPOTLIGHT SHADOW ",
  197. "PERPIXEL POINTLIGHT SHADOW ",
  198. "PERPIXEL DIRLIGHT SPECULAR SHADOW ",
  199. "PERPIXEL SPOTLIGHT SPECULAR SHADOW ",
  200. "PERPIXEL POINTLIGHT SPECULAR SHADOW "
  201. };
  202. static const char* vertexLightVSVariations[] =
  203. {
  204. "",
  205. "NUMVERTEXLIGHTS=1 ",
  206. "NUMVERTEXLIGHTS=2 ",
  207. "NUMVERTEXLIGHTS=3 ",
  208. "NUMVERTEXLIGHTS=4 ",
  209. };
  210. static const char* deferredLightVSVariations[] =
  211. {
  212. "",
  213. "DIRLIGHT ",
  214. "ORTHO ",
  215. "DIRLIGHT ORTHO "
  216. };
  217. static const char* lightPSVariations[] =
  218. {
  219. "PERPIXEL DIRLIGHT ",
  220. "PERPIXEL SPOTLIGHT ",
  221. "PERPIXEL POINTLIGHT ",
  222. "PERPIXEL POINTLIGHT CUBEMASK ",
  223. "PERPIXEL DIRLIGHT SPECULAR ",
  224. "PERPIXEL SPOTLIGHT SPECULAR ",
  225. "PERPIXEL POINTLIGHT SPECULAR ",
  226. "PERPIXEL POINTLIGHT CUBEMASK SPECULAR ",
  227. "PERPIXEL DIRLIGHT SHADOW ",
  228. "PERPIXEL SPOTLIGHT SHADOW ",
  229. "PERPIXEL POINTLIGHT SHADOW ",
  230. "PERPIXEL POINTLIGHT CUBEMASK SHADOW ",
  231. "PERPIXEL DIRLIGHT SPECULAR SHADOW ",
  232. "PERPIXEL SPOTLIGHT SPECULAR SHADOW ",
  233. "PERPIXEL POINTLIGHT SPECULAR SHADOW ",
  234. "PERPIXEL POINTLIGHT CUBEMASK SPECULAR SHADOW "
  235. };
  236. static const unsigned INSTANCING_BUFFER_MASK = MASK_INSTANCEMATRIX1 | MASK_INSTANCEMATRIX2 | MASK_INSTANCEMATRIX3;
  237. static const unsigned MAX_BUFFER_AGE = 1000;
  238. Renderer::Renderer(Context* context) :
  239. Object(context),
  240. defaultZone_(new Zone(context)),
  241. quadDirLight_(new Light(context)),
  242. textureAnisotropy_(4),
  243. textureFilterMode_(FILTER_TRILINEAR),
  244. textureQuality_(QUALITY_HIGH),
  245. materialQuality_(QUALITY_HIGH),
  246. shadowMapSize_(1024),
  247. shadowQuality_(SHADOWQUALITY_HIGH_16BIT),
  248. maxShadowMaps_(1),
  249. maxShadowCascades_(MAX_CASCADE_SPLITS),
  250. minInstances_(2),
  251. maxInstanceTriangles_(500),
  252. maxSortedInstances_(1000),
  253. maxOccluderTriangles_(5000),
  254. occlusionBufferSize_(256),
  255. occluderSizeThreshold_(0.025f),
  256. numViews_(0),
  257. numOcclusionBuffers_(0),
  258. numShadowCameras_(0),
  259. shadersChangedFrameNumber_(M_MAX_UNSIGNED),
  260. hdrRendering_(false),
  261. specularLighting_(true),
  262. drawShadows_(true),
  263. reuseShadowMaps_(true),
  264. dynamicInstancing_(true),
  265. shadersDirty_(true),
  266. initialized_(false)
  267. {
  268. #ifndef USE_OPENGL
  269. shaderPath_ = "Shaders/HLSL/";
  270. shaderExtension_ = ".hlsl";
  271. #else
  272. shaderPath_ = "Shaders/GLSL/";
  273. shaderExtension_ = ".glsl";
  274. #endif
  275. SubscribeToEvent(E_SCREENMODE, HANDLER(Renderer, HandleScreenMode));
  276. SubscribeToEvent(E_GRAPHICSFEATURES, HANDLER(Renderer, HandleGraphicsFeatures));
  277. quadDirLight_->SetLightType(LIGHT_DIRECTIONAL);
  278. // Try to initialize right now, but skip if screen mode is not yet set
  279. Initialize();
  280. }
  281. Renderer::~Renderer()
  282. {
  283. }
  284. void Renderer::SetNumViewports(unsigned num)
  285. {
  286. viewports_.Resize(num);
  287. }
  288. void Renderer::SetViewport(unsigned index, Viewport* viewport)
  289. {
  290. if (index >= viewports_.Size())
  291. viewports_.Resize(index + 1);
  292. viewports_[index] = viewport;
  293. }
  294. void Renderer::SetDefaultRenderPath(RenderPath* renderPath)
  295. {
  296. if (renderPath)
  297. defaultRenderPath_ = renderPath;
  298. }
  299. void Renderer::SetDefaultRenderPath(XMLFile* xmlFile)
  300. {
  301. SharedPtr<RenderPath> newRenderPath(new RenderPath());
  302. if (newRenderPath->Load(xmlFile))
  303. defaultRenderPath_ = newRenderPath;
  304. }
  305. void Renderer::SetHDRRendering(bool enable)
  306. {
  307. hdrRendering_ = enable;
  308. }
  309. void Renderer::SetSpecularLighting(bool enable)
  310. {
  311. specularLighting_ = enable;
  312. }
  313. void Renderer::SetTextureAnisotropy(int level)
  314. {
  315. textureAnisotropy_ = Max(level, 1);
  316. }
  317. void Renderer::SetTextureFilterMode(TextureFilterMode mode)
  318. {
  319. textureFilterMode_ = mode;
  320. }
  321. void Renderer::SetTextureQuality(int quality)
  322. {
  323. quality = Clamp(quality, QUALITY_LOW, QUALITY_HIGH);
  324. if (quality != textureQuality_)
  325. {
  326. textureQuality_ = quality;
  327. ReloadTextures();
  328. }
  329. }
  330. void Renderer::SetMaterialQuality(int quality)
  331. {
  332. materialQuality_ = Clamp(quality, QUALITY_LOW, QUALITY_MAX);
  333. shadersDirty_ = true;
  334. ResetViews();
  335. }
  336. void Renderer::SetDrawShadows(bool enable)
  337. {
  338. if (!graphics_ || !graphics_->GetShadowMapFormat())
  339. return;
  340. drawShadows_ = enable;
  341. if (!drawShadows_)
  342. ResetShadowMaps();
  343. }
  344. void Renderer::SetShadowMapSize(int size)
  345. {
  346. if (!graphics_)
  347. return;
  348. size = NextPowerOfTwo(Max(size, SHADOW_MIN_PIXELS));
  349. if (size != shadowMapSize_)
  350. {
  351. shadowMapSize_ = size;
  352. ResetShadowMaps();
  353. }
  354. }
  355. void Renderer::SetShadowQuality(int quality)
  356. {
  357. if (!graphics_)
  358. return;
  359. quality &= SHADOWQUALITY_HIGH_24BIT;
  360. // If no hardware PCF, do not allow to select one-sample quality
  361. if (!graphics_->GetHardwareShadowSupport())
  362. quality |= SHADOWQUALITY_HIGH_16BIT;
  363. if (!graphics_->GetHiresShadowMapFormat())
  364. quality &= SHADOWQUALITY_HIGH_16BIT;
  365. if (quality != shadowQuality_)
  366. {
  367. shadowQuality_ = quality;
  368. shadersDirty_ = true;
  369. ResetShadowMaps();
  370. }
  371. }
  372. void Renderer::SetReuseShadowMaps(bool enable)
  373. {
  374. if (enable == reuseShadowMaps_)
  375. return;
  376. reuseShadowMaps_ = enable;
  377. }
  378. void Renderer::SetMaxShadowMaps(int shadowMaps)
  379. {
  380. if (shadowMaps < 1)
  381. return;
  382. maxShadowMaps_ = shadowMaps;
  383. for (HashMap<int, Vector<SharedPtr<Texture2D> > >::Iterator i = shadowMaps_.Begin(); i != shadowMaps_.End(); ++i)
  384. {
  385. if ((int)i->second_.Size() > maxShadowMaps_)
  386. i->second_.Resize(maxShadowMaps_);
  387. }
  388. }
  389. void Renderer::SetMaxShadowCascades(int cascades)
  390. {
  391. cascades = Clamp(cascades, 1, MAX_CASCADE_SPLITS);
  392. if (cascades != maxShadowCascades_)
  393. {
  394. maxShadowCascades_ = cascades;
  395. ResetShadowMaps();
  396. }
  397. }
  398. void Renderer::SetDynamicInstancing(bool enable)
  399. {
  400. if (!instancingBuffer_)
  401. enable = false;
  402. dynamicInstancing_ = enable;
  403. }
  404. void Renderer::SetMinInstances(int instances)
  405. {
  406. minInstances_ = Max(instances, 2);
  407. }
  408. void Renderer::SetMaxInstanceTriangles(int triangles)
  409. {
  410. maxInstanceTriangles_ = Max(triangles, 0);
  411. }
  412. void Renderer::SetMaxSortedInstances(int instances)
  413. {
  414. maxSortedInstances_ = Max(instances, 0);
  415. }
  416. void Renderer::SetMaxOccluderTriangles(int triangles)
  417. {
  418. maxOccluderTriangles_ = Max(triangles, 0);
  419. }
  420. void Renderer::SetOcclusionBufferSize(int size)
  421. {
  422. occlusionBufferSize_ = Max(size, 1);
  423. occlusionBuffers_.Clear();
  424. }
  425. void Renderer::SetOccluderSizeThreshold(float screenSize)
  426. {
  427. occluderSizeThreshold_ = Max(screenSize, 0.0f);
  428. }
  429. void Renderer::ReloadShaders()
  430. {
  431. shadersDirty_ = true;
  432. }
  433. Viewport* Renderer::GetViewport(unsigned index) const
  434. {
  435. return index < viewports_.Size() ? viewports_[index] : (Viewport*)0;
  436. }
  437. RenderPath* Renderer::GetDefaultRenderPath() const
  438. {
  439. return defaultRenderPath_;
  440. }
  441. unsigned Renderer::GetNumGeometries(bool allViews) const
  442. {
  443. unsigned numGeometries = 0;
  444. unsigned lastView = allViews ? numViews_ : 1;
  445. for (unsigned i = 0; i < lastView; ++i)
  446. numGeometries += views_[i]->GetGeometries().Size();
  447. return numGeometries;
  448. }
  449. unsigned Renderer::GetNumLights(bool allViews) const
  450. {
  451. unsigned numLights = 0;
  452. unsigned lastView = allViews ? numViews_ : 1;
  453. for (unsigned i = 0; i < lastView; ++i)
  454. numLights += views_[i]->GetLights().Size();
  455. return numLights;
  456. }
  457. unsigned Renderer::GetNumShadowMaps(bool allViews) const
  458. {
  459. unsigned numShadowMaps = 0;
  460. unsigned lastView = allViews ? numViews_ : 1;
  461. for (unsigned i = 0; i < lastView; ++i)
  462. {
  463. const Vector<LightBatchQueue>& lightQueues = views_[i]->GetLightQueues();
  464. for (Vector<LightBatchQueue>::ConstIterator i = lightQueues.Begin(); i != lightQueues.End(); ++i)
  465. {
  466. if (i->shadowMap_)
  467. ++numShadowMaps;
  468. }
  469. }
  470. return numShadowMaps;
  471. }
  472. unsigned Renderer::GetNumOccluders(bool allViews) const
  473. {
  474. unsigned numOccluders = 0;
  475. unsigned lastView = allViews ? numViews_ : 1;
  476. for (unsigned i = 0; i < lastView; ++i)
  477. numOccluders += views_[i]->GetOccluders().Size();
  478. return numOccluders;
  479. }
  480. ShaderVariation* Renderer::GetShader(ShaderType type, const String& name, const String& defines) const
  481. {
  482. return GetShader(type, name.CString(), defines.CString());
  483. }
  484. ShaderVariation* Renderer::GetShader(ShaderType type, const char* name, const char* defines) const
  485. {
  486. if (lastShaderName_ != name || !lastShader_)
  487. {
  488. ResourceCache* cache = GetSubsystem<ResourceCache>();
  489. if (!cache)
  490. return 0;
  491. lastShader_ = cache->GetResource<Shader>(shaderPath_ + name + shaderExtension_);
  492. lastShaderName_ = name;
  493. }
  494. return lastShader_ ? lastShader_->GetVariation(type, defines) : (ShaderVariation*)0;
  495. }
  496. void Renderer::Update(float timeStep)
  497. {
  498. PROFILE(UpdateViews);
  499. numViews_ = 0;
  500. // If device lost, do not perform update. This is because any dynamic vertex/index buffer updates happen already here,
  501. // and if the device is lost, the updates queue up, causing memory use to rise constantly
  502. if (!graphics_ || !graphics_->IsInitialized() || graphics_->IsDeviceLost())
  503. return;
  504. // Set up the frameinfo structure for this frame
  505. frame_.frameNumber_ = GetSubsystem<Time>()->GetFrameNumber();
  506. frame_.timeStep_ = timeStep;
  507. frame_.camera_ = 0;
  508. numShadowCameras_ = 0;
  509. numOcclusionBuffers_ = 0;
  510. updatedOctrees_.Clear();
  511. // Reload shaders now if needed
  512. if (shadersDirty_)
  513. LoadShaders();
  514. // Queue update of the main viewports. Use reverse order, as rendering order is also reverse
  515. // to render auxiliary views before dependant main views
  516. for (unsigned i = viewports_.Size() - 1; i < viewports_.Size(); --i)
  517. QueueViewport(0, viewports_[i]);
  518. // Gather other render surfaces that are autoupdated
  519. SendEvent(E_RENDERSURFACEUPDATE);
  520. // Process gathered views. This may queue further views (render surfaces that are only updated when visible)
  521. for (unsigned i = 0; i < queuedViews_.Size(); ++i)
  522. {
  523. WeakPtr<RenderSurface>& renderTarget = queuedViews_[i].first_;
  524. WeakPtr<Viewport>& viewport = queuedViews_[i].second_;
  525. // Null pointer means backbuffer view. Differentiate between that and an expired rendersurface
  526. if ((renderTarget.NotNull() && renderTarget.Expired()) || viewport.Expired())
  527. continue;
  528. // Allocate new view if necessary
  529. if (numViews_ == views_.Size())
  530. views_.Push(SharedPtr<View>(new View(context_)));
  531. // Check if view can be defined successfully (has valid scene, camera and octree)
  532. assert(numViews_ < views_.Size());
  533. View* view = views_[numViews_];
  534. if (!view->Define(renderTarget, viewport))
  535. continue;
  536. ++numViews_;
  537. const IntRect& viewRect = viewport->GetRect();
  538. Scene* scene = viewport->GetScene();
  539. Octree* octree = scene->GetComponent<Octree>();
  540. // Update octree (perform early update for drawables which need that, and reinsert moved drawables.)
  541. // However, if the same scene is viewed from multiple cameras, update the octree only once
  542. if (!updatedOctrees_.Contains(octree))
  543. {
  544. frame_.camera_ = viewport->GetCamera();
  545. frame_.viewSize_ = viewRect.Size();
  546. if (frame_.viewSize_ == IntVector2::ZERO)
  547. frame_.viewSize_ = IntVector2(graphics_->GetWidth(), graphics_->GetHeight());
  548. octree->Update(frame_);
  549. updatedOctrees_.Insert(octree);
  550. // Set also the view for the debug renderer already here, so that it can use culling
  551. /// \todo May result in incorrect debug geometry culling if the same scene is drawn from multiple viewports
  552. DebugRenderer* debug = scene->GetComponent<DebugRenderer>();
  553. if (debug)
  554. debug->SetView(viewport->GetCamera());
  555. }
  556. // Update view. This may queue further views
  557. using namespace BeginViewUpdate;
  558. VariantMap& eventData = GetEventDataMap();
  559. eventData[P_SURFACE] = (void*)renderTarget.Get();
  560. eventData[P_TEXTURE] = (void*)(renderTarget ? renderTarget->GetParentTexture() : 0);
  561. eventData[P_SCENE] = (void*)scene;
  562. eventData[P_CAMERA] = (void*)viewport->GetCamera();
  563. SendEvent(E_BEGINVIEWUPDATE, eventData);
  564. ResetShadowMapAllocations(); // Each view can reuse the same shadow maps
  565. view->Update(frame_);
  566. SendEvent(E_ENDVIEWUPDATE, eventData);
  567. }
  568. // Reset update flag from queued render surfaces. At this point no new views can be added on this frame
  569. for (unsigned i = 0; i < queuedViews_.Size(); ++i)
  570. {
  571. WeakPtr<RenderSurface>& renderTarget = queuedViews_[i].first_;
  572. if (renderTarget)
  573. renderTarget->WasUpdated();
  574. }
  575. queuedViews_.Clear();
  576. }
  577. void Renderer::Render()
  578. {
  579. // Engine does not render when window is closed or device is lost
  580. assert(graphics_ && graphics_->IsInitialized() && !graphics_->IsDeviceLost());
  581. PROFILE(RenderViews);
  582. // If the indirection textures have lost content (OpenGL mode only), restore them now
  583. if (faceSelectCubeMap_ && faceSelectCubeMap_->IsDataLost())
  584. SetIndirectionTextureData();
  585. graphics_->SetDefaultTextureFilterMode(textureFilterMode_);
  586. graphics_->SetTextureAnisotropy(textureAnisotropy_);
  587. graphics_->ClearParameterSources();
  588. // If no views, just clear the screen
  589. if (!numViews_)
  590. {
  591. graphics_->SetBlendMode(BLEND_REPLACE);
  592. graphics_->SetColorWrite(true);
  593. graphics_->SetDepthWrite(true);
  594. graphics_->SetScissorTest(false);
  595. graphics_->SetStencilTest(false);
  596. graphics_->ResetRenderTargets();
  597. graphics_->Clear(CLEAR_COLOR | CLEAR_DEPTH | CLEAR_STENCIL, defaultZone_->GetFogColor());
  598. numPrimitives_ = 0;
  599. numBatches_ = 0;
  600. }
  601. else
  602. {
  603. // Render views from last to first (each main view is rendered after the auxiliary views it depends on)
  604. for (unsigned i = numViews_ - 1; i < numViews_; --i)
  605. {
  606. using namespace BeginViewRender;
  607. RenderSurface* renderTarget = views_[i]->GetRenderTarget();
  608. VariantMap& eventData = GetEventDataMap();
  609. eventData[P_SURFACE] = (void*)renderTarget;
  610. eventData[P_TEXTURE] = (void*)(renderTarget ? renderTarget->GetParentTexture() : 0);
  611. eventData[P_SCENE] = (void*)views_[i]->GetScene();
  612. eventData[P_CAMERA] = (void*)views_[i]->GetCamera();
  613. SendEvent(E_BEGINVIEWRENDER, eventData);
  614. // Screen buffers can be reused between views, as each is rendered completely
  615. PrepareViewRender();
  616. views_[i]->Render();
  617. SendEvent(E_ENDVIEWRENDER, eventData);
  618. }
  619. // Copy the number of batches & primitives from Graphics so that we can account for 3D geometry only
  620. numPrimitives_ = graphics_->GetNumPrimitives();
  621. numBatches_ = graphics_->GetNumBatches();
  622. }
  623. // Remove unused occlusion buffers and renderbuffers
  624. RemoveUnusedBuffers();
  625. }
  626. void Renderer::DrawDebugGeometry(bool depthTest)
  627. {
  628. PROFILE(RendererDrawDebug);
  629. /// \todo Because debug geometry is per-scene, if two cameras show views of the same area, occlusion is not shown correctly
  630. HashSet<Drawable*> processedGeometries;
  631. HashSet<Light*> processedLights;
  632. for (unsigned i = 0; i < numViews_; ++i)
  633. {
  634. // Make sure it's a main view, and process each node only once
  635. View* view = views_[i];
  636. if (view->GetRenderTarget())
  637. continue;
  638. Octree* octree = view->GetOctree();
  639. if (!octree)
  640. continue;
  641. DebugRenderer* debug = octree->GetComponent<DebugRenderer>();
  642. if (!debug)
  643. continue;
  644. const PODVector<Drawable*>& geometries = view->GetGeometries();
  645. const PODVector<Light*>& lights = view->GetLights();
  646. for (unsigned i = 0; i < geometries.Size(); ++i)
  647. {
  648. if (!processedGeometries.Contains(geometries[i]))
  649. {
  650. geometries[i]->DrawDebugGeometry(debug, depthTest);
  651. processedGeometries.Insert(geometries[i]);
  652. }
  653. }
  654. for (unsigned i = 0; i < lights.Size(); ++i)
  655. {
  656. if (!processedLights.Contains(lights[i]))
  657. {
  658. lights[i]->DrawDebugGeometry(debug, depthTest);
  659. processedLights.Insert(lights[i]);
  660. }
  661. }
  662. }
  663. }
  664. void Renderer::QueueRenderSurface(RenderSurface* renderTarget)
  665. {
  666. if (renderTarget)
  667. {
  668. unsigned numViewports = renderTarget->GetNumViewports();
  669. for (unsigned i = 0; i < numViewports; ++i)
  670. QueueViewport(renderTarget, renderTarget->GetViewport(i));
  671. }
  672. }
  673. void Renderer::QueueViewport(RenderSurface* renderTarget, Viewport* viewport)
  674. {
  675. if (viewport)
  676. {
  677. queuedViews_.Push(Pair<WeakPtr<RenderSurface>, WeakPtr<Viewport> >(WeakPtr<RenderSurface>(renderTarget),
  678. WeakPtr<Viewport>(viewport)));
  679. }
  680. }
  681. Geometry* Renderer::GetLightGeometry(Light* light)
  682. {
  683. switch (light->GetLightType())
  684. {
  685. case LIGHT_DIRECTIONAL:
  686. return dirLightGeometry_;
  687. case LIGHT_SPOT:
  688. return spotLightGeometry_;
  689. case LIGHT_POINT:
  690. return pointLightGeometry_;
  691. }
  692. return 0;
  693. }
  694. Texture2D* Renderer::GetShadowMap(Light* light, Camera* camera, unsigned viewWidth, unsigned viewHeight)
  695. {
  696. LightType type = light->GetLightType();
  697. const FocusParameters& parameters = light->GetShadowFocus();
  698. float size = (float)shadowMapSize_ * light->GetShadowResolution();
  699. // Automatically reduce shadow map size when far away
  700. if (parameters.autoSize_ && type != LIGHT_DIRECTIONAL)
  701. {
  702. const Matrix3x4& view = camera->GetView();
  703. const Matrix4& projection = camera->GetProjection();
  704. BoundingBox lightBox;
  705. float lightPixels;
  706. if (type == LIGHT_POINT)
  707. {
  708. // Calculate point light pixel size from the projection of its diagonal
  709. Vector3 center = view * light->GetNode()->GetWorldPosition();
  710. float extent = 0.58f * light->GetRange();
  711. lightBox.Define(center + Vector3(extent, extent, extent), center - Vector3(extent, extent, extent));
  712. }
  713. else
  714. {
  715. // Calculate spot light pixel size from the projection of its frustum far vertices
  716. Frustum lightFrustum = light->GetFrustum().Transformed(view);
  717. lightBox.Define(&lightFrustum.vertices_[4], 4);
  718. }
  719. Vector2 projectionSize = lightBox.Projected(projection).Size();
  720. lightPixels = Max(0.5f * (float)viewWidth * projectionSize.x_, 0.5f * (float)viewHeight * projectionSize.y_);
  721. // Clamp pixel amount to a sufficient minimum to avoid self-shadowing artifacts due to loss of precision
  722. if (lightPixels < SHADOW_MIN_PIXELS)
  723. lightPixels = SHADOW_MIN_PIXELS;
  724. size = Min(size, lightPixels);
  725. }
  726. /// \todo Allow to specify maximum shadow maps per resolution, as smaller shadow maps take less memory
  727. int width = NextPowerOfTwo((unsigned)size);
  728. int height = width;
  729. // Adjust the size for directional or point light shadow map atlases
  730. if (type == LIGHT_DIRECTIONAL)
  731. {
  732. if (maxShadowCascades_ > 1)
  733. width *= 2;
  734. if (maxShadowCascades_ > 2)
  735. height *= 2;
  736. }
  737. else if (type == LIGHT_POINT)
  738. {
  739. width *= 2;
  740. height *= 3;
  741. }
  742. int searchKey = (width << 16) | height;
  743. if (shadowMaps_.Contains(searchKey))
  744. {
  745. // If shadow maps are reused, always return the first
  746. if (reuseShadowMaps_)
  747. return shadowMaps_[searchKey][0];
  748. else
  749. {
  750. // If not reused, check allocation count and return existing shadow map if possible
  751. unsigned allocated = shadowMapAllocations_[searchKey].Size();
  752. if (allocated < shadowMaps_[searchKey].Size())
  753. {
  754. shadowMapAllocations_[searchKey].Push(light);
  755. return shadowMaps_[searchKey][allocated];
  756. }
  757. else if ((int)allocated >= maxShadowMaps_)
  758. return 0;
  759. }
  760. }
  761. unsigned shadowMapFormat = (shadowQuality_ & SHADOWQUALITY_LOW_24BIT) ? graphics_->GetHiresShadowMapFormat() :
  762. graphics_->GetShadowMapFormat();
  763. if (!shadowMapFormat)
  764. return 0;
  765. SharedPtr<Texture2D> newShadowMap(new Texture2D(context_));
  766. int retries = 3;
  767. // OpenGL: create shadow map only. Color rendertarget is not needed
  768. #ifdef USE_OPENGL
  769. while (retries)
  770. {
  771. if (!newShadowMap->SetSize(width, height, shadowMapFormat, TEXTURE_DEPTHSTENCIL))
  772. {
  773. width >>= 1;
  774. height >>= 1;
  775. --retries;
  776. }
  777. else
  778. {
  779. #ifndef GL_ES_VERSION_2_0
  780. newShadowMap->SetFilterMode(FILTER_BILINEAR);
  781. newShadowMap->SetShadowCompare(true);
  782. #endif
  783. break;
  784. }
  785. }
  786. #else
  787. // Direct3D9: create shadow map and dummy color rendertarget
  788. unsigned dummyColorFormat = graphics_->GetDummyColorFormat();
  789. while (retries)
  790. {
  791. if (!newShadowMap->SetSize(width, height, shadowMapFormat, TEXTURE_DEPTHSTENCIL))
  792. {
  793. width >>= 1;
  794. height >>= 1;
  795. --retries;
  796. }
  797. else
  798. {
  799. newShadowMap->SetFilterMode(FILTER_BILINEAR);
  800. // If no dummy color rendertarget for this size exists yet, create one now
  801. if (!colorShadowMaps_.Contains(searchKey))
  802. {
  803. colorShadowMaps_[searchKey] = new Texture2D(context_);
  804. colorShadowMaps_[searchKey]->SetSize(width, height, dummyColorFormat, TEXTURE_RENDERTARGET);
  805. }
  806. // Link the color rendertarget to the shadow map
  807. newShadowMap->GetRenderSurface()->SetLinkedRenderTarget(colorShadowMaps_[searchKey]->GetRenderSurface());
  808. break;
  809. }
  810. }
  811. #endif
  812. // If failed to set size, store a null pointer so that we will not retry
  813. if (!retries)
  814. newShadowMap.Reset();
  815. shadowMaps_[searchKey].Push(newShadowMap);
  816. if (!reuseShadowMaps_)
  817. shadowMapAllocations_[searchKey].Push(light);
  818. return newShadowMap;
  819. }
  820. Texture2D* Renderer::GetScreenBuffer(int width, int height, unsigned format, bool filtered, bool srgb)
  821. {
  822. bool depthStencil = (format == Graphics::GetDepthStencilFormat());
  823. if (depthStencil)
  824. {
  825. filtered = false;
  826. srgb = false;
  827. }
  828. long long searchKey = ((long long)format << 32) | (width << 16) | height;
  829. if (filtered)
  830. searchKey |= 0x8000000000000000LL;
  831. if (srgb)
  832. searchKey |= 0x4000000000000000LL;
  833. // If new size or format, initialize the allocation stats
  834. if (screenBuffers_.Find(searchKey) == screenBuffers_.End())
  835. screenBufferAllocations_[searchKey] = 0;
  836. // Reuse depth-stencil buffers whenever the size matches, instead of allocating new
  837. unsigned allocations = screenBufferAllocations_[searchKey];
  838. if(!depthStencil)
  839. ++screenBufferAllocations_[searchKey];
  840. if (allocations >= screenBuffers_[searchKey].Size())
  841. {
  842. SharedPtr<Texture2D> newBuffer(new Texture2D(context_));
  843. newBuffer->SetSRGB(srgb);
  844. newBuffer->SetSize(width, height, format, depthStencil ? TEXTURE_DEPTHSTENCIL : TEXTURE_RENDERTARGET);
  845. newBuffer->SetFilterMode(filtered ? FILTER_BILINEAR : FILTER_NEAREST);
  846. newBuffer->ResetUseTimer();
  847. screenBuffers_[searchKey].Push(newBuffer);
  848. LOGDEBUG("Allocated new screen buffer size " + String(width) + "x" + String(height) + " format " + String(format));
  849. return newBuffer;
  850. }
  851. else
  852. {
  853. Texture2D* buffer = screenBuffers_[searchKey][allocations];
  854. buffer->ResetUseTimer();
  855. return buffer;
  856. }
  857. }
  858. RenderSurface* Renderer::GetDepthStencil(int width, int height)
  859. {
  860. // Return the default depth-stencil surface if applicable
  861. // (when using OpenGL Graphics will allocate right size surfaces on demand to emulate Direct3D9)
  862. if (width == graphics_->GetWidth() && height == graphics_->GetHeight() && graphics_->GetMultiSample() <= 1)
  863. return 0;
  864. else
  865. return GetScreenBuffer(width, height, Graphics::GetDepthStencilFormat(), false, false)->GetRenderSurface();
  866. }
  867. OcclusionBuffer* Renderer::GetOcclusionBuffer(Camera* camera)
  868. {
  869. assert(numOcclusionBuffers_ <= occlusionBuffers_.Size());
  870. if (numOcclusionBuffers_ == occlusionBuffers_.Size())
  871. {
  872. SharedPtr<OcclusionBuffer> newBuffer(new OcclusionBuffer(context_));
  873. occlusionBuffers_.Push(newBuffer);
  874. }
  875. int width = occlusionBufferSize_;
  876. int height = (int)((float)occlusionBufferSize_ / camera->GetAspectRatio() + 0.5f);
  877. OcclusionBuffer* buffer = occlusionBuffers_[numOcclusionBuffers_++];
  878. buffer->SetSize(width, height);
  879. buffer->SetView(camera);
  880. buffer->ResetUseTimer();
  881. return buffer;
  882. }
  883. Camera* Renderer::GetShadowCamera()
  884. {
  885. MutexLock lock(rendererMutex_);
  886. assert(numShadowCameras_ <= shadowCameraNodes_.Size());
  887. if (numShadowCameras_ == shadowCameraNodes_.Size())
  888. {
  889. SharedPtr<Node> newNode(new Node(context_));
  890. newNode->CreateComponent<Camera>();
  891. shadowCameraNodes_.Push(newNode);
  892. }
  893. Camera* camera = shadowCameraNodes_[numShadowCameras_++]->GetComponent<Camera>();
  894. camera->SetOrthographic(false);
  895. camera->SetZoom(1.0f);
  896. return camera;
  897. }
  898. void Renderer::SetBatchShaders(Batch& batch, Technique* tech, bool allowShadows)
  899. {
  900. // Check if shaders are unloaded or need reloading
  901. Pass* pass = batch.pass_;
  902. Vector<SharedPtr<ShaderVariation> >& vertexShaders = pass->GetVertexShaders();
  903. Vector<SharedPtr<ShaderVariation> >& pixelShaders = pass->GetPixelShaders();
  904. if (!vertexShaders.Size() || !pixelShaders.Size() || pass->GetShadersLoadedFrameNumber() !=
  905. shadersChangedFrameNumber_)
  906. {
  907. // First release all previous shaders, then load
  908. pass->ReleaseShaders();
  909. LoadPassShaders(tech, pass->GetType());
  910. }
  911. // Make sure shaders are loaded now
  912. if (vertexShaders.Size() && pixelShaders.Size())
  913. {
  914. // If instancing is not supported, but was requested, or the object is too large to be instanced,
  915. // choose static geometry vertex shader instead
  916. if (batch.geometryType_ == GEOM_INSTANCED && (!GetDynamicInstancing() || batch.geometry_->GetIndexCount() >
  917. (unsigned)maxInstanceTriangles_ * 3))
  918. batch.geometryType_ = GEOM_STATIC;
  919. if (batch.geometryType_ == GEOM_STATIC_NOINSTANCING)
  920. batch.geometryType_ = GEOM_STATIC;
  921. // Check whether is a pixel lit forward pass. If not, there is only one pixel shader
  922. if (pass->GetLightingMode() == LIGHTING_PERPIXEL)
  923. {
  924. LightBatchQueue* lightQueue = batch.lightQueue_;
  925. if (!lightQueue)
  926. {
  927. // Do not log error, as it would result in a lot of spam
  928. batch.vertexShader_ = 0;
  929. batch.pixelShader_ = 0;
  930. return;
  931. }
  932. Light* light = lightQueue->light_;
  933. unsigned vsi = 0;
  934. unsigned psi = 0;
  935. vsi = batch.geometryType_ * MAX_LIGHT_VS_VARIATIONS;
  936. bool materialHasSpecular = batch.material_ ? batch.material_->GetSpecular() : true;
  937. if (specularLighting_ && light->GetSpecularIntensity() > 0.0f && materialHasSpecular)
  938. {
  939. vsi += LVS_SPEC;
  940. psi += LPS_SPEC;
  941. }
  942. if (allowShadows && lightQueue->shadowMap_)
  943. {
  944. vsi += LVS_SHADOW;
  945. psi += LPS_SHADOW;
  946. }
  947. switch (light->GetLightType())
  948. {
  949. case LIGHT_DIRECTIONAL:
  950. vsi += LVS_DIR;
  951. break;
  952. case LIGHT_SPOT:
  953. psi += LPS_SPOT;
  954. vsi += LVS_SPOT;
  955. break;
  956. case LIGHT_POINT:
  957. if (light->GetShapeTexture())
  958. psi += LPS_POINTMASK;
  959. else
  960. psi += LPS_POINT;
  961. vsi += LVS_POINT;
  962. break;
  963. }
  964. batch.vertexShader_ = vertexShaders[vsi];
  965. batch.pixelShader_ = pixelShaders[psi];
  966. // If shadow or specular variations do not exist, try without them
  967. if ((!batch.vertexShader_ || !batch.pixelShader_) && ((vsi % MAX_LIGHT_VS_VARIATIONS) >= LVS_SHADOW))
  968. {
  969. vsi -= LVS_SHADOW;
  970. psi -= LPS_SHADOW;
  971. batch.vertexShader_ = vertexShaders[vsi];
  972. batch.pixelShader_ = pixelShaders[psi];
  973. }
  974. if ((!batch.vertexShader_ || !batch.pixelShader_) && ((vsi % MAX_LIGHT_VS_VARIATIONS) >= LVS_SPEC))
  975. {
  976. vsi -= LVS_SPEC;
  977. psi -= LPS_SPEC;
  978. batch.vertexShader_ = vertexShaders[vsi];
  979. batch.pixelShader_ = pixelShaders[psi];
  980. }
  981. }
  982. else
  983. {
  984. // Check if pass has vertex lighting support
  985. if (pass->GetLightingMode() == LIGHTING_PERVERTEX)
  986. {
  987. unsigned numVertexLights = 0;
  988. if (batch.lightQueue_)
  989. numVertexLights = batch.lightQueue_->vertexLights_.Size();
  990. unsigned vsi = batch.geometryType_ * MAX_VERTEXLIGHT_VS_VARIATIONS + numVertexLights;
  991. batch.vertexShader_ = vertexShaders[vsi];
  992. // If vertex lights variations do not exist, try without them
  993. if (!batch.vertexShader_)
  994. {
  995. unsigned vsi = batch.geometryType_ * MAX_VERTEXLIGHT_VS_VARIATIONS;
  996. batch.vertexShader_ = vertexShaders[vsi];
  997. }
  998. }
  999. else
  1000. {
  1001. unsigned vsi = batch.geometryType_;
  1002. batch.vertexShader_ = vertexShaders[vsi];
  1003. }
  1004. batch.pixelShader_ = pixelShaders[0];
  1005. }
  1006. }
  1007. // Log error if shaders could not be assigned, but only once per technique
  1008. if (!batch.vertexShader_ || !batch.pixelShader_)
  1009. {
  1010. if (!shaderErrorDisplayed_.Contains(tech))
  1011. {
  1012. shaderErrorDisplayed_.Insert(tech);
  1013. LOGERROR("Technique " + tech->GetName() + " has missing shaders");
  1014. }
  1015. }
  1016. }
  1017. void Renderer::SetLightVolumeBatchShaders(Batch& batch, const String& vsName, const String& psName)
  1018. {
  1019. assert(deferredLightPSVariations_.Size());
  1020. unsigned vsi = DLVS_NONE;
  1021. unsigned psi = DLPS_NONE;
  1022. Light* light = batch.lightQueue_->light_;
  1023. switch (light->GetLightType())
  1024. {
  1025. case LIGHT_DIRECTIONAL:
  1026. vsi += DLVS_DIR;
  1027. break;
  1028. case LIGHT_SPOT:
  1029. psi += DLPS_SPOT;
  1030. break;
  1031. case LIGHT_POINT:
  1032. if (light->GetShapeTexture())
  1033. psi += DLPS_POINTMASK;
  1034. else
  1035. psi += DLPS_POINT;
  1036. break;
  1037. }
  1038. if (batch.lightQueue_->shadowMap_)
  1039. psi += DLPS_SHADOW;
  1040. if (specularLighting_ && light->GetSpecularIntensity() > 0.0f)
  1041. psi += DLPS_SPEC;
  1042. if (batch.camera_->IsOrthographic())
  1043. {
  1044. vsi += DLVS_ORTHO;
  1045. psi += DLPS_ORTHO;
  1046. }
  1047. batch.vertexShader_ = GetShader(VS, vsName, deferredLightVSVariations[vsi]);
  1048. batch.pixelShader_ = GetShader(PS, psName, deferredLightPSVariations_[psi]);
  1049. }
  1050. void Renderer::SetCullMode(CullMode mode, Camera* camera)
  1051. {
  1052. // If a camera is specified, check whether it reverses culling due to vertical flipping or reflection
  1053. if (camera && camera->GetReverseCulling())
  1054. {
  1055. if (mode == CULL_CW)
  1056. mode = CULL_CCW;
  1057. else if (mode == CULL_CCW)
  1058. mode = CULL_CW;
  1059. }
  1060. graphics_->SetCullMode(mode);
  1061. }
  1062. bool Renderer::ResizeInstancingBuffer(unsigned numInstances)
  1063. {
  1064. if (!instancingBuffer_ || !dynamicInstancing_)
  1065. return false;
  1066. unsigned oldSize = instancingBuffer_->GetVertexCount();
  1067. if (numInstances <= oldSize)
  1068. return true;
  1069. unsigned newSize = INSTANCING_BUFFER_DEFAULT_SIZE;
  1070. while (newSize < numInstances)
  1071. newSize <<= 1;
  1072. if (!instancingBuffer_->SetSize(newSize, INSTANCING_BUFFER_MASK, true))
  1073. {
  1074. LOGERROR("Failed to resize instancing buffer to " + String(newSize));
  1075. // If failed, try to restore the old size
  1076. instancingBuffer_->SetSize(oldSize, INSTANCING_BUFFER_MASK, true);
  1077. return false;
  1078. }
  1079. LOGDEBUG("Resized instancing buffer to " + String(newSize));
  1080. return true;
  1081. }
  1082. void Renderer::SaveScreenBufferAllocations()
  1083. {
  1084. savedScreenBufferAllocations_ = screenBufferAllocations_;
  1085. }
  1086. void Renderer::RestoreScreenBufferAllocations()
  1087. {
  1088. screenBufferAllocations_ = savedScreenBufferAllocations_;
  1089. }
  1090. void Renderer::OptimizeLightByScissor(Light* light, Camera* camera)
  1091. {
  1092. if (light && light->GetLightType() != LIGHT_DIRECTIONAL)
  1093. graphics_->SetScissorTest(true, GetLightScissor(light, camera));
  1094. else
  1095. graphics_->SetScissorTest(false);
  1096. }
  1097. void Renderer::OptimizeLightByStencil(Light* light, Camera* camera)
  1098. {
  1099. #ifndef GL_ES_VERSION_2_0
  1100. if (light)
  1101. {
  1102. LightType type = light->GetLightType();
  1103. if (type == LIGHT_DIRECTIONAL)
  1104. {
  1105. graphics_->SetStencilTest(false);
  1106. return;
  1107. }
  1108. Geometry* geometry = GetLightGeometry(light);
  1109. const Matrix3x4& view = camera->GetView();
  1110. const Matrix4& projection = camera->GetProjection();
  1111. Vector3 cameraPos = camera->GetNode()->GetWorldPosition();
  1112. float lightDist;
  1113. if (type == LIGHT_POINT)
  1114. lightDist = Sphere(light->GetNode()->GetWorldPosition(), light->GetRange() * 1.25f).Distance(cameraPos);
  1115. else
  1116. lightDist = light->GetFrustum().Distance(cameraPos);
  1117. // If the camera is actually inside the light volume, do not draw to stencil as it would waste fillrate
  1118. if (lightDist < M_EPSILON)
  1119. {
  1120. graphics_->SetStencilTest(false);
  1121. return;
  1122. }
  1123. // If the stencil value has wrapped, clear the whole stencil first
  1124. if (!lightStencilValue_)
  1125. {
  1126. graphics_->Clear(CLEAR_STENCIL);
  1127. lightStencilValue_ = 1;
  1128. }
  1129. // If possible, render the stencil volume front faces. However, close to the near clip plane render back faces instead
  1130. // to avoid clipping.
  1131. if (lightDist < camera->GetNearClip() * 2.0f)
  1132. {
  1133. SetCullMode(CULL_CW, camera);
  1134. graphics_->SetDepthTest(CMP_GREATER);
  1135. }
  1136. else
  1137. {
  1138. SetCullMode(CULL_CCW, camera);
  1139. graphics_->SetDepthTest(CMP_LESSEQUAL);
  1140. }
  1141. graphics_->SetColorWrite(false);
  1142. graphics_->SetDepthWrite(false);
  1143. graphics_->SetStencilTest(true, CMP_ALWAYS, OP_REF, OP_KEEP, OP_KEEP, lightStencilValue_);
  1144. graphics_->SetShaders(GetShader(VS, "Stencil"), GetShader(PS, "Stencil"));
  1145. graphics_->SetShaderParameter(VSP_VIEWPROJ, projection * view);
  1146. graphics_->SetShaderParameter(VSP_MODEL, light->GetVolumeTransform(camera));
  1147. geometry->Draw(graphics_);
  1148. graphics_->ClearTransformSources();
  1149. graphics_->SetColorWrite(true);
  1150. graphics_->SetStencilTest(true, CMP_EQUAL, OP_KEEP, OP_KEEP, OP_KEEP, lightStencilValue_);
  1151. // Increase stencil value for next light
  1152. ++lightStencilValue_;
  1153. }
  1154. else
  1155. graphics_->SetStencilTest(false);
  1156. #endif
  1157. }
  1158. const Rect& Renderer::GetLightScissor(Light* light, Camera* camera)
  1159. {
  1160. Pair<Light*, Camera*> combination(light, camera);
  1161. HashMap<Pair<Light*, Camera*>, Rect>::Iterator i = lightScissorCache_.Find(combination);
  1162. if (i != lightScissorCache_.End())
  1163. return i->second_;
  1164. const Matrix3x4& view = camera->GetView();
  1165. const Matrix4& projection = camera->GetProjection();
  1166. assert(light->GetLightType() != LIGHT_DIRECTIONAL);
  1167. if (light->GetLightType() == LIGHT_SPOT)
  1168. {
  1169. Frustum viewFrustum(light->GetFrustum().Transformed(view));
  1170. return lightScissorCache_[combination] = viewFrustum.Projected(projection);
  1171. }
  1172. else // LIGHT_POINT
  1173. {
  1174. BoundingBox viewBox(light->GetWorldBoundingBox().Transformed(view));
  1175. return lightScissorCache_[combination] = viewBox.Projected(projection);
  1176. }
  1177. }
  1178. void Renderer::PrepareViewRender()
  1179. {
  1180. ResetScreenBufferAllocations();
  1181. lightScissorCache_.Clear();
  1182. lightStencilValue_ = 1;
  1183. }
  1184. void Renderer::RemoveUnusedBuffers()
  1185. {
  1186. for (unsigned i = occlusionBuffers_.Size() - 1; i < occlusionBuffers_.Size(); --i)
  1187. {
  1188. if (occlusionBuffers_[i]->GetUseTimer() > MAX_BUFFER_AGE)
  1189. {
  1190. LOGDEBUG("Removed unused occlusion buffer");
  1191. occlusionBuffers_.Erase(i);
  1192. }
  1193. }
  1194. for (HashMap<long long, Vector<SharedPtr<Texture2D> > >::Iterator i = screenBuffers_.Begin(); i != screenBuffers_.End();)
  1195. {
  1196. HashMap<long long, Vector<SharedPtr<Texture2D> > >::Iterator current = i++;
  1197. Vector<SharedPtr<Texture2D> >& buffers = current->second_;
  1198. for (unsigned j = buffers.Size() - 1; j < buffers.Size(); --j)
  1199. {
  1200. Texture2D* buffer = buffers[j];
  1201. if (buffer->GetUseTimer() > MAX_BUFFER_AGE)
  1202. {
  1203. LOGDEBUG("Removed unused screen buffer size " + String(buffer->GetWidth()) + "x" + String(buffer->GetHeight()) + " format " + String(buffer->GetFormat()));
  1204. buffers.Erase(j);
  1205. }
  1206. }
  1207. if (buffers.Empty())
  1208. {
  1209. screenBufferAllocations_.Erase(current->first_);
  1210. screenBuffers_.Erase(current);
  1211. }
  1212. }
  1213. }
  1214. void Renderer::ResetShadowMapAllocations()
  1215. {
  1216. for (HashMap<int, PODVector<Light*> >::Iterator i = shadowMapAllocations_.Begin(); i != shadowMapAllocations_.End(); ++i)
  1217. i->second_.Clear();
  1218. }
  1219. void Renderer::ResetScreenBufferAllocations()
  1220. {
  1221. for (HashMap<long long, unsigned>::Iterator i = screenBufferAllocations_.Begin(); i != screenBufferAllocations_.End(); ++i)
  1222. i->second_ = 0;
  1223. }
  1224. void Renderer::Initialize()
  1225. {
  1226. Graphics* graphics = GetSubsystem<Graphics>();
  1227. ResourceCache* cache = GetSubsystem<ResourceCache>();
  1228. if (!graphics || !graphics->IsInitialized() || !cache)
  1229. return;
  1230. PROFILE(InitRenderer);
  1231. graphics_ = graphics;
  1232. if (!graphics_->GetShadowMapFormat())
  1233. drawShadows_ = false;
  1234. defaultLightRamp_ = cache->GetResource<Texture2D>("Textures/Ramp.png");
  1235. defaultLightSpot_ = cache->GetResource<Texture2D>("Textures/Spot.png");
  1236. defaultMaterial_ = cache->GetResource<Material>("Materials/Default.xml");
  1237. // If default material not found, create one. This will actually not render properly, but prevents crashing
  1238. if (!defaultMaterial_)
  1239. defaultMaterial_ = new Material(context_);
  1240. defaultRenderPath_ = new RenderPath();
  1241. defaultRenderPath_->Load(cache->GetResource<XMLFile>("RenderPaths/Forward.xml"));
  1242. CreateGeometries();
  1243. CreateInstancingBuffer();
  1244. viewports_.Resize(1);
  1245. ResetViews();
  1246. ResetShadowMaps();
  1247. ResetBuffers();
  1248. shadersDirty_ = true;
  1249. initialized_ = true;
  1250. SubscribeToEvent(E_RENDERUPDATE, HANDLER(Renderer, HandleRenderUpdate));
  1251. LOGINFO("Initialized renderer");
  1252. }
  1253. void Renderer::ResetViews()
  1254. {
  1255. views_.Clear();
  1256. numViews_ = 0;
  1257. }
  1258. void Renderer::LoadShaders()
  1259. {
  1260. LOGDEBUG("Reloading shaders");
  1261. // Release old material shaders, mark them for reload
  1262. ReleaseMaterialShaders();
  1263. shadersChangedFrameNumber_ = GetSubsystem<Time>()->GetFrameNumber();
  1264. // Construct new names for deferred light volume pixel shaders based on rendering options
  1265. deferredLightPSVariations_.Resize(MAX_DEFERRED_LIGHT_PS_VARIATIONS);
  1266. unsigned shadows = (graphics_->GetHardwareShadowSupport() ? 1 : 0) | (shadowQuality_ & SHADOWQUALITY_HIGH_16BIT);
  1267. for (unsigned i = 0; i < MAX_DEFERRED_LIGHT_PS_VARIATIONS; ++i)
  1268. {
  1269. deferredLightPSVariations_[i] = lightPSVariations[i % DLPS_ORTHO];
  1270. if (i & DLPS_SHADOW)
  1271. deferredLightPSVariations_[i] += shadowVariations[shadows];
  1272. if (i & DLPS_ORTHO)
  1273. deferredLightPSVariations_[i] += "ORTHO";
  1274. }
  1275. shadersDirty_ = false;
  1276. }
  1277. void Renderer::LoadPassShaders(Technique* tech, StringHash type)
  1278. {
  1279. Pass* pass = tech->GetPass(type);
  1280. if (!pass)
  1281. return;
  1282. PROFILE(LoadPassShaders);
  1283. unsigned shadows = (graphics_->GetHardwareShadowSupport() ? 1 : 0) | (shadowQuality_ & SHADOWQUALITY_HIGH_16BIT);
  1284. Vector<SharedPtr<ShaderVariation> >& vertexShaders = pass->GetVertexShaders();
  1285. Vector<SharedPtr<ShaderVariation> >& pixelShaders = pass->GetPixelShaders();
  1286. // Forget all the old shaders
  1287. vertexShaders.Clear();
  1288. pixelShaders.Clear();
  1289. if (pass->GetLightingMode() == LIGHTING_PERPIXEL)
  1290. {
  1291. // Load forward pixel lit variations
  1292. vertexShaders.Resize(MAX_GEOMETRYTYPES * MAX_LIGHT_VS_VARIATIONS);
  1293. pixelShaders.Resize(MAX_LIGHT_PS_VARIATIONS);
  1294. for (unsigned j = 0; j < MAX_GEOMETRYTYPES * MAX_LIGHT_VS_VARIATIONS; ++j)
  1295. {
  1296. unsigned g = j / MAX_LIGHT_VS_VARIATIONS;
  1297. unsigned l = j % MAX_LIGHT_VS_VARIATIONS;
  1298. vertexShaders[j] = GetShader(VS, pass->GetVertexShader(), Shader::SanitateDefines(pass->GetVertexShaderDefines() + " " +
  1299. lightVSVariations[l] + geometryVSVariations[g]));
  1300. }
  1301. for (unsigned j = 0; j < MAX_LIGHT_PS_VARIATIONS; ++j)
  1302. {
  1303. if (j & LPS_SHADOW)
  1304. {
  1305. pixelShaders[j] = GetShader(PS, pass->GetPixelShader(), Shader::SanitateDefines(pass->GetPixelShaderDefines() +
  1306. " " + lightPSVariations[j] + shadowVariations[shadows]));
  1307. }
  1308. else
  1309. pixelShaders[j] = GetShader(PS, pass->GetPixelShader(), Shader::SanitateDefines(pass->GetPixelShaderDefines() +
  1310. " " + lightPSVariations[j]));
  1311. }
  1312. }
  1313. else
  1314. {
  1315. // Load vertex light variations
  1316. if (pass->GetLightingMode() == LIGHTING_PERVERTEX)
  1317. {
  1318. vertexShaders.Resize(MAX_VERTEXLIGHT_VS_VARIATIONS * MAX_GEOMETRYTYPES);
  1319. for (unsigned j = 0; j < MAX_GEOMETRYTYPES * MAX_VERTEXLIGHT_VS_VARIATIONS; ++j)
  1320. {
  1321. unsigned g = j / MAX_VERTEXLIGHT_VS_VARIATIONS;
  1322. unsigned l = j % MAX_VERTEXLIGHT_VS_VARIATIONS;
  1323. vertexShaders[j] = GetShader(VS, pass->GetVertexShader(), Shader::SanitateDefines(pass->GetVertexShaderDefines() +
  1324. " " + vertexLightVSVariations[l] + geometryVSVariations[g]));
  1325. }
  1326. }
  1327. else
  1328. {
  1329. vertexShaders.Resize(MAX_GEOMETRYTYPES);
  1330. for (unsigned j = 0; j < MAX_GEOMETRYTYPES; ++j)
  1331. {
  1332. vertexShaders[j] = GetShader(VS, pass->GetVertexShader(), Shader::SanitateDefines(pass->GetVertexShaderDefines() +
  1333. " " + geometryVSVariations[j]));
  1334. }
  1335. }
  1336. pixelShaders.Resize(1);
  1337. pixelShaders[0] = GetShader(PS, pass->GetPixelShader(), Shader::SanitateDefines(pass->GetPixelShaderDefines()));
  1338. }
  1339. pass->MarkShadersLoaded(shadersChangedFrameNumber_);
  1340. }
  1341. void Renderer::ReleaseMaterialShaders()
  1342. {
  1343. ResourceCache* cache = GetSubsystem<ResourceCache>();
  1344. PODVector<Material*> materials;
  1345. cache->GetResources<Material>(materials);
  1346. for (unsigned i = 0; i < materials.Size(); ++i)
  1347. materials[i]->ReleaseShaders();
  1348. }
  1349. void Renderer::ReloadTextures()
  1350. {
  1351. ResourceCache* cache = GetSubsystem<ResourceCache>();
  1352. PODVector<Resource*> textures;
  1353. cache->GetResources(textures, Texture2D::GetTypeStatic());
  1354. for (unsigned i = 0; i < textures.Size(); ++i)
  1355. cache->ReloadResource(textures[i]);
  1356. cache->GetResources(textures, TextureCube::GetTypeStatic());
  1357. for (unsigned i = 0; i < textures.Size(); ++i)
  1358. cache->ReloadResource(textures[i]);
  1359. }
  1360. void Renderer::CreateGeometries()
  1361. {
  1362. SharedPtr<VertexBuffer> dlvb(new VertexBuffer(context_));
  1363. dlvb->SetShadowed(true);
  1364. dlvb->SetSize(4, MASK_POSITION);
  1365. dlvb->SetData(dirLightVertexData);
  1366. SharedPtr<IndexBuffer> dlib(new IndexBuffer(context_));
  1367. dlib->SetShadowed(true);
  1368. dlib->SetSize(6, false);
  1369. dlib->SetData(dirLightIndexData);
  1370. dirLightGeometry_ = new Geometry(context_);
  1371. dirLightGeometry_->SetVertexBuffer(0, dlvb);
  1372. dirLightGeometry_->SetIndexBuffer(dlib);
  1373. dirLightGeometry_->SetDrawRange(TRIANGLE_LIST, 0, dlib->GetIndexCount());
  1374. SharedPtr<VertexBuffer> slvb(new VertexBuffer(context_));
  1375. slvb->SetShadowed(true);
  1376. slvb->SetSize(8, MASK_POSITION);
  1377. slvb->SetData(spotLightVertexData);
  1378. SharedPtr<IndexBuffer> slib(new IndexBuffer(context_));
  1379. slib->SetShadowed(true);
  1380. slib->SetSize(36, false);
  1381. slib->SetData(spotLightIndexData);
  1382. spotLightGeometry_ = new Geometry(context_);
  1383. spotLightGeometry_->SetVertexBuffer(0, slvb);
  1384. spotLightGeometry_->SetIndexBuffer(slib);
  1385. spotLightGeometry_->SetDrawRange(TRIANGLE_LIST, 0, slib->GetIndexCount());
  1386. SharedPtr<VertexBuffer> plvb(new VertexBuffer(context_));
  1387. plvb->SetShadowed(true);
  1388. plvb->SetSize(24, MASK_POSITION);
  1389. plvb->SetData(pointLightVertexData);
  1390. SharedPtr<IndexBuffer> plib(new IndexBuffer(context_));
  1391. plib->SetShadowed(true);
  1392. plib->SetSize(132, false);
  1393. plib->SetData(pointLightIndexData);
  1394. pointLightGeometry_ = new Geometry(context_);
  1395. pointLightGeometry_->SetVertexBuffer(0, plvb);
  1396. pointLightGeometry_->SetIndexBuffer(plib);
  1397. pointLightGeometry_->SetDrawRange(TRIANGLE_LIST, 0, plib->GetIndexCount());
  1398. #if !defined(USE_OPENGL) || !defined(GL_ES_VERSION_2_0)
  1399. if (graphics_->GetShadowMapFormat())
  1400. {
  1401. faceSelectCubeMap_ = new TextureCube(context_);
  1402. faceSelectCubeMap_->SetNumLevels(1);
  1403. faceSelectCubeMap_->SetSize(1, graphics_->GetRGBAFormat());
  1404. faceSelectCubeMap_->SetFilterMode(FILTER_NEAREST);
  1405. indirectionCubeMap_ = new TextureCube(context_);
  1406. indirectionCubeMap_->SetNumLevels(1);
  1407. indirectionCubeMap_->SetSize(256, graphics_->GetRGBAFormat());
  1408. indirectionCubeMap_->SetFilterMode(FILTER_BILINEAR);
  1409. indirectionCubeMap_->SetAddressMode(COORD_U, ADDRESS_CLAMP);
  1410. indirectionCubeMap_->SetAddressMode(COORD_V, ADDRESS_CLAMP);
  1411. indirectionCubeMap_->SetAddressMode(COORD_W, ADDRESS_CLAMP);
  1412. SetIndirectionTextureData();
  1413. }
  1414. #endif
  1415. }
  1416. void Renderer::SetIndirectionTextureData()
  1417. {
  1418. unsigned char data[256 * 256 * 4];
  1419. for (unsigned i = 0; i < MAX_CUBEMAP_FACES; ++i)
  1420. {
  1421. unsigned axis = i / 2;
  1422. data[0] = (axis == 0) ? 255 : 0;
  1423. data[1] = (axis == 1) ? 255 : 0;
  1424. data[2] = (axis == 2) ? 255 : 0;
  1425. data[3] = 0;
  1426. faceSelectCubeMap_->SetData((CubeMapFace)i, 0, 0, 0, 1, 1, data);
  1427. }
  1428. for (unsigned i = 0; i < MAX_CUBEMAP_FACES; ++i)
  1429. {
  1430. unsigned char faceX = (i & 1) * 255;
  1431. unsigned char faceY = (i / 2) * 255 / 3;
  1432. unsigned char* dest = data;
  1433. for (unsigned y = 0; y < 256; ++y)
  1434. {
  1435. for (unsigned x = 0; x < 256; ++x)
  1436. {
  1437. #ifdef USE_OPENGL
  1438. dest[0] = x;
  1439. dest[1] = 255 - y;
  1440. dest[2] = faceX;
  1441. dest[3] = 255 * 2 / 3 - faceY;
  1442. #else
  1443. dest[0] = x;
  1444. dest[1] = y;
  1445. dest[2] = faceX;
  1446. dest[3] = faceY;
  1447. #endif
  1448. dest += 4;
  1449. }
  1450. }
  1451. indirectionCubeMap_->SetData((CubeMapFace)i, 0, 0, 0, 256, 256, data);
  1452. }
  1453. faceSelectCubeMap_->ClearDataLost();
  1454. indirectionCubeMap_->ClearDataLost();
  1455. }
  1456. void Renderer::CreateInstancingBuffer()
  1457. {
  1458. // Do not create buffer if instancing not supported
  1459. if (!graphics_->GetInstancingSupport())
  1460. {
  1461. instancingBuffer_.Reset();
  1462. dynamicInstancing_ = false;
  1463. return;
  1464. }
  1465. // If must lock the buffer for each batch group, set a smaller size
  1466. unsigned defaultSize = graphics_->GetStreamOffsetSupport() ? INSTANCING_BUFFER_DEFAULT_SIZE : INSTANCING_BUFFER_DEFAULT_SIZE / 4;
  1467. instancingBuffer_ = new VertexBuffer(context_);
  1468. if (!instancingBuffer_->SetSize(defaultSize, INSTANCING_BUFFER_MASK, true))
  1469. {
  1470. instancingBuffer_.Reset();
  1471. dynamicInstancing_ = false;
  1472. }
  1473. }
  1474. void Renderer::ResetShadowMaps()
  1475. {
  1476. shadowMaps_.Clear();
  1477. shadowMapAllocations_.Clear();
  1478. colorShadowMaps_.Clear();
  1479. }
  1480. void Renderer::ResetBuffers()
  1481. {
  1482. occlusionBuffers_.Clear();
  1483. screenBuffers_.Clear();
  1484. screenBufferAllocations_.Clear();
  1485. }
  1486. void Renderer::HandleScreenMode(StringHash eventType, VariantMap& eventData)
  1487. {
  1488. if (!initialized_)
  1489. Initialize();
  1490. else
  1491. {
  1492. // When screen mode changes, purge old views
  1493. ResetViews();
  1494. }
  1495. }
  1496. void Renderer::HandleGraphicsFeatures(StringHash eventType, VariantMap& eventData)
  1497. {
  1498. // Reinitialize if already initialized
  1499. if (initialized_)
  1500. Initialize();
  1501. }
  1502. void Renderer::HandleRenderUpdate(StringHash eventType, VariantMap& eventData)
  1503. {
  1504. using namespace RenderUpdate;
  1505. Update(eventData[P_TIMESTEP].GetFloat());
  1506. }
  1507. }