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 import std.traits; 34 35 import dlib.core.memory; 36 37 import dlib.container.array; 38 import dlib.container.dict; 39 import dlib.math.vector; 40 import dlib.math.matrix; 41 import dlib.math.transformation; 42 import dlib.image.color; 43 import dlib.image.image; 44 import dlib.image.unmanaged; 45 import dlib.image.io.png; 46 47 import dagon.core.libs; 48 import dagon.core.ownership; 49 import dagon.core.event; 50 import dagon.core.application; 51 52 import dagon.resource.asset; 53 import dagon.resource.textasset; 54 import dagon.resource.textureasset; 55 import dagon.resource.fontasset; 56 import dagon.resource.obj; 57 import dagon.resource.iqm; 58 import dagon.resource.packageasset; 59 60 import dagon.graphics.environment; 61 import dagon.graphics.rc; 62 import dagon.graphics.view; 63 import dagon.graphics.shapes; 64 import dagon.graphics.light; 65 import dagon.graphics.shadow; 66 import dagon.graphics.texture; 67 import dagon.graphics.particles; 68 import dagon.graphics.framebuffer; 69 import dagon.graphics.renderer; 70 import dagon.graphics.postproc; 71 72 import dagon.graphics.material; 73 74 import dagon.graphics.shader; 75 import dagon.graphics.shaders.standard; 76 import dagon.graphics.shaders.sky; 77 import dagon.graphics.shaders.particle; 78 import dagon.graphics.shaders.hud; 79 80 import dagon.graphics.filters.fxaa; 81 import dagon.graphics.filters.lens; 82 import dagon.graphics.filters.hdrprepass; 83 import dagon.graphics.filters.hdr; 84 import dagon.graphics.filters.blur; 85 import dagon.graphics.filters.finalizer; 86 87 import dagon.logics.entity; 88 89 class BaseScene: EventListener 90 { 91 SceneManager sceneManager; 92 AssetManager assetManager; 93 bool canRun = false; 94 bool releaseAtNextStep = false; 95 bool needToLoad = true; 96 97 this(SceneManager smngr) 98 { 99 super(smngr.eventManager, null); 100 sceneManager = smngr; 101 assetManager = New!AssetManager(eventManager); 102 } 103 104 ~this() 105 { 106 release(); 107 Delete(assetManager); 108 } 109 110 // Set preload to true if you want to load the asset immediately 111 // before actual loading (e.g., to render a loading screen) 112 Asset addAsset(Asset asset, string filename, bool preload = false) 113 { 114 if (preload) 115 assetManager.preloadAsset(asset, filename); 116 else 117 assetManager.addAsset(asset, filename); 118 return asset; 119 } 120 121 void onAssetsRequest() 122 { 123 // Add your assets here 124 } 125 126 void onLoading(float percentage) 127 { 128 // Render your loading screen here 129 } 130 131 void onAllocate() 132 { 133 // Allocate your objects here 134 } 135 136 void onRelease() 137 { 138 // Release your objects here 139 } 140 141 void onStart() 142 { 143 // Do your (re)initialization here 144 } 145 146 void onEnd() 147 { 148 // Do your finalization here 149 } 150 151 void onUpdate(double dt) 152 { 153 // Do your animation and logics here 154 } 155 156 void onRender() 157 { 158 // Do your rendering here 159 } 160 161 void exitApplication() 162 { 163 generateUserEvent(DagonEvent.Exit); 164 } 165 166 void load() 167 { 168 if (needToLoad) 169 { 170 onAssetsRequest(); 171 float p = assetManager.nextLoadingPercentage; 172 173 assetManager.loadThreadSafePart(); 174 175 while(assetManager.isLoading) 176 { 177 sceneManager.application.beginRender(); 178 onLoading(p); 179 sceneManager.application.endRender(); 180 p = assetManager.nextLoadingPercentage; 181 } 182 183 bool loaded = assetManager.loadThreadUnsafePart(); 184 185 if (loaded) 186 { 187 onAllocate(); 188 canRun = true; 189 needToLoad = false; 190 } 191 else 192 { 193 writeln("Exiting due to error while loading assets"); 194 canRun = false; 195 eventManager.running = false; 196 } 197 } 198 else 199 { 200 canRun = true; 201 } 202 } 203 204 void release() 205 { 206 onRelease(); 207 clearOwnedObjects(); 208 assetManager.releaseAssets(); 209 needToLoad = true; 210 canRun = false; 211 } 212 213 void start() 214 { 215 if (canRun) 216 onStart(); 217 } 218 219 void end() 220 { 221 if (canRun) 222 onEnd(); 223 } 224 225 void update(double dt) 226 { 227 if (canRun) 228 { 229 processEvents(); 230 assetManager.updateMonitor(dt); 231 onUpdate(dt); 232 } 233 234 if (releaseAtNextStep) 235 { 236 end(); 237 release(); 238 239 releaseAtNextStep = false; 240 canRun = false; 241 } 242 } 243 244 void render() 245 { 246 if (canRun) 247 onRender(); 248 } 249 } 250 251 class SceneManager: Owner 252 { 253 SceneApplication application; 254 Dict!(BaseScene, string) scenesByName; 255 EventManager eventManager; 256 BaseScene currentScene; 257 258 this(EventManager emngr, SceneApplication app) 259 { 260 super(app); 261 application = app; 262 eventManager = emngr; 263 scenesByName = New!(Dict!(BaseScene, string)); 264 } 265 266 ~this() 267 { 268 foreach(i, s; scenesByName) 269 { 270 Delete(s); 271 } 272 Delete(scenesByName); 273 } 274 275 BaseScene addScene(BaseScene scene, string name) 276 { 277 scenesByName[name] = scene; 278 return scene; 279 } 280 281 void removeScene(string name) 282 { 283 Delete(scenesByName[name]); 284 scenesByName.remove(name); 285 } 286 287 void goToScene(string name, bool releaseCurrent = true) 288 { 289 if (currentScene && releaseCurrent) 290 { 291 currentScene.releaseAtNextStep = true; 292 } 293 294 BaseScene scene = scenesByName[name]; 295 296 writefln("Loading scene \"%s\"", name); 297 298 scene.load(); 299 currentScene = scene; 300 currentScene.start(); 301 302 writefln("Running...", name); 303 } 304 305 void update(double dt) 306 { 307 if (currentScene) 308 { 309 currentScene.update(dt); 310 } 311 } 312 313 void render() 314 { 315 if (currentScene) 316 { 317 currentScene.render(); 318 } 319 } 320 } 321 322 class SceneApplication: Application 323 { 324 SceneManager sceneManager; 325 UnmanagedImageFactory imageFactory; 326 SuperImage screenshotBuffer1; 327 SuperImage screenshotBuffer2; 328 329 this(uint w, uint h, bool fullscreen, string windowTitle, string[] args) 330 { 331 super(w, h, fullscreen, windowTitle, args); 332 333 sceneManager = New!SceneManager(eventManager, this); 334 335 imageFactory = New!UnmanagedImageFactory(); 336 screenshotBuffer1 = imageFactory.createImage(eventManager.windowWidth, eventManager.windowHeight, 3, 8); 337 screenshotBuffer2 = imageFactory.createImage(eventManager.windowWidth, eventManager.windowHeight, 3, 8); 338 } 339 340 ~this() 341 { 342 Delete(imageFactory); 343 Delete(screenshotBuffer1); 344 Delete(screenshotBuffer2); 345 } 346 347 override void onUpdate(double dt) 348 { 349 sceneManager.update(dt); 350 } 351 352 override void onRender() 353 { 354 sceneManager.render(); 355 } 356 357 void saveScreenshot(string filename) 358 { 359 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 360 glReadPixels(0, 0, eventManager.windowWidth, eventManager.windowHeight, GL_RGB, GL_UNSIGNED_BYTE, screenshotBuffer1.data.ptr); 361 glPixelStorei(GL_UNPACK_ALIGNMENT, 4); 362 363 foreach(y; 0..screenshotBuffer1.height) 364 foreach(x; 0..screenshotBuffer1.width) 365 { 366 screenshotBuffer2[x, y] = screenshotBuffer1[x, screenshotBuffer1.height - y]; 367 } 368 369 screenshotBuffer2.savePNG(filename); 370 } 371 } 372 373 // TODO: Renderer class 374 class Scene: BaseScene 375 { 376 Renderer renderer; 377 378 Environment environment; 379 380 LightManager lightManager; 381 ParticleSystem particleSystem; 382 383 StandardShader standardShader; 384 SkyShader skyShader; 385 ParticleShader particleShader; 386 Material defaultMaterial3D; 387 388 RenderingContext rc3d; 389 RenderingContext rc2d; 390 View view; 391 392 PostFilterHDR hdrFilter; 393 394 Framebuffer hdrPrepassFramebuffer; 395 PostFilterHDRPrepass hdrPrepassFilter; 396 397 Framebuffer hblurredFramebuffer; 398 Framebuffer vblurredFramebuffer; 399 PostFilterBlur hblur; 400 PostFilterBlur vblur; 401 402 PostFilterFXAA fxaaFilter; 403 PostFilterLensDistortion lensFilter; 404 405 PostFilterFinalizer finalizerFilter; 406 407 //TODO: move post-processing to a separate class 408 struct SSAOSettings 409 { 410 BaseScene3D scene; 411 412 void enabled(bool mode) @property 413 { 414 scene.renderer.deferredEnvPass.shader.enableSSAO = mode; 415 } 416 417 bool enabled() @property 418 { 419 return scene.renderer.deferredEnvPass.shader.enableSSAO; 420 } 421 422 void samples(int s) @property 423 { 424 scene.renderer.deferredEnvPass.shader.ssaoSamples = s; 425 } 426 427 int samples() @property 428 { 429 return scene.renderer.deferredEnvPass.shader.ssaoSamples; 430 } 431 432 void radius(float r) @property 433 { 434 scene.renderer.deferredEnvPass.shader.ssaoRadius = r; 435 } 436 437 float radius() @property 438 { 439 return scene.renderer.deferredEnvPass.shader.ssaoRadius; 440 } 441 442 void power(float p) @property 443 { 444 scene.renderer.deferredEnvPass.shader.ssaoPower = p; 445 } 446 447 float power() @property 448 { 449 return scene.renderer.deferredEnvPass.shader.ssaoPower; 450 } 451 452 //TODO: other SSAO parameters 453 } 454 455 struct HDRSettings 456 { 457 BaseScene3D scene; 458 459 void tonemapper(Tonemapper f) @property 460 { 461 scene.hdrFilter.tonemapFunction = f; 462 } 463 464 Tonemapper tonemapper() @property 465 { 466 return scene.hdrFilter.tonemapFunction; 467 } 468 469 470 void exposure(float ex) @property 471 { 472 scene.hdrFilter.exposure = ex; 473 } 474 475 float exposure() @property 476 { 477 return scene.hdrFilter.exposure; 478 } 479 480 481 void autoExposure(bool mode) @property 482 { 483 scene.hdrFilter.autoExposure = mode; 484 } 485 486 bool autoExposure() @property 487 { 488 return scene.hdrFilter.autoExposure; 489 } 490 491 492 void minLuminance(float l) @property 493 { 494 scene.hdrFilter.minLuminance = l; 495 } 496 497 float minLuminance() @property 498 { 499 return scene.hdrFilter.minLuminance; 500 } 501 502 503 void maxLuminance(float l) @property 504 { 505 scene.hdrFilter.maxLuminance = l; 506 } 507 508 float maxLuminance() @property 509 { 510 return scene.hdrFilter.maxLuminance; 511 } 512 513 514 void keyValue(float k) @property 515 { 516 scene.hdrFilter.keyValue = k; 517 } 518 519 float keyValue() @property 520 { 521 return scene.hdrFilter.keyValue; 522 } 523 524 525 void adaptationSpeed(float s) @property 526 { 527 scene.hdrFilter.adaptationSpeed = s; 528 } 529 530 float adaptationSpeed() @property 531 { 532 return scene.hdrFilter.adaptationSpeed; 533 } 534 } 535 536 struct GlowSettings 537 { 538 BaseScene3D scene; 539 uint radius; 540 541 void enabled(bool mode) @property 542 { 543 scene.hblur.enabled = mode; 544 scene.vblur.enabled = mode; 545 scene.hdrPrepassFilter.glowEnabled = mode; 546 } 547 548 bool enabled() @property 549 { 550 return scene.hdrPrepassFilter.glowEnabled; 551 } 552 553 554 void brightness(float b) @property 555 { 556 scene.hdrPrepassFilter.glowBrightness = b; 557 } 558 559 float brightness() @property 560 { 561 return scene.hdrPrepassFilter.glowBrightness; 562 } 563 } 564 565 struct MotionBlurSettings 566 { 567 BaseScene3D scene; 568 569 void enabled(bool mode) @property 570 { 571 scene.hdrFilter.mblurEnabled = mode; 572 } 573 574 bool enabled() @property 575 { 576 return scene.hdrFilter.mblurEnabled; 577 } 578 579 580 void samples(uint s) @property 581 { 582 scene.hdrFilter.motionBlurSamples = s; 583 } 584 585 uint samples() @property 586 { 587 return scene.hdrFilter.motionBlurSamples; 588 } 589 590 591 void shutterSpeed(float s) @property 592 { 593 scene.hdrFilter.shutterSpeed = s; 594 scene.hdrFilter.shutterFps = 1.0 / s; 595 } 596 597 float shutterSpeed() @property 598 { 599 return scene.hdrFilter.shutterSpeed; 600 } 601 } 602 603 struct LUTSettings 604 { 605 BaseScene3D scene; 606 607 void texture(Texture tex) @property 608 { 609 scene.hdrFilter.colorTable = tex; 610 } 611 612 Texture texture() @property 613 { 614 return scene.hdrFilter.colorTable; 615 } 616 } 617 618 struct VignetteSettings 619 { 620 BaseScene3D scene; 621 622 void texture(Texture tex) @property 623 { 624 scene.hdrFilter.vignette = tex; 625 } 626 627 Texture texture() @property 628 { 629 return scene.hdrFilter.vignette; 630 } 631 } 632 633 struct AASettings 634 { 635 BaseScene3D scene; 636 637 void enabled(bool mode) @property 638 { 639 scene.fxaaFilter.enabled = mode; 640 } 641 642 bool enabled() @property 643 { 644 return scene.fxaaFilter.enabled; 645 } 646 } 647 648 struct LensSettings 649 { 650 BaseScene3D scene; 651 652 void enabled(bool mode) @property 653 { 654 scene.lensFilter.enabled = mode; 655 } 656 657 bool enabled() @property 658 { 659 return scene.lensFilter.enabled; 660 } 661 662 void scale(float s) @property 663 { 664 scene.lensFilter.scale = s; 665 } 666 667 float scale() @property 668 { 669 return scene.lensFilter.scale; 670 } 671 672 673 void dispersion(float d) @property 674 { 675 scene.lensFilter.dispersion = d; 676 } 677 678 float dispersion() @property 679 { 680 return scene.lensFilter.dispersion; 681 } 682 } 683 684 SSAOSettings ssao; 685 HDRSettings hdr; 686 MotionBlurSettings motionBlur; 687 GlowSettings glow; 688 LUTSettings lut; 689 VignetteSettings vignette; 690 AASettings antiAliasing; 691 LensSettings lensDistortion; 692 693 DynamicArray!PostFilter postFilters; 694 695 DynamicArray!Entity entities3D; 696 DynamicArray!Entity entities2D; 697 698 ShapeQuad loadingProgressBar; 699 Entity eLoadingProgressBar; 700 HUDShader hudShader; 701 Material mLoadingProgressBar; 702 703 double timer = 0.0; 704 double fixedTimeStep = 1.0 / 60.0; 705 706 this(SceneManager smngr) 707 { 708 super(smngr); 709 710 rc3d.init(eventManager, environment); 711 rc3d.projectionMatrix = perspectiveMatrix(60.0f, eventManager.aspectRatio, 0.1f, 1000.0f); 712 713 rc2d.init(eventManager, environment); 714 rc2d.projectionMatrix = orthoMatrix(0.0f, eventManager.windowWidth, 0.0f, eventManager.windowHeight, 0.0f, 100.0f); 715 716 loadingProgressBar = New!ShapeQuad(assetManager); 717 eLoadingProgressBar = New!Entity(eventManager, assetManager); 718 eLoadingProgressBar.drawable = loadingProgressBar; 719 hudShader = New!HUDShader(assetManager); 720 mLoadingProgressBar = createMaterial(hudShader); 721 mLoadingProgressBar.diffuse = Color4f(1, 1, 1, 1); 722 eLoadingProgressBar.material = mLoadingProgressBar; 723 } 724 725 void sortEntities(ref DynamicArray!Entity entities) 726 { 727 size_t j = 0; 728 Entity tmp; 729 730 auto edata = entities.data; 731 732 foreach(i, v; edata) 733 { 734 j = i; 735 size_t k = i; 736 737 while (k < edata.length) 738 { 739 float b1 = edata[j].layer; 740 float b2 = edata[k].layer; 741 742 if (b2 < b1) 743 j = k; 744 745 k++; 746 } 747 748 tmp = edata[i]; 749 edata[i] = edata[j]; 750 edata[j] = tmp; 751 752 sortEntities(v.children); 753 } 754 } 755 756 TextAsset addTextAsset(string filename, bool preload = false) 757 { 758 TextAsset text; 759 if (assetManager.assetExists(filename)) 760 text = cast(TextAsset)assetManager.getAsset(filename); 761 else 762 { 763 text = New!TextAsset(assetManager); 764 addAsset(text, filename, preload); 765 } 766 return text; 767 } 768 769 TextureAsset addTextureAsset(string filename, bool preload = false) 770 { 771 TextureAsset tex; 772 if (assetManager.assetExists(filename)) 773 tex = cast(TextureAsset)assetManager.getAsset(filename); 774 else 775 { 776 tex = New!TextureAsset(assetManager.imageFactory, assetManager.hdrImageFactory, assetManager); 777 addAsset(tex, filename, preload); 778 } 779 return tex; 780 } 781 782 FontAsset addFontAsset(string filename, uint height, bool preload = false) 783 { 784 FontAsset font; 785 if (assetManager.assetExists(filename)) 786 font = cast(FontAsset)assetManager.getAsset(filename); 787 else 788 { 789 font = New!FontAsset(height, assetManager); 790 addAsset(font, filename, preload); 791 } 792 return font; 793 } 794 795 OBJAsset addOBJAsset(string filename, bool preload = false) 796 { 797 OBJAsset obj; 798 if (assetManager.assetExists(filename)) 799 obj = cast(OBJAsset)assetManager.getAsset(filename); 800 else 801 { 802 obj = New!OBJAsset(assetManager); 803 addAsset(obj, filename, preload); 804 } 805 return obj; 806 } 807 808 IQMAsset addIQMAsset(string filename, bool preload = false) 809 { 810 IQMAsset iqm; 811 if (assetManager.assetExists(filename)) 812 iqm = cast(IQMAsset)assetManager.getAsset(filename); 813 else 814 { 815 iqm = New!IQMAsset(assetManager); 816 addAsset(iqm, filename, preload); 817 } 818 return iqm; 819 } 820 821 PackageAsset addPackageAsset(string filename, bool preload = false) 822 { 823 PackageAsset pa; 824 if (assetManager.assetExists(filename)) 825 pa = cast(PackageAsset)assetManager.getAsset(filename); 826 else 827 { 828 pa = New!PackageAsset(this, assetManager); 829 addAsset(pa, filename, preload); 830 } 831 return pa; 832 } 833 834 Entity createEntity2D(Entity parent = null) 835 { 836 Entity e; 837 if (parent) 838 e = New!Entity(parent); 839 else 840 { 841 e = New!Entity(eventManager, assetManager); 842 entities2D.append(e); 843 844 sortEntities(entities2D); 845 } 846 847 return e; 848 } 849 850 Entity createEntity3D(Entity parent = null) 851 { 852 Entity e; 853 if (parent) 854 e = New!Entity(parent); 855 else 856 { 857 e = New!Entity(eventManager, assetManager); 858 entities3D.append(e); 859 860 sortEntities(entities3D); 861 } 862 863 e.material = defaultMaterial3D; 864 865 return e; 866 } 867 868 Entity addEntity3D(Entity e) 869 { 870 entities3D.append(e); 871 sortEntities(entities3D); 872 return e; 873 } 874 875 Entity createSky(Material mat = null) 876 { 877 Material matSky; 878 if (mat is null) 879 { 880 matSky = New!Material(skyShader, assetManager); 881 matSky.depthWrite = false; 882 } 883 else 884 { 885 matSky = mat; 886 } 887 888 auto eSky = createEntity3D(); 889 eSky.layer = 0; 890 eSky.attach = Attach.Camera; 891 eSky.castShadow = false; 892 eSky.material = matSky; 893 // TODO: use box instead of sphere 894 eSky.drawable = New!ShapeSphere(1.0f, 16, 8, true, assetManager); 895 eSky.scaling = Vector3f(100.0f, 100.0f, 100.0f); 896 sortEntities(entities3D); 897 return eSky; 898 } 899 900 Material createMaterial(Shader shader) 901 { 902 auto m = New!Material(shader, assetManager); 903 if (shader !is standardShader) 904 m.customShader = true; 905 return m; 906 } 907 908 Material createMaterial() 909 { 910 return createMaterial(standardShader); 911 } 912 913 Material createParticleMaterial(Shader shader = null) 914 { 915 if (shader is null) 916 shader = particleShader; 917 return New!Material(shader, assetManager); 918 } 919 920 LightSource createLight(Vector3f position, Color4f color, float energy, float volumeRadius, float areaRadius = 0.0f) 921 { 922 return lightManager.addLight(position, color, energy, volumeRadius, areaRadius); 923 } 924 925 override void onAllocate() 926 { 927 environment = New!Environment(assetManager); 928 lightManager = New!LightManager(assetManager); 929 930 renderer = New!Renderer(this, assetManager); 931 932 standardShader = New!StandardShader(assetManager); 933 standardShader.shadowMap = renderer.shadowMap; 934 skyShader = New!SkyShader(assetManager); 935 particleShader = New!ParticleShader(renderer.gbuffer, assetManager); 936 937 particleSystem = New!ParticleSystem(assetManager); 938 939 defaultMaterial3D = createMaterial(); 940 941 ssao.scene = this; 942 hdr.scene = this; 943 motionBlur.scene = this; 944 glow.scene = this; 945 glow.radius = 3; 946 lut.scene = this; 947 vignette.scene = this; 948 antiAliasing.scene = this; 949 lensDistortion.scene = this; 950 951 hblurredFramebuffer = New!Framebuffer(renderer.gbuffer, eventManager.windowWidth / 2, eventManager.windowHeight / 2, true, false, assetManager); 952 hblur = New!PostFilterBlur(true, renderer.sceneFramebuffer, hblurredFramebuffer, assetManager); 953 954 vblurredFramebuffer = New!Framebuffer(renderer.gbuffer, eventManager.windowWidth / 2, eventManager.windowHeight / 2, true, false, assetManager); 955 vblur = New!PostFilterBlur(false, hblurredFramebuffer, vblurredFramebuffer, assetManager); 956 957 hdrPrepassFramebuffer = New!Framebuffer(renderer.gbuffer, eventManager.windowWidth, eventManager.windowHeight, true, false, assetManager); 958 hdrPrepassFilter = New!PostFilterHDRPrepass(renderer.sceneFramebuffer, hdrPrepassFramebuffer, assetManager); 959 hdrPrepassFilter.blurredTexture = vblurredFramebuffer.currentColorTexture; 960 postFilters.append(hdrPrepassFilter); 961 962 hdrFilter = New!PostFilterHDR(hdrPrepassFramebuffer, null, assetManager); 963 hdrFilter.velocityTexture = renderer.gbuffer.velocityTexture; 964 postFilters.append(hdrFilter); 965 966 fxaaFilter = New!PostFilterFXAA(null, null, assetManager); 967 postFilters.append(fxaaFilter); 968 fxaaFilter.enabled = false; 969 970 lensFilter = New!PostFilterLensDistortion(null, null, assetManager); 971 postFilters.append(lensFilter); 972 lensFilter.enabled = false; 973 974 finalizerFilter = New!PostFilterFinalizer(null, null, assetManager); 975 976 rc3d.initPerspective(eventManager, environment, 60.0f, 0.1f, 1000.0f); 977 rc2d.initOrtho(eventManager, environment, 0.0f, 100.0f); 978 979 timer = 0.0; 980 } 981 982 PostFilter addFilter(PostFilter f) 983 { 984 postFilters.append(f); 985 return f; 986 } 987 988 override void onRelease() 989 { 990 entities3D.free(); 991 entities2D.free(); 992 993 postFilters.free(); 994 } 995 996 override void onLoading(float percentage) 997 { 998 glEnable(GL_SCISSOR_TEST); 999 glScissor(0, 0, eventManager.windowWidth, eventManager.windowHeight); 1000 glViewport(0, 0, eventManager.windowWidth, eventManager.windowHeight); 1001 glClearColor(0, 0, 0, 1); 1002 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 1003 1004 float maxWidth = eventManager.windowWidth * 0.33f; 1005 float x = (eventManager.windowWidth - maxWidth) * 0.5f; 1006 float y = eventManager.windowHeight * 0.5f - 10; 1007 float w = percentage * maxWidth; 1008 1009 glDisable(GL_DEPTH_TEST); 1010 mLoadingProgressBar.diffuse = Color4f(0.1, 0.1, 0.1, 1); 1011 eLoadingProgressBar.position = Vector3f(x, y, 0); 1012 eLoadingProgressBar.scaling = Vector3f(maxWidth, 10, 1); 1013 eLoadingProgressBar.update(1.0/60.0); 1014 eLoadingProgressBar.render(&rc2d); 1015 1016 mLoadingProgressBar.diffuse = Color4f(1, 1, 1, 1); 1017 eLoadingProgressBar.scaling = Vector3f(w, 10, 1); 1018 eLoadingProgressBar.update(1.0/60.0); 1019 eLoadingProgressBar.render(&rc2d); 1020 } 1021 1022 override void onStart() 1023 { 1024 } 1025 1026 void onLogicsUpdate(double dt) 1027 { 1028 } 1029 1030 void fixedStepUpdate() 1031 { 1032 if (view) 1033 { 1034 view.update(fixedTimeStep); 1035 view.prepareRC(&rc3d); 1036 } 1037 1038 rc3d.time += fixedTimeStep; 1039 rc2d.time += fixedTimeStep; 1040 1041 foreach(e; entities3D) 1042 e.update(fixedTimeStep); 1043 1044 foreach(e; entities2D) 1045 e.update(fixedTimeStep); 1046 1047 particleSystem.update(fixedTimeStep); 1048 1049 onLogicsUpdate(fixedTimeStep); 1050 1051 environment.update(fixedTimeStep); 1052 1053 if (view) // TODO: allow to turn this off 1054 { 1055 Vector3f cameraDirection = -view.invViewMatrix.forward; 1056 cameraDirection.y = 0.0f; 1057 cameraDirection = cameraDirection.normalized; 1058 1059 renderer.shadowMap.area1.position = view.cameraPosition + cameraDirection * (renderer.shadowMap.projSize1 * 0.5f - 1.0f); 1060 renderer.shadowMap.area2.position = view.cameraPosition + cameraDirection * renderer.shadowMap.projSize2 * 0.5f; 1061 renderer.shadowMap.area3.position = view.cameraPosition + cameraDirection * renderer.shadowMap.projSize3 * 0.5f; 1062 } 1063 1064 renderer.shadowMap.update(&rc3d, fixedTimeStep); 1065 } 1066 1067 override void onUpdate(double dt) 1068 { 1069 foreach(e; entities3D) 1070 e.processEvents(); 1071 1072 foreach(e; entities2D) 1073 e.processEvents(); 1074 1075 timer += dt; 1076 if (timer >= fixedTimeStep) 1077 { 1078 timer -= fixedTimeStep; 1079 fixedStepUpdate(); 1080 } 1081 } 1082 1083 void renderBackgroundEntities3D(RenderingContext* rc) 1084 { 1085 glEnable(GL_DEPTH_TEST); 1086 foreach(e; entities3D) 1087 if (e.layer <= 0) 1088 e.render(rc); 1089 } 1090 1091 void renderOpaqueEntities3D(RenderingContext* rc) 1092 { 1093 glEnable(GL_DEPTH_TEST); 1094 RenderingContext rcLocal = *rc; 1095 rcLocal.ignoreTransparentEntities = true; 1096 foreach(e; entities3D) 1097 { 1098 if (e.layer > 0) 1099 e.render(&rcLocal); 1100 } 1101 } 1102 1103 void renderTransparentEntities3D(RenderingContext* rc) 1104 { 1105 glEnable(GL_DEPTH_TEST); 1106 RenderingContext rcLocal = *rc; 1107 rcLocal.ignoreOpaqueEntities = true; 1108 foreach(e; entities3D) 1109 { 1110 if (e.layer > 0) 1111 e.render(&rcLocal); 1112 } 1113 } 1114 1115 void renderEntities3D(RenderingContext* rc) 1116 { 1117 glEnable(GL_DEPTH_TEST); 1118 foreach(e; entities3D) 1119 e.render(rc); 1120 } 1121 1122 void renderEntities2D(RenderingContext* rc) 1123 { 1124 glDisable(GL_DEPTH_TEST); 1125 foreach(e; entities2D) 1126 e.render(rc); 1127 } 1128 1129 void renderBlur(uint iterations) 1130 { 1131 RenderingContext rcTmp; 1132 1133 foreach(i; 1..iterations+1) 1134 { 1135 hblur.outputBuffer.bind(); 1136 rcTmp.initOrtho(eventManager, environment, hblur.outputBuffer.width, hblur.outputBuffer.height, 0.0f, 100.0f); 1137 renderer.prepareViewport(hblur.outputBuffer); 1138 hblur.radius = i; 1139 hblur.render(&rcTmp); 1140 hblur.outputBuffer.unbind(); 1141 1142 vblur.outputBuffer.bind(); 1143 rcTmp.initOrtho(eventManager, environment, vblur.outputBuffer.width, vblur.outputBuffer.height, 0.0f, 100.0f); 1144 renderer.prepareViewport(vblur.outputBuffer); 1145 vblur.radius = i; 1146 vblur.render(&rcTmp); 1147 vblur.outputBuffer.unbind(); 1148 1149 hblur.inputBuffer = vblur.outputBuffer; 1150 } 1151 1152 hblur.inputBuffer = renderer.sceneFramebuffer; 1153 } 1154 1155 override void onRender() 1156 { 1157 renderer.render(&rc3d); 1158 1159 if (hdrFilter.autoExposure) 1160 { 1161 renderer.sceneFramebuffer.genLuminanceMipmaps(); 1162 float lum = renderer.sceneFramebuffer.averageLuminance(); 1163 1164 if (!isNaN(lum)) 1165 { 1166 float newExposure = hdrFilter.keyValue * (1.0f / clamp(lum, hdrFilter.minLuminance, hdrFilter.maxLuminance)); 1167 1168 float exposureDelta = newExposure - hdrFilter.exposure; 1169 hdrFilter.exposure += exposureDelta * hdrFilter.adaptationSpeed * eventManager.deltaTime; 1170 } 1171 } 1172 1173 if (hdrPrepassFilter.glowEnabled) 1174 renderBlur(glow.radius); 1175 1176 RenderingContext rcTmp; 1177 Framebuffer nextInput = renderer.sceneFramebuffer; 1178 1179 hdrPrepassFilter.perspectiveMatrix = rc3d.projectionMatrix; 1180 1181 foreach(i, f; postFilters.data) 1182 if (f.enabled) 1183 { 1184 if (f.outputBuffer is null) 1185 f.outputBuffer = New!Framebuffer(renderer.gbuffer, eventManager.windowWidth, eventManager.windowHeight, false, false, assetManager); 1186 1187 if (f.inputBuffer is null) 1188 f.inputBuffer = nextInput; 1189 1190 nextInput = f.outputBuffer; 1191 1192 f.outputBuffer.bind(); 1193 rcTmp.initOrtho(eventManager, environment, f.outputBuffer.width, f.outputBuffer.height, 0.0f, 100.0f); 1194 renderer.prepareViewport(f.outputBuffer); 1195 f.render(&rcTmp); 1196 f.outputBuffer.unbind(); 1197 } 1198 1199 renderer.prepareViewport(); 1200 finalizerFilter.inputBuffer = nextInput; 1201 finalizerFilter.render(&rc2d); 1202 1203 renderEntities2D(&rc2d); 1204 } 1205 } 1206 1207 alias Scene BaseScene3D;