1 /** @file rendersystem.cpp  Renderer subsystem.
2  *
3  * @authors Copyright © 2003-2017 Jaakko Keränen <jaakko.keranen@iki.fi>
4  * @authors Copyright © 2006-2015 Daniel Swanson <danij@dengine.net>
5  *
6  * @par License
7  * GPL: http://www.gnu.org/licenses/gpl.html
8  *
9  * <small>This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by the
11  * Free Software Foundation; either version 2 of the License, or (at your
12  * option) any later version. This program is distributed in the hope that it
13  * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15  * Public License for more details. You should have received a copy of the GNU
16  * General Public License along with this program; if not, see:
17  * http://www.gnu.org/licenses</small>
18  */
19 
20 #include "de_platform.h"
21 #include "render/rendersystem.h"
22 
23 #include <de/memory.h>
24 #include <de/memoryzone.h>
25 #include <de/Function>
26 #include <de/GLUniform>
27 #include <de/PackageLoader>
28 #include <de/ScriptSystem>
29 #include <de/ScriptedInfo>
30 #include <de/TextValue>
31 #include "clientapp.h"
32 #include "render/environ.h"
33 #include "render/rend_main.h"
34 #include "render/rend_halo.h"
35 #include "render/angleclipper.h"
36 #include "render/modelrenderer.h"
37 #include "render/skydrawable.h"
38 #include "render/store.h"
39 #include "world/clientserverworld.h"
40 
41 #include "gl/gl_main.h"
42 #include "gl/gl_texmanager.h"
43 
44 #include "ConvexSubspace"
45 #include "Subsector"
46 #include "Surface"
47 
48 #include "Contact"
49 #include "misc/r_util.h"
50 
51 using namespace de;
52 
DENG2_PIMPL(RenderSystem)53 DENG2_PIMPL(RenderSystem)
54 , DENG2_OBSERVES(PackageLoader, Load)
55 , DENG2_OBSERVES(PackageLoader, Unload)
56 {
57     Binder binder;
58     Record renderModule;
59 
60     render::Environment environment;
61     ModelRenderer models;
62     SkyDrawable sky;
63     ConfigProfiles settings;
64     ConfigProfiles appearanceSettings;
65     ImageBank images;
66 
67     AngleClipper clipper;
68 
69     Store buffer;
70     DrawLists drawLists;
71 
72     GLUniform uMapTime          { "uMapTime",          GLUniform::Float };
73     GLUniform uViewMatrix       { "uViewMatrix",       GLUniform::Mat4  };
74     GLUniform uProjectionMatrix { "uProjectionMatrix", GLUniform::Mat4  };
75 
76     // Texture => world surface projection lists.
77     struct ProjectionLists
78     {
79         duint listCount = 0;
80         duint cursorList = 0;
81         ProjectionList *lists = nullptr;
82 
83         void init()
84         {
85             ProjectionList::init();
86 
87             // All memory for the lists is allocated from Zone so we can "forget" it.
88             lists = nullptr;
89             listCount = 0;
90             cursorList = 0;
91         }
92 
93         void reset()
94         {
95             ProjectionList::rewind();  // start reusing list nodes.
96 
97             // Clear the lists.
98             cursorList = 0;
99             if(listCount)
100             {
101                 std::memset(lists, 0, listCount * sizeof *lists);
102             }
103         }
104 
105         ProjectionList *tryFindList(duint listIdx) const
106         {
107             if(listIdx > 0 && listIdx <= listCount)
108             {
109                 return &lists[listIdx - 1];
110             }
111             return nullptr;  // not found.
112         }
113 
114         ProjectionList &findList(duint listIdx) const
115         {
116             if(ProjectionList *found = tryFindList(listIdx)) return *found;
117             /// @throw MissingListError  Invalid index specified.
118             throw Error("RenderSystem::projector::findList", "Invalid index #" + String::number(listIdx));
119         }
120 
121         ProjectionList &findOrCreateList(duint *listIdx, bool sortByLuma)
122         {
123             DENG2_ASSERT(listIdx);
124 
125             // Do we need to allocate a list?
126             if(!(*listIdx))
127             {
128                 // Do we need to allocate more lists?
129                 if(++cursorList >= listCount)
130                 {
131                     listCount *= 2;
132                     if(!listCount) listCount = 2;
133 
134                     lists = (ProjectionList *) Z_Realloc(lists, listCount * sizeof(*lists), PU_MAP);
135                 }
136 
137                 ProjectionList *list = &lists[cursorList - 1];
138                 list->head       = nullptr;
139                 list->sortByLuma = sortByLuma;
140 
141                 *listIdx = cursorList;
142             }
143 
144             return lists[(*listIdx) - 1];  // 1-based index.
145         }
146     } projector;
147 
148     /// VectorLight => object affection lists.
149     struct VectorLights
150     {
151         duint listCount = 0;
152         duint cursorList = 0;
153         VectorLightList *lists = nullptr;
154 
155         void init()
156         {
157             VectorLightList::init();
158 
159             // All memory for the lists is allocated from Zone so we can "forget" it.
160             lists = nullptr;
161             listCount = 0;
162             cursorList = 0;
163         }
164 
165         void reset()
166         {
167             VectorLightList::rewind();  // start reusing list nodes.
168 
169             // Clear the lists.
170             cursorList = 0;
171             if(listCount)
172             {
173                 std::memset(lists, 0, listCount * sizeof *lists);
174             }
175         }
176 
177         VectorLightList *tryFindList(duint listIdx) const
178         {
179             if(listIdx > 0 && listIdx <= listCount)
180             {
181                 return &lists[listIdx - 1];
182             }
183             return nullptr;  // not found.
184         }
185 
186         VectorLightList &findList(duint listIdx) const
187         {
188             if(VectorLightList *found = tryFindList(listIdx)) return *found;
189             /// @throw MissingListError  Invalid index specified.
190             throw Error("RenderSystem::vlights::findList", "Invalid index #" + String::number(listIdx));
191         }
192 
193         VectorLightList &findOrCreateList(duint *listIdx)
194         {
195             DENG2_ASSERT(listIdx);
196 
197             // Do we need to allocate a list?
198             if(!(*listIdx))
199             {
200                 // Do we need to allocate more lists?
201                 if(++cursorList >= listCount)
202                 {
203                     listCount *= 2;
204                     if(!listCount) listCount = 2;
205 
206                     lists = (VectorLightList *) Z_Realloc(lists, listCount * sizeof(*lists), PU_MAP);
207                 }
208 
209                 VectorLightList *list = &lists[cursorList - 1];
210                 list->head = nullptr;
211 
212                 *listIdx = cursorList;
213             }
214 
215             return lists[(*listIdx) - 1];  // 1-based index.
216         }
217     } vlights;
218 
219     Impl(Public *i) : Base(i)
220     {
221         LOG_AS("RenderSystem");
222 
223         ModelRenderer::initBindings(binder, renderModule);
224         ClientApp::scriptSystem().addNativeModule("Render", renderModule);
225 
226         // Packages are checked for shaders when (un)loaded.
227         App::packageLoader().audienceForLoad() += this;
228         App::packageLoader().audienceForUnload() += this;
229 
230         // Load the required packages.
231         App::packageLoader().load("net.dengine.client.renderer");
232         App::packageLoader().load("net.dengine.client.renderer.lensflares");
233 
234         loadImages();
235 
236         typedef ConfigProfiles SReg;
237 
238         // Initialize settings.
239         settings.define(SReg::FloatCVar, "rend-camera-fov", 95.f)
240                 .define(SReg::ConfigVariable, "render.pixelDensity")
241                 .define(SReg::IntCVar,   "rend-model-mirror-hud", 0)
242                 .define(SReg::IntCVar,   "rend-model-precache", 1)
243                 .define(SReg::IntCVar,   "rend-sprite-precache", 1)
244                 .define(SReg::IntCVar,   "rend-tex", 1)
245                 .define(SReg::IntCVar,   "rend-dev-wireframe", 0)
246                 .define(SReg::IntCVar,   "rend-dev-thinker-ids", 0)
247                 .define(SReg::IntCVar,   "rend-dev-mobj-bbox", 0)
248                 .define(SReg::IntCVar,   "rend-dev-polyobj-bbox", 0)
249                 .define(SReg::IntCVar,   "rend-dev-sector-show-indices", 0)
250                 .define(SReg::IntCVar,   "rend-dev-vertex-show-indices", 0)
251                 .define(SReg::IntCVar,   "rend-dev-generator-show-indices", 0);
252 
253         appearanceSettings.setPersistentName("renderer");
254         appearanceSettings
255                 .define(SReg::IntCVar,   "rend-light", 1)
256                 .define(SReg::IntCVar,   "rend-light-decor", 1)
257                 .define(SReg::IntCVar,   "rend-light-blend", 0)
258                 .define(SReg::IntCVar,   "rend-light-num", 0)
259                 .define(SReg::FloatCVar, "rend-light-bright", .7f)
260                 .define(SReg::FloatCVar, "rend-light-fog-bright", .15f)
261                 .define(SReg::FloatCVar, "rend-light-radius-scale", 5.2f)
262                 .define(SReg::IntCVar,   "rend-light-radius-max", 320)
263                 .define(SReg::IntCVar,   "rend-light-ambient", 0)
264                 .define(SReg::FloatCVar, "rend-light-compression", 0)
265                 .define(SReg::IntCVar,   "rend-light-attenuation", 924)
266                 .define(SReg::IntCVar,   "rend-light-sky-auto", 1)
267                 .define(SReg::FloatCVar, "rend-light-sky", .273f)
268                 .define(SReg::IntCVar,   "rend-light-wall-angle-smooth", 1)
269                 .define(SReg::FloatCVar, "rend-light-wall-angle", 1.2f)
270 
271                 .define(SReg::IntCVar,   "rend-vignette", 1)
272                 .define(SReg::FloatCVar, "rend-vignette-darkness", 1)
273                 .define(SReg::FloatCVar, "rend-vignette-width", 1)
274 
275                 .define(SReg::IntCVar,   "rend-halo-realistic", 1)
276                 .define(SReg::IntCVar,   "rend-halo", 5)
277                 .define(SReg::IntCVar,   "rend-halo-bright", 45)
278                 .define(SReg::IntCVar,   "rend-halo-size", 80)
279                 .define(SReg::IntCVar,   "rend-halo-occlusion", 48)
280                 .define(SReg::FloatCVar, "rend-halo-radius-min", 20)
281                 .define(SReg::FloatCVar, "rend-halo-secondary-limit", 1)
282                 .define(SReg::FloatCVar, "rend-halo-dim-near", 10)
283                 .define(SReg::FloatCVar, "rend-halo-dim-far", 100)
284                 .define(SReg::FloatCVar, "rend-halo-zmag-div", 62)
285 
286                 .define(SReg::FloatCVar, "rend-glow", .8f)
287                 .define(SReg::IntCVar,   "rend-glow-height", 100)
288                 .define(SReg::FloatCVar, "rend-glow-scale", 3)
289                 .define(SReg::IntCVar,   "rend-glow-wall", 1)
290 
291                 .define(SReg::ConfigVariable, "render.fx.resize.factor")
292 
293                 .define(SReg::IntCVar,   "rend-bloom", 1)
294                 .define(SReg::FloatCVar, "rend-bloom-intensity", .65f)
295                 .define(SReg::FloatCVar, "rend-bloom-threshold", .35f)
296                 .define(SReg::FloatCVar, "rend-bloom-dispersion", 1)
297 
298                 .define(SReg::IntCVar,   "rend-fakeradio", 1)
299                 .define(SReg::FloatCVar, "rend-fakeradio-darkness", 1.2f)
300                 .define(SReg::IntCVar,   "rend-shadow", 1)
301                 .define(SReg::FloatCVar, "rend-shadow-darkness", 1.2f)
302                 .define(SReg::IntCVar,   "rend-shadow-far", 1000)
303                 .define(SReg::IntCVar,   "rend-shadow-radius-max", 80)
304 
305                 .define(SReg::IntCVar,   "rend-tex-shiny", 1)
306                 .define(SReg::IntCVar,   "rend-tex-mipmap", 5)
307                 .define(SReg::IntCVar,   "rend-tex-quality", TEXQ_BEST)
308                 .define(SReg::IntCVar,   "rend-tex-anim-smooth", 1)
309                 .define(SReg::IntCVar,   "rend-tex-filter-smart", 0)
310                 .define(SReg::IntCVar,   "rend-tex-filter-sprite", 1)
311                 .define(SReg::IntCVar,   "rend-tex-filter-mag", 1)
312                 .define(SReg::IntCVar,   "rend-tex-filter-ui", 1)
313                 .define(SReg::IntCVar,   "rend-tex-filter-anisotropic", -1)
314                 .define(SReg::IntCVar,   "rend-tex-detail", 1)
315                 .define(SReg::FloatCVar, "rend-tex-detail-scale", 4)
316                 .define(SReg::FloatCVar, "rend-tex-detail-strength", .5f)
317 
318                 .define(SReg::IntCVar,   "rend-mobj-smooth-move", 2)
319                 .define(SReg::IntCVar,   "rend-mobj-smooth-turn", 1)
320 
321                 .define(SReg::IntCVar,   "rend-model", 1)
322                 .define(SReg::IntCVar,   "rend-model-inter", 1)
323                 .define(SReg::IntCVar,   "rend-model-distance", 1500)
324                 .define(SReg::FloatCVar, "rend-model-lod", 256)
325                 .define(SReg::FloatCVar, "rend-model-lights", 4)
326 
327                 .define(SReg::IntCVar,   "rend-sprite-mode", 0)
328                 .define(SReg::IntCVar,   "rend-sprite-blend", 1)
329                 .define(SReg::IntCVar,   "rend-sprite-lights", 4)
330                 .define(SReg::IntCVar,   "rend-sprite-align", 0)
331                 .define(SReg::IntCVar,   "rend-sprite-noz", 0)
332 
333                 .define(SReg::IntCVar,   "rend-particle", 1)
334                 .define(SReg::IntCVar,   "rend-particle-max", 0)
335                 .define(SReg::FloatCVar, "rend-particle-rate", 1)
336                 .define(SReg::FloatCVar, "rend-particle-diffuse", 4)
337                 .define(SReg::IntCVar,   "rend-particle-visible-near", 0)
338 
339                 .define(SReg::FloatCVar, "rend-sky-distance", 1600);
340     }
341 
342     //~Impl()
343     //{
344         //App::packageLoader().audienceForLoad()   -= this;
345         //App::packageLoader().audienceForUnload() -= this;
346     //}
347 
348     void packageLoaded(String const &packageId)
349     {
350         FS::FoundFiles found;
351         App::packageLoader().package(packageId).findPartialPath("shaders.dei", found);
352         DENG2_FOR_EACH(FS::FoundFiles, i, found)
353         {
354             // Load new shaders.
355             loadShaders(**i);
356         }
357     }
358 
359     void aboutToUnloadPackage(String const &packageId)
360     {
361         ClientApp::shaders().removeAllFromPackage(packageId);
362     }
363 
364     /*
365      * Reads all shader definitions and sets up a Bank where the actual
366      * compiled shaders are stored once they're needed.
367      *
368      * @todo This should be reworked to support unloading packages, and
369      * loading of new shaders from any newly loaded packages. -jk
370      */
371 //    void loadAllShaders()
372 //    {
373 //        // Load all the shader program definitions.
374 //        FS::FoundFiles found;
375 //        App::findInPackages("shaders.dei", found);
376 //        DENG2_FOR_EACH(FS::FoundFiles, i, found)
377 //        {
378 //            loadShaders(**i);
379 //        }
380 //    }
381 
382     void loadShaders(File const &defs)
383     {
384         LOG_MSG("Loading shader definitions from %s") << defs.description();
385         ClientApp::shaders().addFromInfo(defs);
386     }
387 
388     /**
389      * Reads the renderer's image definitions and sets up a Bank for caching them
390      * when they're needed.
391      */
392     void loadImages()
393     {
394         //Folder const &renderPack = App::fileSystem().find<Folder>("renderer.pack");
395         //images.addFromInfo(renderPack.locate<File>("images.dei"));
396     }
397 };
398 
RenderSystem()399 RenderSystem::RenderSystem() : d(new Impl(this))
400 {}
401 
glInit()402 void RenderSystem::glInit()
403 {
404     // Shader defines.
405     {
406         DictionaryValue defines;
407         defines.add(new TextValue("DGL_BATCH_MAX"),
408                     new NumberValue(DGL_BatchMaxSize()));
409         shaders().setPreprocessorDefines(defines);
410     }
411 
412     d->models.glInit();
413 }
414 
glDeinit()415 void RenderSystem::glDeinit()
416 {
417     d->models.glDeinit();
418     d->environment.glDeinit();
419 }
420 
shaders()421 GLShaderBank &RenderSystem::shaders()
422 {
423     return BaseGuiApp::shaders();
424 }
425 
images()426 ImageBank &RenderSystem::images()
427 {
428     return d->images;
429 }
430 
uMapTime() const431 GLUniform const &RenderSystem::uMapTime() const
432 {
433     return d->uMapTime;
434 }
435 
uProjectionMatrix() const436 GLUniform &RenderSystem::uProjectionMatrix() const
437 {
438     return d->uProjectionMatrix;
439 }
440 
uViewMatrix() const441 GLUniform &RenderSystem::uViewMatrix() const
442 {
443     return d->uViewMatrix;
444 }
445 
environment()446 render::Environment &RenderSystem::environment()
447 {
448     return d->environment;
449 }
450 
modelRenderer()451 ModelRenderer &RenderSystem::modelRenderer()
452 {
453     return d->models;
454 }
455 
sky()456 SkyDrawable &RenderSystem::sky()
457 {
458     return d->sky;
459 }
460 
timeChanged(Clock const &)461 void RenderSystem::timeChanged(Clock const &)
462 {
463     // Update the current map time for shaders.
464     d->uMapTime = ClientApp::world().time();
465 }
466 
settings()467 ConfigProfiles &RenderSystem::settings()
468 {
469     return d->settings;
470 }
471 
appearanceSettings()472 ConfigProfiles &RenderSystem::appearanceSettings()
473 {
474     return d->appearanceSettings;
475 }
476 
angleClipper() const477 AngleClipper &RenderSystem::angleClipper() const
478 {
479     return d->clipper;
480 }
481 
buffer()482 Store &RenderSystem::buffer()
483 {
484     return d->buffer;
485 }
486 
clearDrawLists()487 void RenderSystem::clearDrawLists()
488 {
489     d->drawLists.clear();
490 
491     // Clear the global vertex buffer, also.
492     d->buffer.clear();
493 }
494 
drawLists()495 DrawLists &RenderSystem::drawLists()
496 {
497     return d->drawLists;
498 }
499 
worldSystemMapChanged(world::Map &)500 void RenderSystem::worldSystemMapChanged(world::Map &)
501 {
502     d->projector.init();
503     d->vlights.init();
504 }
505 
beginFrame()506 void RenderSystem::beginFrame()
507 {
508     // Clear the draw lists ready for new geometry.
509     d->drawLists.reset();
510     d->buffer.rewind();  // Start reallocating storage from the global vertex buffer.
511 
512     // Clear the clipper - we're drawing from a new point of view.
513     d->clipper.clearRanges();
514 
515     // Recycle view dependent list data.
516     d->projector.reset();
517     d->vlights.reset();
518 
519     R_BeginFrame();
520 }
521 
findSurfaceProjectionList(duint * listIdx,bool sortByLuma)522 ProjectionList &RenderSystem::findSurfaceProjectionList(duint *listIdx, bool sortByLuma)
523 {
524     return d->projector.findOrCreateList(listIdx, sortByLuma);
525 }
526 
forAllSurfaceProjections(duint listIdx,std::function<LoopResult (ProjectedTextureData const &)> func) const527 LoopResult RenderSystem::forAllSurfaceProjections(duint listIdx, std::function<LoopResult (ProjectedTextureData const &)> func) const
528 {
529     if(ProjectionList *list = d->projector.tryFindList(listIdx))
530     {
531         for(ProjectionList::Node *node = list->head; node; node = node->next)
532         {
533             if(auto result = func(node->projection))
534                 return result;
535         }
536     }
537     return LoopContinue;
538 }
539 
findVectorLightList(duint * listIdx)540 VectorLightList &RenderSystem::findVectorLightList(duint *listIdx)
541 {
542     return d->vlights.findOrCreateList(listIdx);
543 }
544 
forAllVectorLights(duint listIdx,std::function<LoopResult (VectorLightData const &)> func)545 LoopResult RenderSystem::forAllVectorLights(duint listIdx, std::function<LoopResult (VectorLightData const &)> func)
546 {
547     if(VectorLightList *list = d->vlights.tryFindList(listIdx))
548     {
549         for(VectorLightList::Node *node = list->head; node; node = node->next)
550         {
551             if(auto result = func(node->vlight))
552                 return result;
553         }
554     }
555     return LoopContinue;
556 }
557 
consoleRegister()558 void RenderSystem::consoleRegister()
559 {
560     Viewports_Register();
561     Rend_Register();
562     H_Register();
563 }
564