1 /* 2 Copyright (c) 2017-2018 Timur Gafarov 3 4 Boost Software License - Version 1.0 - August 17th, 2003 5 Permission is hereby granted, free of charge, to any person or organization 6 obtaining a copy of the software and accompanying documentation covered by 7 this license (the "Software") to use, reproduce, display, distribute, 8 execute, and transmit the Software, and to prepare derivative works of the 9 Software, and to permit third-parties to whom the Software is furnished to 10 do so, all subject to the following: 11 12 The copyright notices in the Software and this entire statement, including 13 the above license grant, this restriction and the following disclaimer, 14 must be included in all copies of the Software, in whole or in part, and 15 all derivative works of the Software, unless such copies or derivative 16 works are solely in the form of machine-executable object code generated by 17 a source language processor. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 22 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 23 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 DEALINGS IN THE SOFTWARE. 26 */ 27 28 module dagon.resource.scene; 29 30 import std.stdio; 31 import std.math; 32 import std.algorithm; 33 34 import dlib.core.memory; 35 36 import dlib.container.array; 37 import dlib.container.dict; 38 import dlib.math.vector; 39 import dlib.math.matrix; 40 import dlib.math.transformation; 41 import dlib.image.color; 42 43 import derelict.opengl; 44 45 import dagon.core.ownership; 46 import dagon.core.event; 47 import dagon.core.application; 48 import dagon.resource.asset; 49 import dagon.resource.textasset; 50 import dagon.resource.textureasset; 51 import dagon.resource.fontasset; 52 import dagon.resource.obj; 53 import dagon.resource.iqm; 54 import dagon.resource.packageasset; 55 import dagon.graphics.environment; 56 import dagon.graphics.rc; 57 import dagon.graphics.view; 58 import dagon.graphics.shapes; 59 import dagon.graphics.clustered; 60 import dagon.graphics.shadow; 61 import dagon.graphics.texture; 62 import dagon.graphics.materials.generic; 63 import dagon.graphics.materials.standard; 64 import dagon.graphics.materials.sky; 65 import dagon.graphics.materials.hud; 66 import dagon.graphics.framebuffer; 67 import dagon.graphics.postproc; 68 import dagon.graphics.filters.fxaa; 69 import dagon.graphics.filters.lens; 70 import dagon.graphics.filters.hdrprepass; 71 import dagon.graphics.filters.hdr; 72 import dagon.graphics.filters.blur; 73 import dagon.graphics.filters.finalizer; 74 import dagon.logics.entity; 75 76 class BaseScene: EventListener 77 { 78 SceneManager sceneManager; 79 AssetManager assetManager; 80 bool canRun = false; 81 bool releaseAtNextStep = false; 82 bool needToLoad = true; 83 84 this(SceneManager smngr) 85 { 86 super(smngr.eventManager, null); 87 sceneManager = smngr; 88 assetManager = New!AssetManager(eventManager); 89 } 90 91 ~this() 92 { 93 release(); 94 Delete(assetManager); 95 } 96 97 // Set preload to true if you want to load the asset immediately 98 // before actual loading (e.g., to render a loading screen) 99 100 Asset addAsset(Asset asset, string filename, bool preload = false) 101 { 102 if (preload) 103 assetManager.preloadAsset(asset, filename); 104 else 105 assetManager.addAsset(asset, filename); 106 return asset; 107 } 108 109 void onAssetsRequest() 110 { 111 // Add your assets here 112 } 113 114 void onLoading(float percentage) 115 { 116 // Render your loading screen here 117 } 118 119 void onAllocate() 120 { 121 // Allocate your objects here 122 } 123 124 void onRelease() 125 { 126 // Release your objects here 127 } 128 129 void onStart() 130 { 131 // Do your (re)initialization here 132 } 133 134 void onEnd() 135 { 136 // Do your finalization here 137 } 138 139 void onUpdate(double dt) 140 { 141 // Do your animation and logics here 142 } 143 144 void onRender() 145 { 146 // Do your rendering here 147 } 148 149 void exitApplication() 150 { 151 generateUserEvent(DagonEvent.Exit); 152 } 153 154 void load() 155 { 156 if (needToLoad) 157 { 158 onAssetsRequest(); 159 float p = assetManager.nextLoadingPercentage; 160 161 assetManager.loadThreadSafePart(); 162 163 while(assetManager.isLoading) 164 { 165 sceneManager.application.beginRender(); 166 onLoading(p); 167 sceneManager.application.endRender(); 168 p = assetManager.nextLoadingPercentage; 169 } 170 171 bool loaded = assetManager.loadThreadUnsafePart(); 172 173 if (loaded) 174 { 175 onAllocate(); 176 canRun = true; 177 needToLoad = false; 178 } 179 else 180 { 181 writeln("Exiting due to error while loading assets"); 182 canRun = false; 183 eventManager.running = false; 184 } 185 } 186 else 187 { 188 canRun = true; 189 } 190 } 191 192 void release() 193 { 194 onRelease(); 195 clearOwnedObjects(); 196 assetManager.releaseAssets(); 197 needToLoad = true; 198 canRun = false; 199 } 200 201 void start() 202 { 203 if (canRun) 204 onStart(); 205 } 206 207 void end() 208 { 209 if (canRun) 210 onEnd(); 211 } 212 213 void update(double dt) 214 { 215 if (canRun) 216 { 217 processEvents(); 218 assetManager.updateMonitor(dt); 219 onUpdate(dt); 220 } 221 222 if (releaseAtNextStep) 223 { 224 end(); 225 release(); 226 227 releaseAtNextStep = false; 228 canRun = false; 229 } 230 } 231 232 void render() 233 { 234 if (canRun) 235 onRender(); 236 } 237 } 238 239 class SceneManager: Owner 240 { 241 SceneApplication application; 242 Dict!(BaseScene, string) scenesByName; 243 EventManager eventManager; 244 BaseScene currentScene; 245 246 this(EventManager emngr, SceneApplication app) 247 { 248 super(app); 249 application = app; 250 eventManager = emngr; 251 scenesByName = New!(Dict!(BaseScene, string)); 252 } 253 254 ~this() 255 { 256 foreach(i, s; scenesByName) 257 { 258 Delete(s); 259 } 260 Delete(scenesByName); 261 } 262 263 BaseScene addScene(BaseScene scene, string name) 264 { 265 scenesByName[name] = scene; 266 return scene; 267 } 268 269 void removeScene(string name) 270 { 271 Delete(scenesByName[name]); 272 scenesByName.remove(name); 273 } 274 275 void goToScene(string name, bool releaseCurrent = true) 276 { 277 if (currentScene && releaseCurrent) 278 { 279 currentScene.releaseAtNextStep = true; 280 } 281 282 BaseScene scene = scenesByName[name]; 283 284 writefln("Loading scene \"%s\"", name); 285 286 scene.load(); 287 currentScene = scene; 288 currentScene.start(); 289 290 writefln("Running...", name); 291 } 292 293 void update(double dt) 294 { 295 if (currentScene) 296 { 297 currentScene.update(dt); 298 } 299 } 300 301 void render() 302 { 303 if (currentScene) 304 { 305 currentScene.render(); 306 } 307 } 308 } 309 310 class SceneApplication: Application 311 { 312 SceneManager sceneManager; 313 314 this(uint w, uint h, bool fullscreen, string windowTitle, string[] args) 315 { 316 super(w, h, fullscreen, windowTitle, args); 317 318 sceneManager = New!SceneManager(eventManager, this); 319 } 320 321 override void onUpdate(double dt) 322 { 323 sceneManager.update(dt); 324 } 325 326 override void onRender() 327 { 328 sceneManager.render(); 329 } 330 } 331 332 class Scene: BaseScene 333 { 334 Environment environment; 335 336 ClusteredLightManager lightManager; 337 CascadedShadowMap shadowMap; 338 339 StandardBackend defaultMaterialBackend; 340 GenericMaterial defaultMaterial3D; 341 342 SkyBackend skyMaterialBackend; 343 344 RenderingContext rc3d; 345 RenderingContext rc2d; 346 View view; 347 348 Framebuffer sceneFramebuffer; 349 PostFilterHDR hdrFilter; 350 351 Framebuffer hdrPrepassFramebuffer; 352 PostFilterHDRPrepass hdrPrepassFilter; 353 354 Framebuffer hblurredFramebuffer; 355 Framebuffer vblurredFramebuffer; 356 PostFilterBlur hblur; 357 PostFilterBlur vblur; 358 359 PostFilterFXAA fxaaFilter; 360 PostFilterLensDistortion lensFilter; 361 362 PostFilterFinalizer finalizerFilter; 363 364 struct HDRSettings 365 { 366 BaseScene3D scene; 367 368 void tonemapper(Tonemapper f) @property 369 { 370 scene.hdrFilter.tonemapFunction = f; 371 } 372 373 Tonemapper tonemapper() @property 374 { 375 return scene.hdrFilter.tonemapFunction; 376 } 377 378 379 void minLuminance(float l) @property 380 { 381 scene.hdrFilter.minLuminance = l; 382 } 383 384 float minLuminance() @property 385 { 386 return scene.hdrFilter.minLuminance; 387 } 388 389 390 void maxLuminance(float l) @property 391 { 392 scene.hdrFilter.maxLuminance = l; 393 } 394 395 float maxLuminance() @property 396 { 397 return scene.hdrFilter.maxLuminance; 398 } 399 400 401 void keyValue(float k) @property 402 { 403 scene.hdrFilter.keyValue = k; 404 } 405 406 float keyValue() @property 407 { 408 return scene.hdrFilter.keyValue; 409 } 410 411 412 void adaptationSpeed(float s) @property 413 { 414 scene.hdrFilter.adaptationSpeed = s; 415 } 416 417 float adaptationSpeed() @property 418 { 419 return scene.hdrFilter.adaptationSpeed; 420 } 421 } 422 423 struct GlowSettings 424 { 425 BaseScene3D scene; 426 uint radius; 427 428 void enabled(bool mode) @property 429 { 430 scene.hblur.enabled = mode; 431 scene.vblur.enabled = mode; 432 scene.hdrPrepassFilter.glowEnabled = mode; 433 } 434 435 bool enabled() @property 436 { 437 return scene.hdrPrepassFilter.glowEnabled; 438 } 439 440 441 void brightness(float b) @property 442 { 443 scene.hdrPrepassFilter.glowBrightness = b; 444 } 445 446 float brightness() @property 447 { 448 return scene.hdrPrepassFilter.glowBrightness; 449 } 450 } 451 452 struct MotionBlurSettings 453 { 454 BaseScene3D scene; 455 456 void enabled(bool mode) @property 457 { 458 scene.hdrFilter.mblurEnabled = mode; 459 } 460 461 bool enabled() @property 462 { 463 return scene.hdrFilter.mblurEnabled; 464 } 465 466 467 void samples(uint s) @property 468 { 469 scene.hdrFilter.motionBlurSamples = s; 470 } 471 472 uint samples() @property 473 { 474 return scene.hdrFilter.motionBlurSamples; 475 } 476 477 478 void shutterSpeed(float s) @property 479 { 480 scene.hdrFilter.shutterSpeed = s; 481 scene.hdrFilter.shutterFps = 1.0 / s; 482 } 483 484 float shutterSpeed() @property 485 { 486 return scene.hdrFilter.shutterSpeed; 487 } 488 } 489 490 struct LUTSettings 491 { 492 BaseScene3D scene; 493 494 void texture(Texture tex) @property 495 { 496 scene.hdrFilter.colorTable = tex; 497 } 498 499 Texture texture() @property 500 { 501 return scene.hdrFilter.colorTable; 502 } 503 } 504 505 struct VignetteSettings 506 { 507 BaseScene3D scene; 508 509 void texture(Texture tex) @property 510 { 511 scene.hdrFilter.vignette = tex; 512 } 513 514 Texture texture() @property 515 { 516 return scene.hdrFilter.vignette; 517 } 518 } 519 520 struct AASettings 521 { 522 BaseScene3D scene; 523 524 void enabled(bool mode) @property 525 { 526 scene.fxaaFilter.enabled = mode; 527 } 528 529 bool enabled() @property 530 { 531 return scene.fxaaFilter.enabled; 532 } 533 } 534 535 struct LensSettings 536 { 537 BaseScene3D scene; 538 539 void enabled(bool mode) @property 540 { 541 scene.lensFilter.enabled = mode; 542 } 543 544 bool enabled() @property 545 { 546 return scene.lensFilter.enabled; 547 } 548 549 void scale(float s) @property 550 { 551 scene.lensFilter.scale = s; 552 } 553 554 float scale() @property 555 { 556 return scene.lensFilter.scale; 557 } 558 559 560 void dispersion(float d) @property 561 { 562 scene.lensFilter.dispersion = d; 563 } 564 565 float dispersion() @property 566 { 567 return scene.lensFilter.dispersion; 568 } 569 } 570 571 HDRSettings hdr; 572 MotionBlurSettings motionBlur; 573 GlowSettings glow; 574 LUTSettings lut; 575 VignetteSettings vignette; 576 AASettings antiAliasing; 577 LensSettings lensDistortion; 578 579 DynamicArray!PostFilter postFilters; 580 581 DynamicArray!Entity entities3D; 582 DynamicArray!Entity entities2D; 583 584 ShapeQuad loadingProgressBar; 585 Entity eLoadingProgressBar; 586 HUDMaterialBackend hudMaterialBackend; 587 GenericMaterial mLoadingProgressBar; 588 589 double timer = 0.0; 590 double fixedTimeStep = 1.0 / 60.0; 591 592 this(SceneManager smngr) 593 { 594 super(smngr); 595 596 rc3d.init(eventManager, environment); 597 rc3d.projectionMatrix = perspectiveMatrix(60.0f, eventManager.aspectRatio, 0.1f, 1000.0f); 598 599 rc2d.init(eventManager, environment); 600 rc2d.projectionMatrix = orthoMatrix(0.0f, eventManager.windowWidth, 0.0f, eventManager.windowHeight, 0.0f, 100.0f); 601 602 loadingProgressBar = New!ShapeQuad(assetManager); 603 eLoadingProgressBar = New!Entity(eventManager, assetManager); 604 eLoadingProgressBar.drawable = loadingProgressBar; 605 hudMaterialBackend = New!HUDMaterialBackend(assetManager); 606 mLoadingProgressBar = createMaterial(hudMaterialBackend); 607 mLoadingProgressBar.diffuse = Color4f(1, 1, 1, 1); 608 eLoadingProgressBar.material = mLoadingProgressBar; 609 } 610 611 void sortEntities(ref DynamicArray!Entity entities) 612 { 613 size_t j = 0; 614 Entity tmp; 615 616 auto edata = entities.data; 617 618 foreach(i, v; edata) 619 { 620 j = i; 621 size_t k = i; 622 623 while (k < edata.length) 624 { 625 float b1 = edata[j].layer; 626 float b2 = edata[k].layer; 627 628 if (b2 < b1) 629 j = k; 630 631 k++; 632 } 633 634 tmp = edata[i]; 635 edata[i] = edata[j]; 636 edata[j] = tmp; 637 638 sortEntities(v.children); 639 } 640 } 641 642 TextAsset addTextAsset(string filename, bool preload = false) 643 { 644 TextAsset text; 645 if (assetManager.assetExists(filename)) 646 text = cast(TextAsset)assetManager.getAsset(filename); 647 else 648 { 649 text = New!TextAsset(assetManager); 650 addAsset(text, filename, preload); 651 } 652 return text; 653 } 654 655 TextureAsset addTextureAsset(string filename, bool preload = false) 656 { 657 TextureAsset tex; 658 if (assetManager.assetExists(filename)) 659 tex = cast(TextureAsset)assetManager.getAsset(filename); 660 else 661 { 662 tex = New!TextureAsset(assetManager.imageFactory, assetManager.hdrImageFactory, assetManager); 663 addAsset(tex, filename, preload); 664 } 665 return tex; 666 } 667 668 FontAsset addFontAsset(string filename, uint height, bool preload = false) 669 { 670 FontAsset font; 671 if (assetManager.assetExists(filename)) 672 font = cast(FontAsset)assetManager.getAsset(filename); 673 else 674 { 675 font = New!FontAsset(height, assetManager); 676 addAsset(font, filename, preload); 677 } 678 return font; 679 } 680 681 OBJAsset addOBJAsset(string filename, bool preload = false) 682 { 683 OBJAsset obj; 684 if (assetManager.assetExists(filename)) 685 obj = cast(OBJAsset)assetManager.getAsset(filename); 686 else 687 { 688 obj = New!OBJAsset(assetManager); 689 addAsset(obj, filename, preload); 690 } 691 return obj; 692 } 693 694 IQMAsset addIQMAsset(string filename, bool preload = false) 695 { 696 IQMAsset iqm; 697 if (assetManager.assetExists(filename)) 698 iqm = cast(IQMAsset)assetManager.getAsset(filename); 699 else 700 { 701 iqm = New!IQMAsset(assetManager); 702 addAsset(iqm, filename, preload); 703 } 704 return iqm; 705 } 706 707 PackageAsset addPackageAsset(string filename, bool preload = false) 708 { 709 PackageAsset pa; 710 if (assetManager.assetExists(filename)) 711 pa = cast(PackageAsset)assetManager.getAsset(filename); 712 else 713 { 714 pa = New!PackageAsset(this, assetManager); 715 addAsset(pa, filename, preload); 716 } 717 return pa; 718 } 719 720 Entity createEntity2D(Entity parent = null) 721 { 722 Entity e; 723 if (parent) 724 e = New!Entity(parent); 725 else 726 { 727 e = New!Entity(eventManager, assetManager); 728 entities2D.append(e); 729 730 sortEntities(entities2D); 731 } 732 733 return e; 734 } 735 736 Entity createEntity3D(Entity parent = null) 737 { 738 Entity e; 739 if (parent) 740 e = New!Entity(parent); 741 else 742 { 743 e = New!Entity(eventManager, assetManager); 744 entities3D.append(e); 745 746 sortEntities(entities3D); 747 } 748 749 e.material = defaultMaterial3D; 750 751 return e; 752 } 753 754 Entity addEntity3D(Entity e) 755 { 756 entities3D.append(e); 757 sortEntities(entities3D); 758 return e; 759 } 760 761 Entity createSky() 762 { 763 auto matSky = createMaterial(skyMaterialBackend); 764 matSky.depthWrite = false; 765 766 auto eSky = createEntity3D(); 767 eSky.layer = 0; 768 eSky.attach = Attach.Camera; 769 eSky.castShadow = false; 770 eSky.material = matSky; 771 eSky.drawable = New!ShapeSphere(1.0f, 16, 8, true, assetManager); //aSphere.mesh; 772 eSky.scaling = Vector3f(100.0f, 100.0f, 100.0f); 773 sortEntities(entities3D); 774 return eSky; 775 } 776 777 GenericMaterial createMaterial(GenericMaterialBackend backend = null) 778 { 779 if (backend is null) 780 backend = defaultMaterialBackend; 781 return New!GenericMaterial(backend, assetManager); 782 } 783 784 LightSource createLight(Vector3f position, Color4f color, float energy, float volumeRadius, float areaRadius = 0.0f) 785 { 786 return lightManager.addLight(position, color, energy, volumeRadius, areaRadius); 787 } 788 789 override void onAllocate() 790 { 791 environment = New!Environment(assetManager); 792 793 lightManager = New!ClusteredLightManager(200.0f, 100, assetManager); 794 defaultMaterialBackend = New!StandardBackend(lightManager, assetManager); 795 796 skyMaterialBackend = New!SkyBackend(assetManager); 797 798 shadowMap = New!CascadedShadowMap(1024, this, 10, 30, 200, -100, 100, assetManager); 799 defaultMaterialBackend.shadowMap = shadowMap; 800 801 defaultMaterial3D = createMaterial(); 802 803 sceneFramebuffer = New!Framebuffer(eventManager.windowWidth, eventManager.windowHeight, true, true, assetManager); 804 805 hdr.scene = this; 806 motionBlur.scene = this; 807 glow.scene = this; 808 glow.radius = 3; 809 lut.scene = this; 810 vignette.scene = this; 811 antiAliasing.scene = this; 812 lensDistortion.scene = this; 813 814 hblurredFramebuffer = New!Framebuffer(eventManager.windowWidth / 2, eventManager.windowHeight / 2, true, false, assetManager); 815 hblur = New!PostFilterBlur(true, sceneFramebuffer, hblurredFramebuffer, assetManager); 816 817 vblurredFramebuffer = New!Framebuffer(eventManager.windowWidth / 2, eventManager.windowHeight / 2, true, false, assetManager); 818 vblur = New!PostFilterBlur(false, hblurredFramebuffer, vblurredFramebuffer, assetManager); 819 820 hdrPrepassFramebuffer = New!Framebuffer(eventManager.windowWidth, eventManager.windowHeight, true, false, assetManager); 821 hdrPrepassFilter = New!PostFilterHDRPrepass(sceneFramebuffer, hdrPrepassFramebuffer, assetManager); 822 hdrPrepassFilter.blurredTexture = vblurredFramebuffer.colorTexture; 823 postFilters.append(hdrPrepassFilter); 824 825 hdrFilter = New!PostFilterHDR(hdrPrepassFramebuffer, null, assetManager); 826 hdrFilter.velocityTexture = sceneFramebuffer.velocityTexture; 827 postFilters.append(hdrFilter); 828 829 fxaaFilter = New!PostFilterFXAA(null, null, assetManager); 830 postFilters.append(fxaaFilter); 831 fxaaFilter.enabled = false; 832 833 lensFilter = New!PostFilterLensDistortion(null, null, assetManager); 834 postFilters.append(lensFilter); 835 lensFilter.enabled = false; 836 837 finalizerFilter = New!PostFilterFinalizer(null, null, assetManager); 838 } 839 840 PostFilter addFilter(PostFilter f) 841 { 842 postFilters.append(f); 843 return f; 844 } 845 846 override void onRelease() 847 { 848 entities3D.free(); 849 entities2D.free(); 850 851 postFilters.free(); 852 } 853 854 override void onLoading(float percentage) 855 { 856 glEnable(GL_SCISSOR_TEST); 857 glScissor(0, 0, eventManager.windowWidth, eventManager.windowHeight); 858 glViewport(0, 0, eventManager.windowWidth, eventManager.windowHeight); 859 glClearColor(0, 0, 0, 1); 860 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 861 862 float maxWidth = eventManager.windowWidth * 0.33f; 863 float x = (eventManager.windowWidth - maxWidth) * 0.5f; 864 float y = eventManager.windowHeight * 0.5f - 10; 865 float w = percentage * maxWidth; 866 867 glDisable(GL_DEPTH_TEST); 868 mLoadingProgressBar.diffuse = Color4f(0.1, 0.1, 0.1, 1); 869 eLoadingProgressBar.position = Vector3f(x, y, 0); 870 eLoadingProgressBar.scaling = Vector3f(maxWidth, 10, 1); 871 eLoadingProgressBar.update(1.0/60.0); 872 eLoadingProgressBar.render(&rc2d); 873 874 mLoadingProgressBar.diffuse = Color4f(1, 1, 1, 1); 875 eLoadingProgressBar.scaling = Vector3f(w, 10, 1); 876 eLoadingProgressBar.update(1.0/60.0); 877 eLoadingProgressBar.render(&rc2d); 878 } 879 880 override void onStart() 881 { 882 rc3d.initPerspective(eventManager, environment, 60.0f, 0.1f, 1000.0f); 883 rc2d.initOrtho(eventManager, environment, 0.0f, 100.0f); 884 885 timer = 0.0; 886 } 887 888 void onLogicsUpdate(double dt) 889 { 890 } 891 892 override void onUpdate(double dt) 893 { 894 foreach(e; entities3D) 895 e.processEvents(); 896 897 foreach(e; entities2D) 898 e.processEvents(); 899 900 timer += dt; 901 if (timer >= fixedTimeStep) 902 { 903 timer -= fixedTimeStep; 904 905 if (view) 906 { 907 view.update(fixedTimeStep); 908 view.prepareRC(&rc3d); 909 } 910 911 rc3d.time += fixedTimeStep; 912 rc2d.time += fixedTimeStep; 913 914 foreach(e; entities3D) 915 e.update(fixedTimeStep); 916 917 foreach(e; entities2D) 918 e.update(fixedTimeStep); 919 920 onLogicsUpdate(fixedTimeStep); 921 922 environment.update(fixedTimeStep); 923 924 if (view) // TODO: allow to turn this off 925 { 926 Vector3f cameraDirection = -view.invViewMatrix.forward; 927 cameraDirection.y = 0.0f; 928 cameraDirection = cameraDirection.normalized; 929 930 shadowMap.area1.position = view.cameraPosition + cameraDirection * (shadowMap.projSize1 * 0.5f - 1.0f); 931 shadowMap.area2.position = view.cameraPosition + cameraDirection * shadowMap.projSize2 * 0.5f; 932 shadowMap.area3.position = view.cameraPosition + cameraDirection * shadowMap.projSize3 * 0.5f; 933 } 934 935 shadowMap.update(&rc3d, fixedTimeStep); 936 937 lightManager.update(&rc3d); 938 } 939 } 940 941 void renderShadows(RenderingContext* rc) 942 { 943 shadowMap.render(rc); 944 } 945 946 void renderEntities3D(RenderingContext* rc) 947 { 948 glEnable(GL_DEPTH_TEST); 949 foreach(e; entities3D) 950 e.render(rc); 951 } 952 953 void renderEntities2D(RenderingContext* rc) 954 { 955 glDisable(GL_DEPTH_TEST); 956 foreach(e; entities2D) 957 e.render(rc); 958 } 959 960 void prepareViewport(Framebuffer b = null) 961 { 962 glEnable(GL_SCISSOR_TEST); 963 if (b) 964 { 965 glScissor(0, 0, b.width, b.height); 966 glViewport(0, 0, b.width, b.height); 967 } 968 else 969 { 970 glScissor(0, 0, eventManager.windowWidth, eventManager.windowHeight); 971 glViewport(0, 0, eventManager.windowWidth, eventManager.windowHeight); 972 } 973 if (environment) 974 glClearColor(environment.backgroundColor.r, environment.backgroundColor.g, environment.backgroundColor.b, environment.backgroundColor.a); 975 } 976 977 void renderBlur(uint iterations) 978 { 979 RenderingContext rcTmp; 980 981 foreach(i; 1..iterations+1) 982 { 983 hblur.outputBuffer.bind(); 984 rcTmp.initOrtho(eventManager, environment, hblur.outputBuffer.width, hblur.outputBuffer.height, 0.0f, 100.0f); 985 prepareViewport(hblur.outputBuffer); 986 hblur.radius = i; 987 hblur.render(&rcTmp); 988 hblur.outputBuffer.unbind(); 989 990 vblur.outputBuffer.bind(); 991 rcTmp.initOrtho(eventManager, environment, vblur.outputBuffer.width, vblur.outputBuffer.height, 0.0f, 100.0f); 992 prepareViewport(vblur.outputBuffer); 993 vblur.radius = i; 994 vblur.render(&rcTmp); 995 vblur.outputBuffer.unbind(); 996 997 hblur.inputBuffer = vblur.outputBuffer; 998 } 999 1000 hblur.inputBuffer = sceneFramebuffer; 1001 } 1002 1003 override void onRender() 1004 { 1005 renderShadows(&rc3d); 1006 1007 sceneFramebuffer.bind(); 1008 prepareViewport(); 1009 sceneFramebuffer.clearBuffers(); 1010 renderEntities3D(&rc3d); 1011 sceneFramebuffer.unbind(); 1012 1013 sceneFramebuffer.genLuminanceMipmaps(); 1014 float lum = sceneFramebuffer.averageLuminance(); 1015 if (!isNaN(lum)) 1016 { 1017 float newExposure = hdrFilter.keyValue * (1.0f / clamp(lum, hdrFilter.minLuminance, hdrFilter.maxLuminance)); 1018 1019 float exposureDelta = newExposure - hdrFilter.exposure; 1020 hdrFilter.exposure += exposureDelta * hdrFilter.adaptationSpeed * eventManager.deltaTime; 1021 } 1022 1023 if (hdrPrepassFilter.glowEnabled) 1024 renderBlur(glow.radius); 1025 1026 RenderingContext rcTmp; 1027 Framebuffer nextInput = sceneFramebuffer; 1028 1029 hdrPrepassFilter.perspectiveMatrix = rc3d.projectionMatrix; 1030 1031 foreach(i, f; postFilters.data) 1032 if (f.enabled) 1033 { 1034 if (f.outputBuffer is null) 1035 f.outputBuffer = New!Framebuffer(eventManager.windowWidth, eventManager.windowHeight, false, false, assetManager); 1036 1037 if (f.inputBuffer is null) 1038 f.inputBuffer = nextInput; 1039 1040 nextInput = f.outputBuffer; 1041 1042 f.outputBuffer.bind(); 1043 rcTmp.initOrtho(eventManager, environment, f.outputBuffer.width, f.outputBuffer.height, 0.0f, 100.0f); 1044 prepareViewport(f.outputBuffer); 1045 f.render(&rcTmp); 1046 f.outputBuffer.unbind(); 1047 } 1048 1049 prepareViewport(); 1050 finalizerFilter.inputBuffer = nextInput; 1051 finalizerFilter.render(&rc2d); 1052 1053 renderEntities2D(&rc2d); 1054 } 1055 } 1056 1057 alias Scene BaseScene3D;