From 02972b5961da8be4b8fbb7a8b62f258bb9422145 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sun, 2 Sep 2018 03:50:31 -0500 Subject: [PATCH 1/4] Clear out old core structure before adding the new module-ified structure. --- .../BaseGame/game/core/CoreComponents.cs | 10 - .../BaseGame/game/core/CoreComponents.module | 19 - Templates/BaseGame/game/core/audio.cs | 436 --- Templates/BaseGame/game/core/canvas.cs | 162 - .../components/RigidBodyComponent.asset.taml | 8 - .../components/animationComponent.asset.taml | 8 - .../cameraOrbiterComponent.asset.taml | 8 - .../components/collisionComponent.asset.taml | 8 - .../core/components/game/camera.asset.taml | 9 - .../game/core/components/game/camera.cs | 185 -- .../components/game/controlObject.asset.taml | 10 - .../core/components/game/controlObject.cs | 89 - .../components/game/itemRotate.asset.taml | 10 - .../game/core/components/game/itemRotate.cs | 49 - .../components/game/playerSpawner.asset.taml | 10 - .../core/components/game/playerSpawner.cs | 78 - .../components/input/fpsControls.asset.taml | 9 - .../game/core/components/input/fpsControls.cs | 247 -- .../core/components/input/inputManager.cs | 82 - .../core/components/meshComponent.asset.taml | 8 - .../playerControllerComponent.asset.taml | 8 - .../core/components/soundComponent.asset.taml | 8 - .../stateMachineComponent.asset.taml | 8 - .../BaseGame/game/core/console/console.gui | 191 -- Templates/BaseGame/game/core/console/main.cs | 140 - .../BaseGame/game/core/console/profiles.cs | 70 - Templates/BaseGame/game/core/cursor.cs | 102 - .../game/core/fonts/Arial 10 (ansi).uft | Bin 412 -> 0 bytes .../game/core/fonts/Arial 12 (ansi).uft | Bin 62 -> 0 bytes .../game/core/fonts/Arial 14 (ansi).uft | Bin 5160 -> 0 bytes .../game/core/fonts/Arial 16 (ansi).uft | Bin 13112 -> 0 bytes .../game/core/fonts/Arial 36 (ansi).uft | Bin 1046 -> 0 bytes .../game/core/fonts/Arial Bold 14 (ansi).uft | Bin 3227 -> 0 bytes .../game/core/fonts/Arial Bold 16 (ansi).uft | Bin 1254 -> 0 bytes .../game/core/fonts/Arial Bold 18 (ansi).uft | Bin 5276 -> 0 bytes .../game/core/fonts/ArialBold 14 (ansi).uft | Bin 2276 -> 0 bytes .../game/core/fonts/ArialItalic 14 (ansi).uft | Bin 2951 -> 0 bytes .../core/fonts/Lucida Console 12 (ansi).uft | Bin 5897 -> 0 bytes .../BaseGame/game/core/gfxData/clouds.cs | 55 - .../game/core/gfxData/commonMaterialData.cs | 79 - .../BaseGame/game/core/gfxData/scatterSky.cs | 48 - .../BaseGame/game/core/gfxData/shaders.cs | 152 - .../game/core/gfxData/terrainBlock.cs | 36 - Templates/BaseGame/game/core/gfxData/water.cs | 208 -- .../gfxprofile/D3D9.ATITechnologiesInc.cs | 36 - .../gfxprofile/D3D9.NVIDIA.GeForce8600.cs | 36 - .../gfxprofile/D3D9.NVIDIA.QuadroFXGo1000.cs | 39 - .../game/core/gfxprofile/D3D9.NVIDIA.cs | 36 - .../BaseGame/game/core/gfxprofile/D3D9.cs | 26 - Templates/BaseGame/game/core/globals.cs | 102 - .../BaseGame/game/core/helperFunctions.cs | 1158 ------- .../BaseGame/game/core/images/AreaMap33.dds | Bin 109028 -> 0 bytes .../BaseGame/game/core/images/button.png | Bin 1153 -> 0 bytes .../BaseGame/game/core/images/caustics_1.png | Bin 34398 -> 0 bytes .../BaseGame/game/core/images/caustics_2.png | Bin 33963 -> 0 bytes .../BaseGame/game/core/images/checkbox.png | Bin 3943 -> 0 bytes .../game/core/images/group-border.png | Bin 1273 -> 0 bytes .../game/core/images/inactive-overlay.png | Bin 131 -> 0 bytes .../BaseGame/game/core/images/loadingbar.png | Bin 635 -> 0 bytes .../BaseGame/game/core/images/materials.cs | 32 - .../game/core/images/missingTexture.png | Bin 10645 -> 0 bytes Templates/BaseGame/game/core/images/noise.png | Bin 14610 -> 0 bytes .../game/core/images/null_color_ramp.png | Bin 2843 -> 0 bytes .../BaseGame/game/core/images/scrollBar.png | Bin 3332 -> 0 bytes .../BaseGame/game/core/images/textEdit.png | Bin 250 -> 0 bytes .../game/core/images/thumbHighlightButton.png | Bin 778 -> 0 bytes .../BaseGame/game/core/images/unavailable.png | Bin 26528 -> 0 bytes .../BaseGame/game/core/images/warnMat.dds | Bin 699192 -> 0 bytes .../BaseGame/game/core/images/window.png | Bin 2559 -> 0 bytes Templates/BaseGame/game/core/lighting.cs | 74 - .../core/lighting/advanced/deferredShading.cs | 71 - .../game/core/lighting/advanced/init.cs | 68 - .../game/core/lighting/advanced/shaders.cs | 276 -- .../BaseGame/game/core/lighting/basic/init.cs | 92 - .../game/core/lighting/basic/shadowFilter.cs | 76 - .../game/core/lighting/shadowMaps/init.cs | 32 - Templates/BaseGame/game/core/main.cs | 99 - Templates/BaseGame/game/core/oculusVR.cs | 248 -- .../BaseGame/game/core/oculusVROverlay.gui | 19 - Templates/BaseGame/game/core/parseArgs.cs | 392 --- .../BaseGame/game/core/postFX/GammaPostFX.cs | 73 - Templates/BaseGame/game/core/postFX/MLAA.cs | 186 -- .../BaseGame/game/core/postFX/MotionBlurFx.cs | 53 - .../BaseGame/game/core/postFX/caustics.cs | 64 - .../game/core/postFX/chromaticLens.cs | 77 - .../game/core/postFX/default.postfxpreset.cs | 72 - Templates/BaseGame/game/core/postFX/dof.cs | 599 ---- Templates/BaseGame/game/core/postFX/edgeAA.cs | 113 - Templates/BaseGame/game/core/postFX/flash.cs | 63 - Templates/BaseGame/game/core/postFX/fog.cs | 135 - Templates/BaseGame/game/core/postFX/fxaa.cs | 64 - Templates/BaseGame/game/core/postFX/glow.cs | 184 -- Templates/BaseGame/game/core/postFX/hdr.cs | 529 ---- .../BaseGame/game/core/postFX/lightRay.cs | 110 - .../game/core/postFX/ovrBarrelDistortion.cs | 167 - .../game/core/postFX/postFxManager.gui | 2755 ----------------- .../game/core/postFX/postFxManager.gui.cs | 446 --- .../core/postFX/postFxManager.gui.settings.cs | 439 --- .../core/postFX/postFxManager.persistance.cs | 79 - Templates/BaseGame/game/core/postFX/ssao.cs | 302 -- .../BaseGame/game/core/postFX/turbulence.cs | 57 - .../BaseGame/game/core/postFX/vignette.cs | 55 - Templates/BaseGame/game/core/postFx.cs | 88 - Templates/BaseGame/game/core/profiles.cs | 226 -- Templates/BaseGame/game/core/renderManager.cs | 136 - .../BaseGame/game/core/sfx/audioAmbience.cs | 44 - Templates/BaseGame/game/core/sfx/audioData.cs | 42 - .../game/core/sfx/audioDescriptions.cs | 143 - .../game/core/sfx/audioEnvironments.cs | 916 ------ .../BaseGame/game/core/sfx/audioStates.cs | 158 - .../core/shaders/VolumetricFog/VFogP.hlsl | 87 - .../core/shaders/VolumetricFog/VFogPreP.hlsl | 40 - .../core/shaders/VolumetricFog/VFogPreV.hlsl | 44 - .../core/shaders/VolumetricFog/VFogRefl.hlsl | 38 - .../core/shaders/VolumetricFog/VFogV.hlsl | 46 - .../core/shaders/VolumetricFog/gl/VFogP.glsl | 87 - .../shaders/VolumetricFog/gl/VFogPreP.glsl | 37 - .../shaders/VolumetricFog/gl/VFogPreV.glsl | 42 - .../shaders/VolumetricFog/gl/VFogRefl.glsl | 33 - .../core/shaders/VolumetricFog/gl/VFogV.glsl | 38 - .../game/core/shaders/basicCloudsP.hlsl | 37 - .../game/core/shaders/basicCloudsV.hlsl | 58 - .../game/core/shaders/cloudLayerP.hlsl | 146 - .../game/core/shaders/cloudLayerV.hlsl | 106 - .../fixedFunction/addColorTextureP.hlsl | 37 - .../fixedFunction/addColorTextureV.hlsl | 48 - .../core/shaders/fixedFunction/colorP.hlsl | 34 - .../core/shaders/fixedFunction/colorV.hlsl | 45 - .../fixedFunction/gl/addColorTextureP.glsl | 32 - .../fixedFunction/gl/addColorTextureV.glsl | 38 - .../core/shaders/fixedFunction/gl/colorP.glsl | 30 - .../core/shaders/fixedFunction/gl/colorV.glsl | 35 - .../fixedFunction/gl/modColorTextureP.glsl | 32 - .../fixedFunction/gl/modColorTextureV.glsl | 38 - .../fixedFunction/gl/targetRestoreP.glsl | 31 - .../fixedFunction/gl/targetRestoreV.glsl | 22 - .../shaders/fixedFunction/gl/textureP.glsl | 31 - .../shaders/fixedFunction/gl/textureV.glsl | 35 - .../fixedFunction/modColorTextureP.hlsl | 37 - .../fixedFunction/modColorTextureV.hlsl | 48 - .../shaders/fixedFunction/targetRestoreP.hlsl | 31 - .../shaders/fixedFunction/targetRestoreV.hlsl | 26 - .../core/shaders/fixedFunction/textureP.hlsl | 36 - .../core/shaders/fixedFunction/textureV.hlsl | 46 - .../BaseGame/game/core/shaders/foliage.hlsl | 186 -- .../core/shaders/fxFoliageReplicatorP.hlsl | 60 - .../core/shaders/fxFoliageReplicatorV.hlsl | 129 - .../game/core/shaders/gl/basicCloudsP.glsl | 39 - .../game/core/shaders/gl/basicCloudsV.glsl | 53 - .../BaseGame/game/core/shaders/gl/blurP.glsl | 39 - .../BaseGame/game/core/shaders/gl/blurV.glsl | 48 - .../game/core/shaders/gl/cloudLayerP.glsl | 147 - .../game/core/shaders/gl/cloudLayerV.glsl | 106 - .../game/core/shaders/gl/foliage.glsl | 186 -- .../core/shaders/gl/fxFoliageReplicatorP.glsl | 42 - .../core/shaders/gl/fxFoliageReplicatorV.glsl | 99 - .../game/core/shaders/gl/guiMaterialV.glsl | 39 - .../game/core/shaders/gl/hlslCompat.glsl | 101 - .../game/core/shaders/gl/imposter.glsl | 161 - .../game/core/shaders/gl/lighting.glsl | 249 -- .../core/shaders/gl/particleCompositeP.glsl | 62 - .../core/shaders/gl/particleCompositeV.glsl | 48 - .../game/core/shaders/gl/particlesP.glsl | 113 - .../game/core/shaders/gl/particlesV.glsl | 54 - .../core/shaders/gl/planarReflectBumpP.glsl | 70 - .../core/shaders/gl/planarReflectBumpV.glsl | 51 - .../game/core/shaders/gl/planarReflectP.glsl | 43 - .../game/core/shaders/gl/planarReflectV.glsl | 51 - .../game/core/shaders/gl/precipP.glsl | 39 - .../game/core/shaders/gl/precipV.glsl | 54 - .../core/shaders/gl/projectedShadowP.glsl | 37 - .../core/shaders/gl/projectedShadowV.glsl | 49 - .../game/core/shaders/gl/scatterSkyP.glsl | 72 - .../game/core/shaders/gl/scatterSkyV.glsl | 154 - .../BaseGame/game/core/shaders/gl/torque.glsl | 339 -- .../BaseGame/game/core/shaders/gl/wavesP.glsl | 57 - .../BaseGame/game/core/shaders/gl/wind.glsl | 101 - .../game/core/shaders/guiMaterialV.hlsl | 45 - .../BaseGame/game/core/shaders/hlslStructs.h | 116 - .../game/core/shaders/hlslStructs.hlsl | 114 - .../BaseGame/game/core/shaders/imposter.hlsl | 149 - .../BaseGame/game/core/shaders/lighting.hlsl | 249 -- .../lighting/advanced/convexGeometryV.hlsl | 54 - .../advanced/deferredClearGBufferP.hlsl | 54 - .../advanced/deferredClearGBufferV.hlsl | 43 - .../advanced/deferredColorShaderP.hlsl | 46 - .../lighting/advanced/deferredShadingP.hlsl | 54 - .../lighting/advanced/farFrustumQuad.hlsl | 47 - .../lighting/advanced/farFrustumQuadV.hlsl | 43 - .../lighting/advanced/gl/convexGeometryV.glsl | 52 - .../advanced/gl/deferredClearGBufferP.glsl | 40 - .../advanced/gl/deferredColorShaderP.glsl | 37 - .../advanced/gl/deferredShadingP.glsl | 59 - .../lighting/advanced/gl/farFrustumQuad.glsl | 30 - .../lighting/advanced/gl/farFrustumQuadV.glsl | 51 - .../lighting/advanced/gl/lightingUtils.glsl | 79 - .../lighting/advanced/gl/pointLightP.glsl | 273 -- .../lighting/advanced/gl/softShadow.glsl | 159 - .../lighting/advanced/gl/spotLightP.glsl | 210 -- .../lighting/advanced/gl/vectorLightP.glsl | 327 -- .../lighting/advanced/lightingUtils.hlsl | 51 - .../advanced/particlePointLightP.hlsl | 76 - .../advanced/particlePointLightV.hlsl | 48 - .../lighting/advanced/pointLightP.hlsl | 277 -- .../shaders/lighting/advanced/softShadow.hlsl | 158 - .../shaders/lighting/advanced/spotLightP.hlsl | 209 -- .../lighting/advanced/vectorLightP.hlsl | 328 -- .../lighting/basic/gl/shadowFilterP.glsl | 46 - .../lighting/basic/gl/shadowFilterV.glsl | 37 - .../shaders/lighting/basic/shadowFilterP.hlsl | 50 - .../shaders/lighting/basic/shadowFilterV.hlsl | 42 - .../lighting/shadowMap/boxFilterP.hlsl | 82 - .../lighting/shadowMap/boxFilterV.hlsl | 57 - .../lighting/shadowMap/gl/boxFilterP.glsl | 49 - .../lighting/shadowMap/gl/boxFilterV.glsl | 34 - .../shaders/lighting/shadowMap/shadowMapIO.h | 50 - .../lighting/shadowMap/shadowMapIO_GLSL.h | 50 - .../lighting/shadowMap/shadowMapIO_HLSL.h | 50 - .../game/core/shaders/particleCompositeP.hlsl | 61 - .../game/core/shaders/particleCompositeV.hlsl | 53 - .../game/core/shaders/particlesP.hlsl | 109 - .../game/core/shaders/particlesV.hlsl | 55 - .../game/core/shaders/planarReflectBumpP.hlsl | 87 - .../game/core/shaders/planarReflectBumpV.hlsl | 67 - .../game/core/shaders/planarReflectP.hlsl | 58 - .../game/core/shaders/planarReflectV.hlsl | 57 - .../game/core/shaders/postFX/VolFogGlowP.hlsl | 74 - .../shaders/postFX/caustics/causticsP.hlsl | 77 - .../shaders/postFX/caustics/gl/causticsP.glsl | 87 - .../core/shaders/postFX/chromaticLens.hlsl | 60 - .../shaders/postFX/dof/DOF_CalcCoC_P.hlsl | 53 - .../shaders/postFX/dof/DOF_CalcCoC_V.hlsl | 70 - .../shaders/postFX/dof/DOF_DownSample_P.hlsl | 143 - .../shaders/postFX/dof/DOF_DownSample_V.hlsl | 61 - .../core/shaders/postFX/dof/DOF_Final_P.hlsl | 145 - .../core/shaders/postFX/dof/DOF_Final_V.hlsl | 72 - .../shaders/postFX/dof/DOF_Gausian_P.hlsl | 63 - .../shaders/postFX/dof/DOF_Gausian_V.hlsl | 80 - .../shaders/postFX/dof/DOF_Passthrough_V.hlsl | 70 - .../shaders/postFX/dof/DOF_SmallBlur_P.hlsl | 46 - .../shaders/postFX/dof/DOF_SmallBlur_V.hlsl | 56 - .../shaders/postFX/dof/gl/DOF_CalcCoC_P.glsl | 55 - .../shaders/postFX/dof/gl/DOF_CalcCoC_V.glsl | 69 - .../postFX/dof/gl/DOF_DownSample_P.glsl | 143 - .../postFX/dof/gl/DOF_DownSample_V.glsl | 67 - .../shaders/postFX/dof/gl/DOF_Final_P.glsl | 147 - .../shaders/postFX/dof/gl/DOF_Final_V.glsl | 71 - .../shaders/postFX/dof/gl/DOF_Gausian_P.glsl | 68 - .../shaders/postFX/dof/gl/DOF_Gausian_V.glsl | 91 - .../postFX/dof/gl/DOF_Passthrough_V.glsl | 69 - .../postFX/dof/gl/DOF_SmallBlur_P.glsl | 46 - .../postFX/dof/gl/DOF_SmallBlur_V.glsl | 54 - .../postFX/edgeaa/dbgEdgeDisplayP.hlsl | 30 - .../core/shaders/postFX/edgeaa/edgeAAP.hlsl | 66 - .../core/shaders/postFX/edgeaa/edgeAAV.hlsl | 45 - .../shaders/postFX/edgeaa/edgeDetectP.hlsl | 93 - .../postFX/edgeaa/gl/dbgEdgeDisplayP.glsl | 36 - .../shaders/postFX/edgeaa/gl/edgeAAP.glsl | 70 - .../shaders/postFX/edgeaa/gl/edgeAAV.glsl | 43 - .../shaders/postFX/edgeaa/gl/edgeDetectP.glsl | 96 - .../game/core/shaders/postFX/flashP.hlsl | 36 - .../game/core/shaders/postFX/fogP.hlsl | 47 - .../game/core/shaders/postFX/fxaa/Fxaa3_11.h | 2047 ------------ .../game/core/shaders/postFX/fxaa/fxaaP.hlsl | 143 - .../game/core/shaders/postFX/fxaa/fxaaV.hlsl | 42 - .../core/shaders/postFX/fxaa/gl/fxaaP.glsl | 125 - .../core/shaders/postFX/fxaa/gl/fxaaV.glsl | 40 - .../game/core/shaders/postFX/gammaP.hlsl | 50 - .../core/shaders/postFX/gl/VolFogGlowP.glsl | 67 - .../core/shaders/postFX/gl/chromaticLens.glsl | 62 - .../game/core/shaders/postFX/gl/flashP.glsl | 39 - .../game/core/shaders/postFX/gl/fogP.glsl | 52 - .../game/core/shaders/postFX/gl/gammaP.glsl | 54 - .../core/shaders/postFX/gl/glowBlurP.glsl | 59 - .../core/shaders/postFX/gl/glowBlurV.glsl | 59 - .../core/shaders/postFX/gl/motionBlurP.glsl | 78 - .../core/shaders/postFX/gl/passthruP.glsl | 33 - .../game/core/shaders/postFX/gl/postFX.glsl | 63 - .../game/core/shaders/postFX/gl/postFxV.glsl | 52 - .../core/shaders/postFX/gl/turbulenceP.glsl | 52 - .../shaders/postFX/gl/underwaterFogP.glsl | 140 - .../game/core/shaders/postFX/glowBlurP.hlsl | 63 - .../game/core/shaders/postFX/glowBlurV.hlsl | 63 - .../shaders/postFX/hdr/bloomGaussBlurHP.hlsl | 68 - .../shaders/postFX/hdr/bloomGaussBlurVP.hlsl | 67 - .../shaders/postFX/hdr/brightPassFilterP.hlsl | 62 - .../postFX/hdr/calculateAdaptedLumP.hlsl | 44 - .../shaders/postFX/hdr/downScale4x4P.hlsl | 53 - .../shaders/postFX/hdr/downScale4x4V.hlsl | 138 - .../shaders/postFX/hdr/finalPassCombineP.hlsl | 92 - .../postFX/hdr/gl/bloomGaussBlurHP.glsl | 72 - .../postFX/hdr/gl/bloomGaussBlurVP.glsl | 71 - .../postFX/hdr/gl/brightPassFilterP.glsl | 65 - .../postFX/hdr/gl/calculateAdaptedLumP.glsl | 48 - .../shaders/postFX/hdr/gl/downScale4x4P.glsl | 50 - .../shaders/postFX/hdr/gl/downScale4x4V.glsl | 141 - .../postFX/hdr/gl/finalPassCombineP.glsl | 97 - .../shaders/postFX/hdr/gl/luminanceVisP.glsl | 42 - .../postFX/hdr/gl/sampleLumInitialP.glsl | 62 - .../postFX/hdr/gl/sampleLumIterativeP.glsl | 52 - .../shaders/postFX/hdr/luminanceVisP.hlsl | 39 - .../shaders/postFX/hdr/sampleLumInitialP.hlsl | 59 - .../postFX/hdr/sampleLumIterativeP.hlsl | 50 - .../postFX/lightRay/gl/lightRayOccludeP.glsl | 55 - .../shaders/postFX/lightRay/gl/lightRayP.glsl | 94 - .../postFX/lightRay/lightRayOccludeP.hlsl | 53 - .../shaders/postFX/lightRay/lightRayP.hlsl | 89 - .../postFX/mlaa/blendWeightCalculationP.hlsl | 78 - .../shaders/postFX/mlaa/edgeDetectionP.hlsl | 72 - .../core/shaders/postFX/mlaa/functions.hlsl | 145 - .../mlaa/gl/blendWeightCalculationP.glsl | 83 - .../postFX/mlaa/gl/edgeDetectionP.glsl | 76 - .../shaders/postFX/mlaa/gl/functions.glsl | 145 - .../postFX/mlaa/gl/neighborhoodBlendingP.glsl | 88 - .../core/shaders/postFX/mlaa/gl/offsetV.glsl | 57 - .../shaders/postFX/mlaa/gl/passthruV.glsl | 52 - .../postFX/mlaa/neighborhoodBlendingP.hlsl | 84 - .../core/shaders/postFX/mlaa/offsetV.hlsl | 42 - .../core/shaders/postFX/mlaa/passthruV.hlsl | 37 - .../game/core/shaders/postFX/motionBlurP.hlsl | 70 - .../oculusvr/barrelDistortionChromaP.hlsl | 95 - .../postFX/oculusvr/barrelDistortionP.hlsl | 80 - .../oculusvr/gl/barrelDistortionChromaP.glsl | 95 - .../postFX/oculusvr/gl/barrelDistortionP.glsl | 81 - .../postFX/oculusvr/gl/monoToStereoP.glsl | 60 - .../postFX/oculusvr/monoToStereoP.hlsl | 59 - .../game/core/shaders/postFX/passthruP.hlsl | 30 - .../game/core/shaders/postFX/postFx.hlsl | 40 - .../game/core/shaders/postFX/postFxV.glsl | 51 - .../game/core/shaders/postFX/postFxV.hlsl | 45 - .../core/shaders/postFX/ssao/SSAO_Blur_P.hlsl | 106 - .../core/shaders/postFX/ssao/SSAO_Blur_V.hlsl | 86 - .../game/core/shaders/postFX/ssao/SSAO_P.hlsl | 272 -- .../postFX/ssao/SSAO_PowerTable_P.hlsl | 29 - .../postFX/ssao/SSAO_PowerTable_V.hlsl | 45 - .../shaders/postFX/ssao/gl/SSAO_Blur_P.glsl | 108 - .../shaders/postFX/ssao/gl/SSAO_Blur_V.glsl | 96 - .../core/shaders/postFX/ssao/gl/SSAO_P.glsl | 278 -- .../postFX/ssao/gl/SSAO_PowerTable_P.glsl | 34 - .../postFX/ssao/gl/SSAO_PowerTable_V.glsl | 38 - .../game/core/shaders/postFX/turbulenceP.hlsl | 44 - .../core/shaders/postFX/underwaterFogP.hlsl | 138 - .../shaders/postFX/vignette/VignetteP.hlsl | 35 - .../shaders/postFX/vignette/gl/VignetteP.glsl | 41 - .../BaseGame/game/core/shaders/precipP.hlsl | 53 - .../BaseGame/game/core/shaders/precipV.hlsl | 71 - .../game/core/shaders/projectedShadowP.hlsl | 40 - .../game/core/shaders/projectedShadowV.hlsl | 60 - .../shaders/ribbons/basicRibbonShaderP.hlsl | 19 - .../shaders/ribbons/basicRibbonShaderV.hlsl | 35 - .../ribbons/gl/basicRibbonShaderP.glsl | 20 - .../ribbons/gl/basicRibbonShaderV.glsl | 37 - .../shaders/ribbons/gl/texRibbonShaderP.glsl | 22 - .../shaders/ribbons/gl/texRibbonShaderV.glsl | 37 - .../shaders/ribbons/texRibbonShaderP.hlsl | 21 - .../shaders/ribbons/texRibbonShaderV.hlsl | 35 - .../game/core/shaders/scatterSkyP.hlsl | 69 - .../game/core/shaders/scatterSkyV.hlsl | 157 - .../game/core/shaders/shaderModel.hlsl | 97 - .../game/core/shaders/shaderModelAutoGen.hlsl | 35 - .../BaseGame/game/core/shaders/shdrConsts.h | 117 - .../game/core/shaders/terrain/blendP.hlsl | 48 - .../game/core/shaders/terrain/blendV.hlsl | 52 - .../game/core/shaders/terrain/gl/blendP.glsl | 48 - .../game/core/shaders/terrain/gl/blendV.glsl | 41 - .../game/core/shaders/terrain/terrain.glsl | 52 - .../game/core/shaders/terrain/terrain.hlsl | 55 - .../BaseGame/game/core/shaders/torque.hlsl | 342 -- .../core/shaders/water/gl/waterBasicP.glsl | 216 -- .../core/shaders/water/gl/waterBasicV.glsl | 243 -- .../game/core/shaders/water/gl/waterP.glsl | 396 --- .../game/core/shaders/water/gl/waterV.glsl | 241 -- .../game/core/shaders/water/waterBasicP.hlsl | 213 -- .../game/core/shaders/water/waterBasicV.hlsl | 237 -- .../game/core/shaders/water/waterP.hlsl | 383 --- .../game/core/shaders/water/waterV.hlsl | 216 -- .../BaseGame/game/core/shaders/wavesP.hlsl | 89 - .../BaseGame/game/core/shaders/wavesV.hlsl | 90 - .../BaseGame/game/core/shaders/wind.hlsl | 101 - .../game/data/clientServer/ClientServer.cs | 112 - .../data/clientServer/ClientServer.module | 9 - .../clientServer/scripts/client/client.cs | 29 - .../scripts/client/connectionToServer.cs | 130 - .../scripts/client/levelDownload.cs | 185 -- .../clientServer/scripts/client/levelLoad.cs | 92 - .../clientServer/scripts/client/message.cs | 94 - .../data/clientServer/scripts/server/audio.cs | 40 - .../clientServer/scripts/server/commands.cs | 35 - .../scripts/server/connectionToClient.cs | 178 -- .../clientServer/scripts/server/defaults.cs | 62 - .../clientServer/scripts/server/kickban.cs | 41 - .../scripts/server/levelDownload.cs | 187 -- .../clientServer/scripts/server/levelInfo.cs | 197 -- .../clientServer/scripts/server/levelLoad.cs | 181 -- .../clientServer/scripts/server/message.cs | 50 - .../clientServer/scripts/server/server.cs | 303 -- 396 files changed, 39611 deletions(-) delete mode 100644 Templates/BaseGame/game/core/CoreComponents.cs delete mode 100644 Templates/BaseGame/game/core/CoreComponents.module delete mode 100644 Templates/BaseGame/game/core/audio.cs delete mode 100644 Templates/BaseGame/game/core/canvas.cs delete mode 100644 Templates/BaseGame/game/core/components/RigidBodyComponent.asset.taml delete mode 100644 Templates/BaseGame/game/core/components/animationComponent.asset.taml delete mode 100644 Templates/BaseGame/game/core/components/cameraOrbiterComponent.asset.taml delete mode 100644 Templates/BaseGame/game/core/components/collisionComponent.asset.taml delete mode 100644 Templates/BaseGame/game/core/components/game/camera.asset.taml delete mode 100644 Templates/BaseGame/game/core/components/game/camera.cs delete mode 100644 Templates/BaseGame/game/core/components/game/controlObject.asset.taml delete mode 100644 Templates/BaseGame/game/core/components/game/controlObject.cs delete mode 100644 Templates/BaseGame/game/core/components/game/itemRotate.asset.taml delete mode 100644 Templates/BaseGame/game/core/components/game/itemRotate.cs delete mode 100644 Templates/BaseGame/game/core/components/game/playerSpawner.asset.taml delete mode 100644 Templates/BaseGame/game/core/components/game/playerSpawner.cs delete mode 100644 Templates/BaseGame/game/core/components/input/fpsControls.asset.taml delete mode 100644 Templates/BaseGame/game/core/components/input/fpsControls.cs delete mode 100644 Templates/BaseGame/game/core/components/input/inputManager.cs delete mode 100644 Templates/BaseGame/game/core/components/meshComponent.asset.taml delete mode 100644 Templates/BaseGame/game/core/components/playerControllerComponent.asset.taml delete mode 100644 Templates/BaseGame/game/core/components/soundComponent.asset.taml delete mode 100644 Templates/BaseGame/game/core/components/stateMachineComponent.asset.taml delete mode 100644 Templates/BaseGame/game/core/console/console.gui delete mode 100644 Templates/BaseGame/game/core/console/main.cs delete mode 100644 Templates/BaseGame/game/core/console/profiles.cs delete mode 100644 Templates/BaseGame/game/core/cursor.cs delete mode 100644 Templates/BaseGame/game/core/fonts/Arial 10 (ansi).uft delete mode 100644 Templates/BaseGame/game/core/fonts/Arial 12 (ansi).uft delete mode 100644 Templates/BaseGame/game/core/fonts/Arial 14 (ansi).uft delete mode 100644 Templates/BaseGame/game/core/fonts/Arial 16 (ansi).uft delete mode 100644 Templates/BaseGame/game/core/fonts/Arial 36 (ansi).uft delete mode 100644 Templates/BaseGame/game/core/fonts/Arial Bold 14 (ansi).uft delete mode 100644 Templates/BaseGame/game/core/fonts/Arial Bold 16 (ansi).uft delete mode 100644 Templates/BaseGame/game/core/fonts/Arial Bold 18 (ansi).uft delete mode 100644 Templates/BaseGame/game/core/fonts/ArialBold 14 (ansi).uft delete mode 100644 Templates/BaseGame/game/core/fonts/ArialItalic 14 (ansi).uft delete mode 100644 Templates/BaseGame/game/core/fonts/Lucida Console 12 (ansi).uft delete mode 100644 Templates/BaseGame/game/core/gfxData/clouds.cs delete mode 100644 Templates/BaseGame/game/core/gfxData/commonMaterialData.cs delete mode 100644 Templates/BaseGame/game/core/gfxData/scatterSky.cs delete mode 100644 Templates/BaseGame/game/core/gfxData/shaders.cs delete mode 100644 Templates/BaseGame/game/core/gfxData/terrainBlock.cs delete mode 100644 Templates/BaseGame/game/core/gfxData/water.cs delete mode 100644 Templates/BaseGame/game/core/gfxprofile/D3D9.ATITechnologiesInc.cs delete mode 100644 Templates/BaseGame/game/core/gfxprofile/D3D9.NVIDIA.GeForce8600.cs delete mode 100644 Templates/BaseGame/game/core/gfxprofile/D3D9.NVIDIA.QuadroFXGo1000.cs delete mode 100644 Templates/BaseGame/game/core/gfxprofile/D3D9.NVIDIA.cs delete mode 100644 Templates/BaseGame/game/core/gfxprofile/D3D9.cs delete mode 100644 Templates/BaseGame/game/core/globals.cs delete mode 100644 Templates/BaseGame/game/core/helperFunctions.cs delete mode 100644 Templates/BaseGame/game/core/images/AreaMap33.dds delete mode 100644 Templates/BaseGame/game/core/images/button.png delete mode 100644 Templates/BaseGame/game/core/images/caustics_1.png delete mode 100644 Templates/BaseGame/game/core/images/caustics_2.png delete mode 100644 Templates/BaseGame/game/core/images/checkbox.png delete mode 100644 Templates/BaseGame/game/core/images/group-border.png delete mode 100644 Templates/BaseGame/game/core/images/inactive-overlay.png delete mode 100644 Templates/BaseGame/game/core/images/loadingbar.png delete mode 100644 Templates/BaseGame/game/core/images/materials.cs delete mode 100644 Templates/BaseGame/game/core/images/missingTexture.png delete mode 100644 Templates/BaseGame/game/core/images/noise.png delete mode 100644 Templates/BaseGame/game/core/images/null_color_ramp.png delete mode 100644 Templates/BaseGame/game/core/images/scrollBar.png delete mode 100644 Templates/BaseGame/game/core/images/textEdit.png delete mode 100644 Templates/BaseGame/game/core/images/thumbHighlightButton.png delete mode 100644 Templates/BaseGame/game/core/images/unavailable.png delete mode 100644 Templates/BaseGame/game/core/images/warnMat.dds delete mode 100644 Templates/BaseGame/game/core/images/window.png delete mode 100644 Templates/BaseGame/game/core/lighting.cs delete mode 100644 Templates/BaseGame/game/core/lighting/advanced/deferredShading.cs delete mode 100644 Templates/BaseGame/game/core/lighting/advanced/init.cs delete mode 100644 Templates/BaseGame/game/core/lighting/advanced/shaders.cs delete mode 100644 Templates/BaseGame/game/core/lighting/basic/init.cs delete mode 100644 Templates/BaseGame/game/core/lighting/basic/shadowFilter.cs delete mode 100644 Templates/BaseGame/game/core/lighting/shadowMaps/init.cs delete mode 100644 Templates/BaseGame/game/core/main.cs delete mode 100644 Templates/BaseGame/game/core/oculusVR.cs delete mode 100644 Templates/BaseGame/game/core/oculusVROverlay.gui delete mode 100644 Templates/BaseGame/game/core/parseArgs.cs delete mode 100644 Templates/BaseGame/game/core/postFX/GammaPostFX.cs delete mode 100644 Templates/BaseGame/game/core/postFX/MLAA.cs delete mode 100644 Templates/BaseGame/game/core/postFX/MotionBlurFx.cs delete mode 100644 Templates/BaseGame/game/core/postFX/caustics.cs delete mode 100644 Templates/BaseGame/game/core/postFX/chromaticLens.cs delete mode 100644 Templates/BaseGame/game/core/postFX/default.postfxpreset.cs delete mode 100644 Templates/BaseGame/game/core/postFX/dof.cs delete mode 100644 Templates/BaseGame/game/core/postFX/edgeAA.cs delete mode 100644 Templates/BaseGame/game/core/postFX/flash.cs delete mode 100644 Templates/BaseGame/game/core/postFX/fog.cs delete mode 100644 Templates/BaseGame/game/core/postFX/fxaa.cs delete mode 100644 Templates/BaseGame/game/core/postFX/glow.cs delete mode 100644 Templates/BaseGame/game/core/postFX/hdr.cs delete mode 100644 Templates/BaseGame/game/core/postFX/lightRay.cs delete mode 100644 Templates/BaseGame/game/core/postFX/ovrBarrelDistortion.cs delete mode 100644 Templates/BaseGame/game/core/postFX/postFxManager.gui delete mode 100644 Templates/BaseGame/game/core/postFX/postFxManager.gui.cs delete mode 100644 Templates/BaseGame/game/core/postFX/postFxManager.gui.settings.cs delete mode 100644 Templates/BaseGame/game/core/postFX/postFxManager.persistance.cs delete mode 100644 Templates/BaseGame/game/core/postFX/ssao.cs delete mode 100644 Templates/BaseGame/game/core/postFX/turbulence.cs delete mode 100644 Templates/BaseGame/game/core/postFX/vignette.cs delete mode 100644 Templates/BaseGame/game/core/postFx.cs delete mode 100644 Templates/BaseGame/game/core/profiles.cs delete mode 100644 Templates/BaseGame/game/core/renderManager.cs delete mode 100644 Templates/BaseGame/game/core/sfx/audioAmbience.cs delete mode 100644 Templates/BaseGame/game/core/sfx/audioData.cs delete mode 100644 Templates/BaseGame/game/core/sfx/audioDescriptions.cs delete mode 100644 Templates/BaseGame/game/core/sfx/audioEnvironments.cs delete mode 100644 Templates/BaseGame/game/core/sfx/audioStates.cs delete mode 100644 Templates/BaseGame/game/core/shaders/VolumetricFog/VFogP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/VolumetricFog/VFogPreP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/VolumetricFog/VFogPreV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/VolumetricFog/VFogRefl.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/VolumetricFog/VFogV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/VolumetricFog/gl/VFogP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/VolumetricFog/gl/VFogPreP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/VolumetricFog/gl/VFogPreV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/VolumetricFog/gl/VFogRefl.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/VolumetricFog/gl/VFogV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/basicCloudsP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/basicCloudsV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/cloudLayerP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/cloudLayerV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/fixedFunction/addColorTextureP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/fixedFunction/addColorTextureV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/fixedFunction/colorP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/fixedFunction/colorV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/fixedFunction/gl/addColorTextureP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/fixedFunction/gl/addColorTextureV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/fixedFunction/gl/colorP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/fixedFunction/gl/colorV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/fixedFunction/gl/modColorTextureP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/fixedFunction/gl/modColorTextureV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/fixedFunction/gl/targetRestoreP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/fixedFunction/gl/targetRestoreV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/fixedFunction/gl/textureP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/fixedFunction/gl/textureV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/fixedFunction/modColorTextureP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/fixedFunction/modColorTextureV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/fixedFunction/targetRestoreP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/fixedFunction/targetRestoreV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/fixedFunction/textureP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/fixedFunction/textureV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/foliage.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/fxFoliageReplicatorP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/fxFoliageReplicatorV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/basicCloudsP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/basicCloudsV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/blurP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/blurV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/cloudLayerP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/cloudLayerV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/foliage.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/fxFoliageReplicatorP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/fxFoliageReplicatorV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/guiMaterialV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/hlslCompat.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/imposter.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/lighting.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/particleCompositeP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/particleCompositeV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/particlesP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/particlesV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/planarReflectBumpP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/planarReflectBumpV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/planarReflectP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/planarReflectV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/precipP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/precipV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/projectedShadowP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/projectedShadowV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/scatterSkyP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/scatterSkyV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/torque.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/wavesP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/gl/wind.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/guiMaterialV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/hlslStructs.h delete mode 100644 Templates/BaseGame/game/core/shaders/hlslStructs.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/imposter.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/advanced/convexGeometryV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/advanced/deferredClearGBufferP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/advanced/deferredClearGBufferV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/advanced/deferredColorShaderP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/advanced/deferredShadingP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/advanced/farFrustumQuad.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/advanced/farFrustumQuadV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/advanced/gl/convexGeometryV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/advanced/gl/deferredClearGBufferP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/advanced/gl/deferredColorShaderP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/advanced/gl/deferredShadingP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/advanced/gl/farFrustumQuad.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/advanced/gl/farFrustumQuadV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/advanced/gl/lightingUtils.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/advanced/gl/pointLightP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/advanced/gl/softShadow.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/advanced/gl/spotLightP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/advanced/gl/vectorLightP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/advanced/lightingUtils.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/advanced/particlePointLightP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/advanced/particlePointLightV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/advanced/pointLightP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/advanced/softShadow.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/advanced/spotLightP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/advanced/vectorLightP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/basic/gl/shadowFilterP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/basic/gl/shadowFilterV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/basic/shadowFilterP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/basic/shadowFilterV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/shadowMap/boxFilterP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/shadowMap/boxFilterV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/shadowMap/gl/boxFilterP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/shadowMap/gl/boxFilterV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/shadowMap/shadowMapIO.h delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/shadowMap/shadowMapIO_GLSL.h delete mode 100644 Templates/BaseGame/game/core/shaders/lighting/shadowMap/shadowMapIO_HLSL.h delete mode 100644 Templates/BaseGame/game/core/shaders/particleCompositeP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/particleCompositeV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/particlesP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/particlesV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/planarReflectBumpP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/planarReflectBumpV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/planarReflectP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/planarReflectV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/VolFogGlowP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/caustics/causticsP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/caustics/gl/causticsP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/chromaticLens.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/dof/DOF_CalcCoC_P.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/dof/DOF_CalcCoC_V.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/dof/DOF_DownSample_P.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/dof/DOF_DownSample_V.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/dof/DOF_Final_P.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/dof/DOF_Final_V.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/dof/DOF_Gausian_P.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/dof/DOF_Gausian_V.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/dof/DOF_Passthrough_V.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/dof/DOF_SmallBlur_P.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/dof/DOF_SmallBlur_V.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/dof/gl/DOF_CalcCoC_P.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/dof/gl/DOF_CalcCoC_V.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/dof/gl/DOF_DownSample_P.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/dof/gl/DOF_DownSample_V.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/dof/gl/DOF_Final_P.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/dof/gl/DOF_Final_V.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/dof/gl/DOF_Gausian_P.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/dof/gl/DOF_Gausian_V.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/dof/gl/DOF_Passthrough_V.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/dof/gl/DOF_SmallBlur_P.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/dof/gl/DOF_SmallBlur_V.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/edgeaa/dbgEdgeDisplayP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/edgeaa/edgeAAP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/edgeaa/edgeAAV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/edgeaa/edgeDetectP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/edgeaa/gl/dbgEdgeDisplayP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/edgeaa/gl/edgeAAP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/edgeaa/gl/edgeAAV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/edgeaa/gl/edgeDetectP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/flashP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/fogP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/fxaa/Fxaa3_11.h delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/fxaa/fxaaP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/fxaa/fxaaV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/fxaa/gl/fxaaP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/fxaa/gl/fxaaV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/gammaP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/gl/VolFogGlowP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/gl/chromaticLens.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/gl/flashP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/gl/fogP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/gl/gammaP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/gl/glowBlurP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/gl/glowBlurV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/gl/motionBlurP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/gl/passthruP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/gl/postFX.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/gl/postFxV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/gl/turbulenceP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/gl/underwaterFogP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/glowBlurP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/glowBlurV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/hdr/bloomGaussBlurHP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/hdr/bloomGaussBlurVP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/hdr/brightPassFilterP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/hdr/calculateAdaptedLumP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/hdr/downScale4x4P.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/hdr/downScale4x4V.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/hdr/finalPassCombineP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/hdr/gl/bloomGaussBlurHP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/hdr/gl/bloomGaussBlurVP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/hdr/gl/brightPassFilterP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/hdr/gl/calculateAdaptedLumP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/hdr/gl/downScale4x4P.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/hdr/gl/downScale4x4V.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/hdr/gl/finalPassCombineP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/hdr/gl/luminanceVisP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/hdr/gl/sampleLumInitialP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/hdr/gl/sampleLumIterativeP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/hdr/luminanceVisP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/hdr/sampleLumInitialP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/hdr/sampleLumIterativeP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/lightRay/gl/lightRayOccludeP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/lightRay/gl/lightRayP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/lightRay/lightRayOccludeP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/lightRay/lightRayP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/mlaa/blendWeightCalculationP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/mlaa/edgeDetectionP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/mlaa/functions.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/mlaa/gl/blendWeightCalculationP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/mlaa/gl/edgeDetectionP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/mlaa/gl/functions.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/mlaa/gl/neighborhoodBlendingP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/mlaa/gl/offsetV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/mlaa/gl/passthruV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/mlaa/neighborhoodBlendingP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/mlaa/offsetV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/mlaa/passthruV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/motionBlurP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/oculusvr/barrelDistortionChromaP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/oculusvr/barrelDistortionP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/oculusvr/gl/barrelDistortionChromaP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/oculusvr/gl/barrelDistortionP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/oculusvr/gl/monoToStereoP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/oculusvr/monoToStereoP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/passthruP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/postFx.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/postFxV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/postFxV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/ssao/SSAO_Blur_P.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/ssao/SSAO_Blur_V.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/ssao/SSAO_P.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/ssao/SSAO_PowerTable_P.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/ssao/SSAO_PowerTable_V.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/ssao/gl/SSAO_Blur_P.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/ssao/gl/SSAO_Blur_V.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/ssao/gl/SSAO_P.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/ssao/gl/SSAO_PowerTable_P.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/ssao/gl/SSAO_PowerTable_V.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/turbulenceP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/underwaterFogP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/vignette/VignetteP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/postFX/vignette/gl/VignetteP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/precipP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/precipV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/projectedShadowP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/projectedShadowV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/ribbons/basicRibbonShaderP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/ribbons/basicRibbonShaderV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/ribbons/gl/basicRibbonShaderP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/ribbons/gl/basicRibbonShaderV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/ribbons/gl/texRibbonShaderP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/ribbons/gl/texRibbonShaderV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/ribbons/texRibbonShaderP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/ribbons/texRibbonShaderV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/scatterSkyP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/scatterSkyV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/shaderModel.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/shaderModelAutoGen.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/shdrConsts.h delete mode 100644 Templates/BaseGame/game/core/shaders/terrain/blendP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/terrain/blendV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/terrain/gl/blendP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/terrain/gl/blendV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/terrain/terrain.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/terrain/terrain.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/torque.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/water/gl/waterBasicP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/water/gl/waterBasicV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/water/gl/waterP.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/water/gl/waterV.glsl delete mode 100644 Templates/BaseGame/game/core/shaders/water/waterBasicP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/water/waterBasicV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/water/waterP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/water/waterV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/wavesP.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/wavesV.hlsl delete mode 100644 Templates/BaseGame/game/core/shaders/wind.hlsl delete mode 100644 Templates/BaseGame/game/data/clientServer/ClientServer.cs delete mode 100644 Templates/BaseGame/game/data/clientServer/ClientServer.module delete mode 100644 Templates/BaseGame/game/data/clientServer/scripts/client/client.cs delete mode 100644 Templates/BaseGame/game/data/clientServer/scripts/client/connectionToServer.cs delete mode 100644 Templates/BaseGame/game/data/clientServer/scripts/client/levelDownload.cs delete mode 100644 Templates/BaseGame/game/data/clientServer/scripts/client/levelLoad.cs delete mode 100644 Templates/BaseGame/game/data/clientServer/scripts/client/message.cs delete mode 100644 Templates/BaseGame/game/data/clientServer/scripts/server/audio.cs delete mode 100644 Templates/BaseGame/game/data/clientServer/scripts/server/commands.cs delete mode 100644 Templates/BaseGame/game/data/clientServer/scripts/server/connectionToClient.cs delete mode 100644 Templates/BaseGame/game/data/clientServer/scripts/server/defaults.cs delete mode 100644 Templates/BaseGame/game/data/clientServer/scripts/server/kickban.cs delete mode 100644 Templates/BaseGame/game/data/clientServer/scripts/server/levelDownload.cs delete mode 100644 Templates/BaseGame/game/data/clientServer/scripts/server/levelInfo.cs delete mode 100644 Templates/BaseGame/game/data/clientServer/scripts/server/levelLoad.cs delete mode 100644 Templates/BaseGame/game/data/clientServer/scripts/server/message.cs delete mode 100644 Templates/BaseGame/game/data/clientServer/scripts/server/server.cs diff --git a/Templates/BaseGame/game/core/CoreComponents.cs b/Templates/BaseGame/game/core/CoreComponents.cs deleted file mode 100644 index 5bdca8cd3..000000000 --- a/Templates/BaseGame/game/core/CoreComponents.cs +++ /dev/null @@ -1,10 +0,0 @@ - -function CoreComponentsModule::onCreate(%this) -{ - %classList = enumerateConsoleClasses( "Component" ); - - foreach$( %componentClass in %classList ) - { - echo("Native Component of type: " @ %componentClass); - } -} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/CoreComponents.module b/Templates/BaseGame/game/core/CoreComponents.module deleted file mode 100644 index 0636e3bb5..000000000 --- a/Templates/BaseGame/game/core/CoreComponents.module +++ /dev/null @@ -1,19 +0,0 @@ - - - - \ No newline at end of file diff --git a/Templates/BaseGame/game/core/audio.cs b/Templates/BaseGame/game/core/audio.cs deleted file mode 100644 index a5932de8f..000000000 --- a/Templates/BaseGame/game/core/audio.cs +++ /dev/null @@ -1,436 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -// Source groups. -//----------------------------------------------------------------------------- - -singleton SFXDescription( AudioMaster ); -singleton SFXSource( AudioChannelMaster ) -{ - description = AudioMaster; -}; - -singleton SFXDescription( AudioChannel ) -{ - sourceGroup = AudioChannelMaster; -}; - -singleton SFXSource( AudioChannelDefault ) -{ - description = AudioChannel; -}; -singleton SFXSource( AudioChannelGui ) -{ - description = AudioChannel; -}; -singleton SFXSource( AudioChannelEffects ) -{ - description = AudioChannel; -}; -singleton SFXSource( AudioChannelMessages ) -{ - description = AudioChannel; -}; -singleton SFXSource( AudioChannelMusic ) -{ - description = AudioChannel; -}; - -// Set default playback states of the channels. - -AudioChannelMaster.play(); -AudioChannelDefault.play(); - -AudioChannelGui.play(); -AudioChannelMusic.play(); -AudioChannelMessages.play(); - -// Stop in-game effects channels. -AudioChannelEffects.stop(); - -//----------------------------------------------------------------------------- -// Master SFXDescriptions. -//----------------------------------------------------------------------------- - -// Master description for interface audio. -singleton SFXDescription( AudioGui ) -{ - volume = 1.0; - sourceGroup = AudioChannelGui; -}; - -// Master description for game effects audio. -singleton SFXDescription( AudioEffect ) -{ - volume = 1.0; - sourceGroup = AudioChannelEffects; -}; - -// Master description for audio in notifications. -singleton SFXDescription( AudioMessage ) -{ - volume = 1.0; - sourceGroup = AudioChannelMessages; -}; - -// Master description for music. -singleton SFXDescription( AudioMusic ) -{ - volume = 1.0; - sourceGroup = AudioChannelMusic; -}; - -//----------------------------------------------------------------------------- -// SFX Functions. -//----------------------------------------------------------------------------- - -/// This initializes the sound system device from -/// the defaults in the $pref::SFX:: globals. -function sfxStartup() -{ - echo( "\nsfxStartup..." ); - - // If we have a provider set, try initialize a device now. - - if( $pref::SFX::provider !$= "" ) - { - if( sfxInit() ) - return; - else - { - // Force auto-detection. - $pref::SFX::autoDetect = true; - } - } - - // If enabled autodetect a safe device. - - if( ( !isDefined( "$pref::SFX::autoDetect" ) || $pref::SFX::autoDetect ) && - sfxAutodetect() ) - return; - - // Failure. - - error( " Failed to initialize device!\n\n" ); - - $pref::SFX::provider = ""; - $pref::SFX::device = ""; - - return; -} - - -/// This initializes the sound system device from -/// the defaults in the $pref::SFX:: globals. -function sfxInit() -{ - // If already initialized, shut down the current device first. - - if( sfxGetDeviceInfo() !$= "" ) - sfxShutdown(); - - // Start it up! - %maxBuffers = $pref::SFX::useHardware ? -1 : $pref::SFX::maxSoftwareBuffers; - if ( !sfxCreateDevice( $pref::SFX::provider, $pref::SFX::device, $pref::SFX::useHardware, %maxBuffers ) ) - return false; - - // This returns a tab seperated string with - // the initialized system info. - %info = sfxGetDeviceInfo(); - $pref::SFX::provider = getField( %info, 0 ); - $pref::SFX::device = getField( %info, 1 ); - $pref::SFX::useHardware = getField( %info, 2 ); - %useHardware = $pref::SFX::useHardware ? "Yes" : "No"; - %maxBuffers = getField( %info, 3 ); - - echo( " Provider: " @ $pref::SFX::provider ); - echo( " Device: " @ $pref::SFX::device ); - echo( " Hardware: " @ %useHardware ); - echo( " Max Buffers: " @ %maxBuffers ); - echo( " " ); - - if( isDefined( "$pref::SFX::distanceModel" ) ) - sfxSetDistanceModel( $pref::SFX::distanceModel ); - if( isDefined( "$pref::SFX::dopplerFactor" ) ) - sfxSetDopplerFactor( $pref::SFX::dopplerFactor ); - if( isDefined( "$pref::SFX::rolloffFactor" ) ) - sfxSetRolloffFactor( $pref::SFX::rolloffFactor ); - - // Restore master volume. - - sfxSetMasterVolume( $pref::SFX::masterVolume ); - - // Restore channel volumes. - - for( %channel = 0; %channel <= 8; %channel ++ ) - sfxSetChannelVolume( %channel, $pref::SFX::channelVolume[ %channel ] ); - - return true; -} - - -/// Destroys the current sound system device. -function sfxShutdown() -{ - // Store volume prefs. - - $pref::SFX::masterVolume = sfxGetMasterVolume(); - - for( %channel = 0; %channel <= 8; %channel ++ ) - $pref::SFX::channelVolume[ %channel ] = sfxGetChannelVolume( %channel ); - - // We're assuming here that a null info - // string means that no device is loaded. - if( sfxGetDeviceInfo() $= "" ) - return; - - sfxDeleteDevice(); -} - - -/// Determines which of the two SFX providers is preferable. -function sfxCompareProvider( %providerA, %providerB ) -{ - if( %providerA $= %providerB ) - return 0; - - switch$( %providerA ) - { - // Always prefer FMOD over anything else. - case "FMOD": - return 1; - - // Prefer OpenAL over anything but FMOD. - case "OpenAL": - if( %providerB $= "FMOD" ) - return -1; - else - return 1; - - // choose XAudio over DirectSound - case "XAudio": - if( %providerB $= "FMOD" || %providerB $= "OpenAL" ) - return -1; - else - return 0; - - case "DirectSound": - if( %providerB !$= "FMOD" && %providerB !$= "OpenAL" && %providerB !$= "XAudio" ) - return 1; - else - return -1; - - default: - return -1; - } -} - - -/// Try to detect and initalize the best SFX device available. -function sfxAutodetect() -{ - // Get all the available devices. - - %devices = sfxGetAvailableDevices(); - - // Collect and sort the devices by preferentiality. - - %deviceTrySequence = new ArrayObject(); - %bestMatch = -1; - %count = getRecordCount( %devices ); - for( %i = 0; %i < %count; %i ++ ) - { - %info = getRecord( %devices, %i ); - %provider = getField( %info, 0 ); - - %deviceTrySequence.push_back( %provider, %info ); - } - - %deviceTrySequence.sortfkd( "sfxCompareProvider" ); - - // Try the devices in order. - - %count = %deviceTrySequence.count(); - for( %i = 0; %i < %count; %i ++ ) - { - %provider = %deviceTrySequence.getKey( %i ); - %info = %deviceTrySequence.getValue( %i ); - - $pref::SFX::provider = %provider; - $pref::SFX::device = getField( %info, 1 ); - $pref::SFX::useHardware = getField( %info, 2 ); - - // By default we've decided to avoid hardware devices as - // they are buggy and prone to problems. - $pref::SFX::useHardware = false; - - if( sfxInit() ) - { - $pref::SFX::autoDetect = false; - %deviceTrySequence.delete(); - return true; - } - } - - // Found no suitable device. - - error( "sfxAutodetect - Could not initialize a valid SFX device." ); - - $pref::SFX::provider = ""; - $pref::SFX::device = ""; - $pref::SFX::useHardware = ""; - - %deviceTrySequence.delete(); - - return false; -} - - -//----------------------------------------------------------------------------- -// Backwards-compatibility with old channel system. -//----------------------------------------------------------------------------- - -// Volume channel IDs for backwards-compatibility. - -$GuiAudioType = 1; // Interface. -$SimAudioType = 2; // Game. -$MessageAudioType = 3; // Notifications. -$MusicAudioType = 4; // Music. - -$AudioChannels[ 0 ] = AudioChannelDefault; -$AudioChannels[ $GuiAudioType ] = AudioChannelGui; -$AudioChannels[ $SimAudioType ] = AudioChannelEffects; -$AudioChannels[ $MessageAudioType ] = AudioChannelMessages; -$AudioChannels[ $MusicAudioType ] = AudioChannelMusic; - -function sfxOldChannelToGroup( %channel ) -{ - return $AudioChannels[ %channel ]; -} - -function sfxGroupToOldChannel( %group ) -{ - %id = %group.getId(); - for( %i = 0;; %i ++ ) - if( !isObject( $AudioChannels[ %i ] ) ) - return -1; - else if( $AudioChannels[ %i ].getId() == %id ) - return %i; - - return -1; -} - -function sfxSetMasterVolume( %volume ) -{ - AudioChannelMaster.setVolume( %volume ); -} - -function sfxGetMasterVolume( %volume ) -{ - return AudioChannelMaster.getVolume(); -} - -function sfxStopAll( %channel ) -{ - // Don't stop channel itself since that isn't quite what the function - // here intends. - - %channel = sfxOldChannelToGroup( %channel ); - if (isObject(%channel)) - { - foreach( %source in %channel ) - %source.stop(); - } -} - -function sfxGetChannelVolume( %channel ) -{ - %obj = sfxOldChannelToGroup( %channel ); - if( isObject( %obj ) ) - return %obj.getVolume(); -} - -function sfxSetChannelVolume( %channel, %volume ) -{ - %obj = sfxOldChannelToGroup( %channel ); - if( isObject( %obj ) ) - %obj.setVolume( %volume ); -} - -/*singleton SimSet( SFXPausedSet ); - - -/// Pauses the playback of active sound sources. -/// -/// @param %channels An optional word list of channel indices or an empty -/// string to pause sources on all channels. -/// @param %pauseSet An optional SimSet which is filled with the paused -/// sources. If not specified the global SfxSourceGroup -/// is used. -/// -/// @deprecated -/// -function sfxPause( %channels, %pauseSet ) -{ - // Did we get a set to populate? - if ( !isObject( %pauseSet ) ) - %pauseSet = SFXPausedSet; - - %count = SFXSourceSet.getCount(); - for ( %i = 0; %i < %count; %i++ ) - { - %source = SFXSourceSet.getObject( %i ); - - %channel = sfxGroupToOldChannel( %source.getGroup() ); - if( %channels $= "" || findWord( %channels, %channel ) != -1 ) - { - %source.pause(); - %pauseSet.add( %source ); - } - } -} - - -/// Resumes the playback of paused sound sources. -/// -/// @param %pauseSet An optional SimSet which contains the paused sound -/// sources to be resumed. If not specified the global -/// SfxSourceGroup is used. -/// @deprecated -/// -function sfxResume( %pauseSet ) -{ - if ( !isObject( %pauseSet ) ) - %pauseSet = SFXPausedSet; - - %count = %pauseSet.getCount(); - for ( %i = 0; %i < %count; %i++ ) - { - %source = %pauseSet.getObject( %i ); - %source.play(); - } - - // Clear our pause set... the caller is left - // to clear his own if he passed one. - %pauseSet.clear(); -}*/ diff --git a/Templates/BaseGame/game/core/canvas.cs b/Templates/BaseGame/game/core/canvas.cs deleted file mode 100644 index b38cdccca..000000000 --- a/Templates/BaseGame/game/core/canvas.cs +++ /dev/null @@ -1,162 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//----------------------------------------------------------------------------- - -function createCanvas(%windowTitle) -{ - if ($isDedicated) - { - GFXInit::createNullDevice(); - return true; - } - - // Create the Canvas - $GameCanvas = new GuiCanvas(Canvas) - { - displayWindow = $platform !$= "windows"; - }; - - // Set the window title - if (isObject(Canvas)) - { - Canvas.setWindowTitle(%windowTitle @ " - " @ $pref::Video::displayDevice); - configureCanvas(); - } - else - { - error("Canvas creation failed. Shutting down."); - quit(); - } -} - -// Constants for referencing video resolution preferences -$WORD::RES_X = 0; -$WORD::RES_Y = 1; -$WORD::FULLSCREEN = 2; -$WORD::BITDEPTH = 3; -$WORD::REFRESH = 4; -$WORD::AA = 5; - -function configureCanvas() -{ - // Setup a good default if we don't have one already. - if ($pref::Video::Resolution $= "") - $pref::Video::Resolution = "800 600"; - if ($pref::Video::FullScreen $= "") - $pref::Video::FullScreen = false; - if ($pref::Video::BitDepth $= "") - $pref::Video::BitDepth = "32"; - if ($pref::Video::RefreshRate $= "") - $pref::Video::RefreshRate = "60"; - if ($pref::Video::AA $= "") - $pref::Video::AA = "4"; - - %resX = $pref::Video::Resolution.x; - %resY = $pref::Video::Resolution.y; - %fs = $pref::Video::FullScreen; - %bpp = $pref::Video::BitDepth; - %rate = $pref::Video::RefreshRate; - %aa = $pref::Video::AA; - - if($cliFullscreen !$= "") { - %fs = $cliFullscreen; - $cliFullscreen = ""; - } - - echo("--------------"); - echo("Attempting to set resolution to \"" @ %resX SPC %resY SPC %fs SPC %bpp SPC %rate SPC %aa @ "\""); - - %deskRes = getDesktopResolution(); - %deskResX = getWord(%deskRes, $WORD::RES_X); - %deskResY = getWord(%deskRes, $WORD::RES_Y); - %deskResBPP = getWord(%deskRes, 2); - - // We shouldn't be getting this any more but just in case... - if (%bpp $= "Default") - %bpp = %deskResBPP; - - // Make sure we are running at a valid resolution - if (%fs $= "0" || %fs $= "false") - { - // Windowed mode has to use the same bit depth as the desktop - %bpp = %deskResBPP; - - // Windowed mode also has to run at a smaller resolution than the desktop - if ((%resX >= %deskResX) || (%resY >= %deskResY)) - { - warn("Warning: The requested windowed resolution is equal to or larger than the current desktop resolution. Attempting to find a better resolution"); - - %resCount = Canvas.getModeCount(); - for (%i = (%resCount - 1); %i >= 0; %i--) - { - %testRes = Canvas.getMode(%i); - %testResX = getWord(%testRes, $WORD::RES_X); - %testResY = getWord(%testRes, $WORD::RES_Y); - %testBPP = getWord(%testRes, $WORD::BITDEPTH); - - if (%testBPP != %bpp) - continue; - - if ((%testResX < %deskResX) && (%testResY < %deskResY)) - { - // This will work as our new resolution - %resX = %testResX; - %resY = %testResY; - - warn("Warning: Switching to \"" @ %resX SPC %resY SPC %bpp @ "\""); - - break; - } - } - } - } - - $pref::Video::Resolution = %resX SPC %resY; - $pref::Video::FullScreen = %fs; - $pref::Video::BitDepth = %bpp; - $pref::Video::RefreshRate = %rate; - $pref::Video::AA = %aa; - - if (%fs == 1 || %fs $= "true") - %fsLabel = "Yes"; - else - %fsLabel = "No"; - - echo("Accepted Mode: " NL - "--Resolution : " @ %resX SPC %resY NL - "--Full Screen : " @ %fsLabel NL - "--Bits Per Pixel : " @ %bpp NL - "--Refresh Rate : " @ %rate NL - "--AA TypeXLevel : " @ %aa NL - "--------------"); - - // Actually set the new video mode - Canvas.setVideoMode(%resX, %resY, %fs, %bpp, %rate, %aa); - - commandToServer('setClientAspectRatio', %resX, %resY); - - // AA piggybacks on the AA setting in $pref::Video::mode. - // We need to parse the setting between AA modes, and then it's level - // It's formatted as AATypexAALevel - // So, FXAAx4 or MLAAx2 - if ( isObject( FXAA_PostEffect ) ) - FXAA_PostEffect.isEnabled = ( %aa > 0 ) ? true : false; -} diff --git a/Templates/BaseGame/game/core/components/RigidBodyComponent.asset.taml b/Templates/BaseGame/game/core/components/RigidBodyComponent.asset.taml deleted file mode 100644 index 8e60db364..000000000 --- a/Templates/BaseGame/game/core/components/RigidBodyComponent.asset.taml +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/Templates/BaseGame/game/core/components/animationComponent.asset.taml b/Templates/BaseGame/game/core/components/animationComponent.asset.taml deleted file mode 100644 index 771d38e02..000000000 --- a/Templates/BaseGame/game/core/components/animationComponent.asset.taml +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/Templates/BaseGame/game/core/components/cameraOrbiterComponent.asset.taml b/Templates/BaseGame/game/core/components/cameraOrbiterComponent.asset.taml deleted file mode 100644 index b615f2348..000000000 --- a/Templates/BaseGame/game/core/components/cameraOrbiterComponent.asset.taml +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/Templates/BaseGame/game/core/components/collisionComponent.asset.taml b/Templates/BaseGame/game/core/components/collisionComponent.asset.taml deleted file mode 100644 index 1a4f99a0d..000000000 --- a/Templates/BaseGame/game/core/components/collisionComponent.asset.taml +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/Templates/BaseGame/game/core/components/game/camera.asset.taml b/Templates/BaseGame/game/core/components/game/camera.asset.taml deleted file mode 100644 index f59e429e2..000000000 --- a/Templates/BaseGame/game/core/components/game/camera.asset.taml +++ /dev/null @@ -1,9 +0,0 @@ - diff --git a/Templates/BaseGame/game/core/components/game/camera.cs b/Templates/BaseGame/game/core/components/game/camera.cs deleted file mode 100644 index b6f510c9d..000000000 --- a/Templates/BaseGame/game/core/components/game/camera.cs +++ /dev/null @@ -1,185 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//----------------------------------------------------------------------------- - -function CameraComponent::onAdd(%this) -{ - %this.addComponentField(clientOwner, "The client that views this camera", "int", "1", ""); - - %test = %this.clientOwner; - - %barf = ClientGroup.getCount(); - - %clientID = %this.getClientID(); - if(%clientID && !isObject(%clientID.camera)) - { - %this.scopeToClient(%clientID); - %this.setDirty(); - - %clientID.setCameraObject(%this.owner); - %clientID.setControlCameraFov(%this.FOV); - - %clientID.camera = %this.owner; - } - - %res = $pref::Video::mode; - %derp = 0; -} - -function CameraComponent::onRemove(%this) -{ - %clientID = %this.getClientID(); - if(%clientID) - %clientID.clearCameraObject(); -} - -function CameraComponent::onInspectorUpdate(%this) -{ - //if(%this.clientOwner) - //%this.clientOwner.setCameraObject(%this.owner); -} - -function CameraComponent::getClientID(%this) -{ - return ClientGroup.getObject(%this.clientOwner-1); -} - -function CameraComponent::isClientCamera(%this, %client) -{ - %clientID = ClientGroup.getObject(%this.clientOwner-1); - - if(%client.getID() == %clientID) - return true; - else - return false; -} - -function CameraComponent::onClientConnect(%this, %client) -{ - //if(%this.isClientCamera(%client) && !isObject(%client.camera)) - //{ - %this.scopeToClient(%client); - %this.setDirty(); - - %client.setCameraObject(%this.owner); - %client.setControlCameraFov(%this.FOV); - - %client.camera = %this.owner; - //} - //else - //{ - // echo("CONNECTED CLIENT IS NOT CAMERA OWNER!"); - //} -} - -function CameraComponent::onClientDisconnect(%this, %client) -{ - Parent::onClientDisconnect(%this, %client); - - if(isClientCamera(%client)){ - %this.clearScopeToClient(%client); - %client.clearCameraObject(); - } -} - -/// -/// -/// - -function VRCameraComponent::onAdd(%this) -{ - %this.addComponentField(clientOwner, "The client that views this camera", "int", "1", ""); - - %test = %this.clientOwner; - - %barf = ClientGroup.getCount(); - - %clientID = %this.getClientID(); - if(%clientID && !isObject(%clientID.camera)) - { - %this.scopeToClient(%clientID); - %this.setDirty(); - - %clientID.setCameraObject(%this.owner); - %clientID.setControlCameraFov(%this.FOV); - - %clientID.camera = %this.owner; - } - - %res = $pref::Video::mode; - %derp = 0; -} - -function VRCameraComponent::onRemove(%this) -{ - %clientID = %this.getClientID(); - if(%clientID) - %clientID.clearCameraObject(); -} - -function CameraComponent::onInspectorUpdate(%this) -{ - //if(%this.clientOwner) - //%this.clientOwner.setCameraObject(%this.owner); -} - -function VRCameraComponent::getClientID(%this) -{ - return ClientGroup.getObject(%this.clientOwner-1); -} - -function VRCameraComponent::isClientCamera(%this, %client) -{ - %clientID = ClientGroup.getObject(%this.clientOwner-1); - - if(%client.getID() == %clientID) - return true; - else - return false; -} - -function VRCameraComponent::onClientConnect(%this, %client) -{ - //if(%this.isClientCamera(%client) && !isObject(%client.camera)) - //{ - %this.scopeToClient(%client); - %this.setDirty(); - - %client.setCameraObject(%this.owner); - %client.setControlCameraFov(%this.FOV); - - %client.camera = %this.owner; - //} - //else - //{ - // echo("CONNECTED CLIENT IS NOT CAMERA OWNER!"); - //} -} - -function VRCameraComponent::onClientDisconnect(%this, %client) -{ - Parent::onClientDisconnect(%this, %client); - - if(isClientCamera(%client)){ - %this.clearScopeToClient(%client); - %client.clearCameraObject(); - } -} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/components/game/controlObject.asset.taml b/Templates/BaseGame/game/core/components/game/controlObject.asset.taml deleted file mode 100644 index 19515e833..000000000 --- a/Templates/BaseGame/game/core/components/game/controlObject.asset.taml +++ /dev/null @@ -1,10 +0,0 @@ - diff --git a/Templates/BaseGame/game/core/components/game/controlObject.cs b/Templates/BaseGame/game/core/components/game/controlObject.cs deleted file mode 100644 index 7f477ecca..000000000 --- a/Templates/BaseGame/game/core/components/game/controlObject.cs +++ /dev/null @@ -1,89 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//----------------------------------------------------------------------------- - -//registerComponent("ControlObjectComponent", "Component", "Control Object", "Game", false, "Allows the behavior owner to operate as a camera."); - -function ControlObjectComponent::onAdd(%this) -{ - %this.addComponentField(clientOwner, "The shape to use for rendering", "int", "1", ""); - - %clientID = %this.getClientID(); - - if(%clientID && !isObject(%clientID.getControlObject())) - %clientID.setControlObject(%this.owner); -} - -function ControlObjectComponent::onRemove(%this) -{ - %clientID = %this.getClientID(); - - if(%clientID) - %clientID.setControlObject(0); -} - -function ControlObjectComponent::onClientConnect(%this, %client) -{ - if(%this.isControlClient(%client) && !isObject(%client.getControlObject())) - %client.setControlObject(%this.owner); -} - -function ControlObjectComponent::onClientDisconnect(%this, %client) -{ - if(%this.isControlClient(%client)) - %client.setControlObject(0); -} - -function ControlObjectComponent::getClientID(%this) -{ - return ClientGroup.getObject(%this.clientOwner-1); -} - -function ControlObjectComponent::isControlClient(%this, %client) -{ - %clientID = ClientGroup.getObject(%this.clientOwner-1); - - if(%client.getID() == %clientID) - return true; - else - return false; -} - -function ControlObjectComponent::onInspectorUpdate(%this, %field) -{ - %clientID = %this.getClientID(); - - if(%clientID && !isObject(%clientID.getControlObject())) - %clientID.setControlObject(%this.owner); -} - -function switchControlObject(%client, %newControlEntity) -{ - if(!isObject(%client) || !isObject(%newControlEntity)) - return error("SwitchControlObject: No client or target controller!"); - - %control = %newControlEntity.getComponent(ControlObjectComponent); - - if(!isObject(%control)) - return error("SwitchControlObject: Target controller has no conrol object behavior!"); - - %client.setControlObject(%newControlEntity); -} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/components/game/itemRotate.asset.taml b/Templates/BaseGame/game/core/components/game/itemRotate.asset.taml deleted file mode 100644 index 4c0c1bec4..000000000 --- a/Templates/BaseGame/game/core/components/game/itemRotate.asset.taml +++ /dev/null @@ -1,10 +0,0 @@ - diff --git a/Templates/BaseGame/game/core/components/game/itemRotate.cs b/Templates/BaseGame/game/core/components/game/itemRotate.cs deleted file mode 100644 index 947d19214..000000000 --- a/Templates/BaseGame/game/core/components/game/itemRotate.cs +++ /dev/null @@ -1,49 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//----------------------------------------------------------------------------- - -//registerComponent("ItemRotationComponent", "Component", "Item Rotation", "Game", false, "Rotates the entity around the z axis, like an item pickup."); - -function ItemRotationComponent::onAdd(%this) -{ - %this.addComponentField(rotationsPerMinute, "Number of rotations per minute", "float", "5", ""); - %this.addComponentField(forward, "Rotate forward or backwards", "bool", "1", ""); - %this.addComponentField(horizontal, "Rotate horizontal or verticle, true for horizontal", "bool", "1", ""); -} - -function ItemRotationComponent::Update(%this) -{ - %tickRate = 0.032; - - //Rotations per second is calculated based on a standard update tick being 32ms. So we scale by the tick speed, then add that to our rotation to - //get a nice rotation speed. - if(%this.horizontal) - { - if(%this.forward) - %this.owner.rotation.z += ( ( 360 * %this.rotationsPerMinute ) / 60 ) * %tickRate; - else - %this.owner.rotation.z -= ( ( 360 * %this.rotationsPerMinute ) / 60 ) * %tickRate; - } - else - { - %this.owner.rotation.x += ( ( 360 * %this.rotationsPerMinute ) / 60 ) * %tickRate; - } -} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/components/game/playerSpawner.asset.taml b/Templates/BaseGame/game/core/components/game/playerSpawner.asset.taml deleted file mode 100644 index 8a597aca4..000000000 --- a/Templates/BaseGame/game/core/components/game/playerSpawner.asset.taml +++ /dev/null @@ -1,10 +0,0 @@ - diff --git a/Templates/BaseGame/game/core/components/game/playerSpawner.cs b/Templates/BaseGame/game/core/components/game/playerSpawner.cs deleted file mode 100644 index a7387eaf1..000000000 --- a/Templates/BaseGame/game/core/components/game/playerSpawner.cs +++ /dev/null @@ -1,78 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//----------------------------------------------------------------------------- - -//registerComponent("PlayerSpawner", "Component", -// "Player Spawner", "Game", false, "When a client connects, it spawns a player object for them and attaches them to it"); - -function PlayerSpawner::onAdd(%this) -{ - %this.clientCount = 1; - %this.friendlyName = "Player Spawner"; - %this.componentType = "Spawner"; - - %this.addComponentField("GameObjectName", "The name of the game object we spawn for the players", "gameObject", "PlayerObject"); -} - -function PlayerSpawner::onClientConnect(%this, %client) -{ - %playerObj = spawnGameObject(%this.GameObjectName, false); - - if(!isObject(%playerObj)) - return; - - %playerObj.position = %this.owner.position; - - %playerObj.notify("onClientConnect", %client); - - switchControlObject(%client, %playerObj); - switchCamera(%client, %playerObj); - - %client.player = %playerObj; - %client.camera = %playerObj; - - %inventory = %playerObj.getComponent(InventoryController); - - if(isObject(%inventory)) - { - for(%i=0; %i<5; %i++) - { - %arrow = spawnGameObject(ArrowProjectile, false); - - %inventory.addItem(%arrow); - } - } - - %playerObj.position = %this.owner.position; - %playerObj.rotation = "0 0 0"; - - %this.clientCount++; -} - -function PlayerSpawner::onClientDisConnect(%this, %client) -{ - -} - -function PlayerSpawner::getClientID(%this) -{ - return ClientGroup.getObject(%this.clientOwner-1); -} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/components/input/fpsControls.asset.taml b/Templates/BaseGame/game/core/components/input/fpsControls.asset.taml deleted file mode 100644 index cd0440055..000000000 --- a/Templates/BaseGame/game/core/components/input/fpsControls.asset.taml +++ /dev/null @@ -1,9 +0,0 @@ - diff --git a/Templates/BaseGame/game/core/components/input/fpsControls.cs b/Templates/BaseGame/game/core/components/input/fpsControls.cs deleted file mode 100644 index 8331e409d..000000000 --- a/Templates/BaseGame/game/core/components/input/fpsControls.cs +++ /dev/null @@ -1,247 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//----------------------------------------------------------------------------- - -//registerComponent("FPSControls", "Component", "FPS Controls", "Input", false, "First Person Shooter-type controls"); - -function FPSControls::onAdd(%this) -{ - // - %this.beginGroup("Keys"); - %this.addComponentField(forwardKey, "Key to bind to vertical thrust", keybind, "keyboard w"); - %this.addComponentField(backKey, "Key to bind to vertical thrust", keybind, "keyboard s"); - %this.addComponentField(leftKey, "Key to bind to horizontal thrust", keybind, "keyboard a"); - %this.addComponentField(rightKey, "Key to bind to horizontal thrust", keybind, "keyboard d"); - - %this.addComponentField(jump, "Key to bind to horizontal thrust", keybind, "keyboard space"); - %this.endGroup(); - - %this.beginGroup("Mouse"); - %this.addComponentField(pitchAxis, "Key to bind to horizontal thrust", keybind, "mouse yaxis"); - %this.addComponentField(yawAxis, "Key to bind to horizontal thrust", keybind, "mouse xaxis"); - %this.endGroup(); - - %this.addComponentField(moveSpeed, "Horizontal thrust force", float, 300.0); - %this.addComponentField(jumpStrength, "Vertical thrust force", float, 3.0); - // - - %control = %this.owner.getComponent( ControlObjectComponent ); - if(!%control) - return echo("SPECTATOR CONTROLS: No Control Object behavior!"); - - //%this.Physics = %this.owner.getComponent( PlayerPhysicsComponent ); - - //%this.Animation = %this.owner.getComponent( AnimationComponent ); - - //%this.Camera = %this.owner.getComponent( MountedCameraComponent ); - - //%this.Animation.playThread(0, "look"); - - %this.setupControls(%control.getClientID()); -} - -function FPSControls::onRemove(%this) -{ - Parent::onBehaviorRemove(%this); - - commandToClient(%control.clientOwnerID, 'removeInput', %this.forwardKey); - commandToClient(%control.clientOwnerID, 'removeInput', %this.backKey); - commandToClient(%control.clientOwnerID, 'removeInput', %this.leftKey); - commandToClient(%control.clientOwnerID, 'removeInput', %this.rightKey); - - commandToClient(%control.clientOwnerID, 'removeInput', %this.pitchAxis); - commandToClient(%control.clientOwnerID, 'removeInput', %this.yawAxis); -} - -function FPSControls::onBehaviorFieldUpdate(%this, %field) -{ - %controller = %this.owner.getBehavior( ControlObjectBehavior ); - commandToClient(%controller.clientOwnerID, 'updateInput', %this.getFieldValue(%field), %field); -} - -function FPSControls::onClientConnect(%this, %client) -{ - %this.setupControls(%client); -} - - -function FPSControls::setupControls(%this, %client) -{ - %control = %this.owner.getComponent( ControlObjectComponent ); - if(!%control.isControlClient(%client)) - { - echo("FPS CONTROLS: Client Did Not Match"); - return; - } - - %inputCommand = "FPSControls"; - - %test = %this.forwardKey; - - /*SetInput(%client, %this.forwardKey.x, %this.forwardKey.y, %inputCommand@"_forwardKey"); - SetInput(%client, %this.backKey.x, %this.backKey.y, %inputCommand@"_backKey"); - SetInput(%client, %this.leftKey.x, %this.leftKey.y, %inputCommand@"_leftKey"); - SetInput(%client, %this.rightKey.x, %this.rightKey.y, %inputCommand@"_rightKey"); - - SetInput(%client, %this.jump.x, %this.jump.y, %inputCommand@"_jump"); - - SetInput(%client, %this.pitchAxis.x, %this.pitchAxis.y, %inputCommand@"_pitchAxis"); - SetInput(%client, %this.yawAxis.x, %this.yawAxis.y, %inputCommand@"_yawAxis");*/ - - SetInput(%client, "keyboard", "w", %inputCommand@"_forwardKey"); - SetInput(%client, "keyboard", "s", %inputCommand@"_backKey"); - SetInput(%client, "keyboard", "a", %inputCommand@"_leftKey"); - SetInput(%client, "keyboard", "d", %inputCommand@"_rightKey"); - - SetInput(%client, "keyboard", "space", %inputCommand@"_jump"); - - SetInput(%client, "mouse", "yaxis", %inputCommand@"_pitchAxis"); - SetInput(%client, "mouse", "xaxis", %inputCommand@"_yawAxis"); - - SetInput(%client, "keyboard", "f", %inputCommand@"_flashlight"); - -} - -function FPSControls::onMoveTrigger(%this, %triggerID) -{ - //check if our jump trigger was pressed! - if(%triggerID == 2) - { - %this.owner.applyImpulse("0 0 0", "0 0 " @ %this.jumpStrength); - } -} - -function FPSControls::Update(%this) -{ - return; - - %moveVector = %this.owner.getMoveVector(); - %moveRotation = %this.owner.getMoveRotation(); - - %this.Physics.moveVector = "0 0 0"; - - if(%moveVector.x != 0) - { - %fv = VectorNormalize(%this.owner.getRightVector()); - - %forMove = VectorScale(%fv, (%moveVector.x));// * (%this.moveSpeed * 0.032))); - - //%this.Physics.velocity = VectorAdd(%this.Physics.velocity, %forMove); - - %this.Physics.moveVector = VectorAdd(%this.Physics.moveVector, %forMove); - - //if(%forMove > 0) - // %this.Animation.playThread(1, "run"); - } - /*else - { - %fv = VectorNormalize(%this.owner.getRightVector()); - - %forMove = VectorScale(%fv, (%moveVector.x * (%this.moveSpeed * 0.032))); - - if(%forMove <= 0) - %this.Animation.stopThread(1); - - }*/ - - if(%moveVector.y != 0) - { - %fv = VectorNormalize(%this.owner.getForwardVector()); - - %forMove = VectorScale(%fv, (%moveVector.y));// * (%this.moveSpeed * 0.032))); - - //%this.Physics.velocity = VectorAdd(%this.Physics.velocity, %forMove); - - %this.Physics.moveVector = VectorAdd(%this.Physics.moveVector, %forMove); - - //if(VectorLen(%this.Physics.velocity) < 2) - // %this.Physics.velocity = VectorAdd(%this.Physics.velocity, %forMove); - } - - /*if(%moveVector.z) - { - %fv = VectorNormalize(%this.owner.getUpVector()); - - %forMove = VectorScale(%fv, (%moveVector.z * (%this.moveSpeed * 0.032))); - - %this.Physics.velocity = VectorAdd(%this.Physics.velocity, %forMove); - }*/ - - if(%moveRotation.x != 0) - { - %look = mRadToDeg(%moveRotation.x) / 180; - - //%this.Animation.setThreadPos(0, %look); - - %this.owner.getComponent( MountedCameraComponent ).rotationOffset.x += mRadToDeg(%moveRotation.x); - - //%this.Camera.rotationOffset.x += mRadToDeg(%moveRotation.x); - } - // %this.owner.rotation.x += mRadToDeg(%moveRotation.x); - - if(%moveRotation.z != 0) - { - %zrot = mRadToDeg(%moveRotation.z); - %this.owner.getComponent( MountedCameraComponent ).rotationOffset.z += %zrot; - //%this.owner.rotation.z += %zrot; - } -} - -// -function FPSControls_forwardKey(%val) -{ - $mvForwardAction = %val; -} - -function FPSControls_backKey(%val) -{ - $mvBackwardAction = %val; -} - -function FPSControls_leftKey(%val) -{ - $mvLeftAction = %val; -} - -function FPSControls_rightKey(%val) -{ - $mvRightAction = %val; -} - -function FPSControls_yawAxis(%val) -{ - $mvYaw += getMouseAdjustAmount(%val); -} - -function FPSControls_pitchAxis(%val) -{ - $mvPitch += getMouseAdjustAmount(%val); -} - -function FPSControls_jump(%val) -{ - $mvTriggerCount2++; -} - -function FPSControls_flashLight(%val) -{ - $mvTriggerCount3++; -} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/components/input/inputManager.cs b/Templates/BaseGame/game/core/components/input/inputManager.cs deleted file mode 100644 index c8123d1e3..000000000 --- a/Templates/BaseGame/game/core/components/input/inputManager.cs +++ /dev/null @@ -1,82 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//----------------------------------------------------------------------------- - -function SetInput(%client, %device, %key, %command, %bindMap, %behav) -{ - commandToClient(%client, 'SetInput', %device, %key, %command, %bindMap, %behav); -} - -function RemoveInput(%client, %device, %key, %command, %bindMap) -{ - commandToClient(%client, 'removeInput', %device, %key, %command, %bindMap); -} - -function clientCmdSetInput(%device, %key, %command, %bindMap, %behav) -{ - //if we're requesting a custom bind map, set that up - if(%bindMap $= "") - %bindMap = moveMap; - - if (!isObject(%bindMap)){ - new ActionMap(moveMap); - moveMap.push(); - } - - //get our local - //%localID = ServerConnection.resolveGhostID(%behav); - - //%tmpl = %localID.getTemplate(); - //%tmpl.insantiateNamespace(%tmpl.getName()); - - //first, check if we have an existing command - %oldBind = %bindMap.getBinding(%command); - if(%oldBind !$= "") - %bindMap.unbind(getField(%oldBind, 0), getField(%oldBind, 1)); - - //now, set the requested bind - %bindMap.bind(%device, %key, %command); -} - -function clientCmdRemoveSpecCtrlInput(%device, %key, %bindMap) -{ - //if we're requesting a custom bind map, set that up - if(%bindMap $= "") - %bindMap = moveMap; - - if (!isObject(%bindMap)) - return; - - %bindMap.unbind(%device, %key); -} - -function clientCmdSetupClientBehavior(%bhvrGstID) -{ - %localID = ServerConnection.resolveGhostID(%bhvrGstID); - %tmpl = %localID.getTemplate(); - %tmpl.insantiateNamespace(%tmpl.getName()); -} - -function getMouseAdjustAmount(%val) -{ - // based on a default camera FOV of 90' - return(%val * ($cameraFov / 90) * 0.01) * $pref::Input::LinkMouseSensitivity; -} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/components/meshComponent.asset.taml b/Templates/BaseGame/game/core/components/meshComponent.asset.taml deleted file mode 100644 index b41de171a..000000000 --- a/Templates/BaseGame/game/core/components/meshComponent.asset.taml +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/Templates/BaseGame/game/core/components/playerControllerComponent.asset.taml b/Templates/BaseGame/game/core/components/playerControllerComponent.asset.taml deleted file mode 100644 index 417f409e0..000000000 --- a/Templates/BaseGame/game/core/components/playerControllerComponent.asset.taml +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/Templates/BaseGame/game/core/components/soundComponent.asset.taml b/Templates/BaseGame/game/core/components/soundComponent.asset.taml deleted file mode 100644 index a29bcc9ff..000000000 --- a/Templates/BaseGame/game/core/components/soundComponent.asset.taml +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/Templates/BaseGame/game/core/components/stateMachineComponent.asset.taml b/Templates/BaseGame/game/core/components/stateMachineComponent.asset.taml deleted file mode 100644 index ff1d53cd8..000000000 --- a/Templates/BaseGame/game/core/components/stateMachineComponent.asset.taml +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/Templates/BaseGame/game/core/console/console.gui b/Templates/BaseGame/game/core/console/console.gui deleted file mode 100644 index c2f21eba9..000000000 --- a/Templates/BaseGame/game/core/console/console.gui +++ /dev/null @@ -1,191 +0,0 @@ -//--- OBJECT WRITE BEGIN --- -%guiContent = new GuiControl(ConsoleDlg) { - position = "0 0"; - extent = "1024 768"; - minExtent = "8 8"; - horizSizing = "right"; - vertSizing = "bottom"; - profile = "GuiDefaultProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "1"; - canSave = "1"; - canSaveDynamicFields = "1"; - helpTag = "0"; - - new GuiConsoleEditCtrl(ConsoleEntry) { - useSiblingScroller = "1"; - historySize = "40"; - tabComplete = "0"; - sinkAllKeyEvents = "1"; - password = "0"; - passwordMask = "*"; - maxLength = "255"; - margin = "0 0 0 0"; - padding = "0 0 0 0"; - anchorTop = "1"; - anchorBottom = "0"; - anchorLeft = "1"; - anchorRight = "0"; - position = "0 750"; - extent = "1024 18"; - minExtent = "8 8"; - horizSizing = "width"; - vertSizing = "top"; - profile = "ConsoleTextEditProfile"; - visible = "1"; - active = "1"; - altCommand = "ConsoleEntry::eval();"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "1"; - canSave = "1"; - canSaveDynamicFields = "0"; - }; - new GuiContainer() { - margin = "0 0 0 0"; - padding = "0 0 0 0"; - anchorTop = "1"; - anchorBottom = "0"; - anchorLeft = "1"; - anchorRight = "0"; - position = "1 728"; - extent = "1024 22"; - minExtent = "8 2"; - horizSizing = "width"; - vertSizing = "top"; - profile = "GuiDefaultProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "1"; - canSave = "1"; - canSaveDynamicFields = "0"; - - new GuiBitmapCtrl() { - bitmap = "data/ui/art/hudfill.png"; - color = "255 255 255 255"; - wrap = "0"; - position = "0 0"; - extent = "1024 22"; - minExtent = "8 2"; - horizSizing = "width"; - vertSizing = "bottom"; - profile = "GuiDefaultProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "0"; - canSave = "1"; - canSaveDynamicFields = "0"; - }; - new GuiCheckBoxCtrl(ConsoleDlgErrorFilterBtn) { - text = "Errors"; - groupNum = "-1"; - buttonType = "ToggleButton"; - useMouseEvents = "0"; - position = "2 2"; - extent = "113 20"; - minExtent = "8 2"; - horizSizing = "right"; - vertSizing = "bottom"; - profile = "GuiCheckBoxProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "0"; - canSave = "1"; - canSaveDynamicFields = "0"; - }; - new GuiCheckBoxCtrl(ConsoleDlgWarnFilterBtn) { - text = "Warnings"; - groupNum = "-1"; - buttonType = "ToggleButton"; - useMouseEvents = "0"; - position = "119 2"; - extent = "113 20"; - minExtent = "8 2"; - horizSizing = "right"; - vertSizing = "bottom"; - profile = "GuiCheckBoxProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "0"; - canSave = "1"; - canSaveDynamicFields = "0"; - }; - new GuiCheckBoxCtrl(ConsoleDlgNormalFilterBtn) { - text = "Normal Messages"; - groupNum = "-1"; - buttonType = "ToggleButton"; - useMouseEvents = "0"; - position = "236 2"; - extent = "113 20"; - minExtent = "8 2"; - horizSizing = "right"; - vertSizing = "bottom"; - profile = "GuiCheckBoxProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "0"; - canSave = "1"; - canSaveDynamicFields = "0"; - }; - }; - new GuiScrollCtrl() { - willFirstRespond = "1"; - hScrollBar = "alwaysOn"; - vScrollBar = "alwaysOn"; - lockHorizScroll = "0"; - lockVertScroll = "0"; - constantThumbHeight = "0"; - childMargin = "0 0"; - mouseWheelScrollSpeed = "-1"; - margin = "0 0 0 0"; - padding = "0 0 0 0"; - anchorTop = "1"; - anchorBottom = "0"; - anchorLeft = "1"; - anchorRight = "0"; - position = "0 0"; - extent = "1024 730"; - minExtent = "8 8"; - horizSizing = "width"; - vertSizing = "height"; - profile = "ConsoleScrollProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "1"; - internalName = "Scroll"; - canSave = "1"; - canSaveDynamicFields = "0"; - - new GuiConsole(ConsoleMessageLogView) { - position = "1 1"; - extent = "622 324"; - minExtent = "8 2"; - horizSizing = "right"; - vertSizing = "bottom"; - profile = "GuiConsoleProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "1"; - canSave = "1"; - canSaveDynamicFields = "0"; - }; - }; -}; -//--- OBJECT WRITE END --- \ No newline at end of file diff --git a/Templates/BaseGame/game/core/console/main.cs b/Templates/BaseGame/game/core/console/main.cs deleted file mode 100644 index 3d89234b8..000000000 --- a/Templates/BaseGame/game/core/console/main.cs +++ /dev/null @@ -1,140 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//----------------------------------------------------------------------------- - -exec("./profiles.cs"); -exec("./console.gui"); - -GlobalActionMap.bind("keyboard", "tilde", "toggleConsole"); - -function ConsoleEntry::eval() -{ - %text = trim(ConsoleEntry.getValue()); - if(%text $= "") - return; - - // If it's missing a trailing () and it's not a variable, - // append the parentheses. - if(strpos(%text, "(") == -1 && !isDefined(%text)) { - if(strpos(%text, "=") == -1 && strpos(%text, " ") == -1) { - if(strpos(%text, "{") == -1 && strpos(%text, "}") == -1) { - %text = %text @ "()"; - } - } - } - - // Append a semicolon if need be. - %pos = strlen(%text) - 1; - if(strpos(%text, ";", %pos) == -1 && strpos(%text, "}") == -1) { - %text = %text @ ";"; - } - - // Turn off warnings for assigning from void - // and evaluate the snippet. - if(!isDefined("$Con::warnVoidAssignment")) - %oldWarnVoidAssignment = true; - else - %oldWarnVoidAssignment = $Con::warnVoidAssignment; - $Con::warnVoidAssignment = false; - - echo("==>" @ %text); - if( !startsWith(%text, "function ") - && !startsWith(%text, "datablock ") - && !startsWith(%text, "foreach(") - && !startsWith(%text, "foreach$(") - && !startsWith(%text, "if(") - && !startsWith(%text, "while(") - && !startsWith(%text, "for(") - && !startsWith(%text, "switch(") - && !startsWith(%text, "switch$(")) - eval("%result = " @ %text); - else - eval(%text); - $Con::warnVoidAssignment = %oldWarnVoidAssignment; - - ConsoleEntry.setValue(""); - - // Echo result. - if(%result !$= "") - echo(%result); -} - -function ToggleConsole(%make) -{ - if (%make) { - if (ConsoleDlg.isAwake()) { - // Deactivate the console. - Canvas.popDialog(ConsoleDlg); - } else { - Canvas.pushDialog(ConsoleDlg, 99); - } - } -} - -function ConsoleDlg::hideWindow(%this) -{ - %this-->Scroll.setVisible(false); -} - -function ConsoleDlg::showWindow(%this) -{ - %this-->Scroll.setVisible(true); -} - -function ConsoleDlg::onWake(%this) -{ - ConsoleDlgErrorFilterBtn.setStateOn(ConsoleMessageLogView.getErrorFilter()); - ConsoleDlgWarnFilterBtn.setStateOn(ConsoleMessageLogView.getWarnFilter()); - ConsoleDlgNormalFilterBtn.setStateOn(ConsoleMessageLogView.getNormalFilter()); - - ConsoleMessageLogView.refresh(); -} - -function ConsoleDlg::setAlpha( %this, %alpha) -{ - if (%alpha $= "") - ConsoleScrollProfile.fillColor = $ConsoleDefaultFillColor; - else - ConsoleScrollProfile.fillColor = getWords($ConsoleDefaultFillColor, 0, 2) SPC %alpha * 255.0; -} - -function ConsoleDlgErrorFilterBtn::onClick(%this) -{ - ConsoleMessageLogView.toggleErrorFilter(); -} - -function ConsoleDlgWarnFilterBtn::onClick(%this) -{ - - ConsoleMessageLogView.toggleWarnFilter(); -} - -function ConsoleDlgNormalFilterBtn::onClick(%this) -{ - ConsoleMessageLogView.toggleNormalFilter(); -} - -function ConsoleMessageLogView::onNewMessage(%this, %errorCount, %warnCount, %normalCount) -{ - ConsoleDlgErrorFilterBtn.setText("(" @ %errorCount @ ") Errors"); - ConsoleDlgWarnFilterBtn.setText("(" @ %warnCount @ ") Warnings"); - ConsoleDlgNormalFilterBtn.setText("(" @ %normalCount @ ") Messages"); -} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/console/profiles.cs b/Templates/BaseGame/game/core/console/profiles.cs deleted file mode 100644 index b83dd4fa7..000000000 --- a/Templates/BaseGame/game/core/console/profiles.cs +++ /dev/null @@ -1,70 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//----------------------------------------------------------------------------- - -if(!isObject(GuiConsoleProfile)) -new GuiControlProfile(GuiConsoleProfile) -{ - fontType = ($platform $= "macos") ? "Monaco" : "Lucida Console"; - fontSize = ($platform $= "macos") ? 13 : 12; - fontColor = "255 255 255"; - fontColorHL = "0 255 255"; - fontColorNA = "255 0 0"; - fontColors[6] = "100 100 100"; - fontColors[7] = "100 100 0"; - fontColors[8] = "0 0 100"; - fontColors[9] = "0 100 0"; - category = "Core"; -}; - -if(!isObject(GuiConsoleTextProfile)) -new GuiControlProfile(GuiConsoleTextProfile) -{ - fontColor = "0 0 0"; - autoSizeWidth = true; - autoSizeHeight = true; - textOffset = "2 2"; - opaque = true; - fillColor = "255 255 255"; - border = true; - borderThickness = 1; - borderColor = "0 0 0"; - category = "Core"; -}; - -if(!isObject(ConsoleScrollProfile)) -new GuiControlProfile(ConsoleScrollProfile : GuiScrollProfile) -{ - opaque = true; - fillColor = "0 0 0 175"; - border = 1; - //borderThickness = 0; - borderColor = "0 0 0"; - category = "Core"; -}; - -if(!isObject(ConsoleTextEditProfile)) -new GuiControlProfile(ConsoleTextEditProfile : GuiTextEditProfile) -{ - fillColor = "242 241 240 255"; - fillColorHL = "255 255 255"; - category = "Core"; -}; diff --git a/Templates/BaseGame/game/core/cursor.cs b/Templates/BaseGame/game/core/cursor.cs deleted file mode 100644 index f71bc023a..000000000 --- a/Templates/BaseGame/game/core/cursor.cs +++ /dev/null @@ -1,102 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//----------------------------------------------------------------------------- - -//--------------------------------------------------------------------------------------------- -// Cursor toggle functions. -//--------------------------------------------------------------------------------------------- -$cursorControlled = true; -function showCursor() -{ - if ($cursorControlled) - lockMouse(false); - Canvas.cursorOn(); -} - -function hideCursor() -{ - if ($cursorControlled) - lockMouse(true); - Canvas.cursorOff(); -} - -//--------------------------------------------------------------------------------------------- -// In the CanvasCursor package we add some additional functionality to the built-in GuiCanvas -// class, of which the global Canvas object is an instance. In this case, the behavior we want -// is for the cursor to automatically display, except when the only guis visible want no -// cursor - usually the in game interface. -//--------------------------------------------------------------------------------------------- -package CanvasCursorPackage -{ - -//--------------------------------------------------------------------------------------------- -// checkCursor -// The checkCursor method iterates through all the root controls on the canvas checking each -// ones noCursor property. If the noCursor property exists as anything other than false or an -// empty string on every control, the cursor will be hidden. -//--------------------------------------------------------------------------------------------- -function GuiCanvas::checkCursor(%this) -{ - %count = %this.getCount(); - for(%i = 0; %i < %count; %i++) - { - %control = %this.getObject(%i); - if ((%control.noCursor $= "") || !%control.noCursor) - { - showCursor(); - return; - } - } - // If we get here, every control requested a hidden cursor, so we oblige. - hideCursor(); -} - -//--------------------------------------------------------------------------------------------- -// The following functions override the GuiCanvas defaults that involve changing the content -// of the Canvas. Basically, all we are doing is adding a call to checkCursor to each one. -//--------------------------------------------------------------------------------------------- -function GuiCanvas::setContent(%this, %ctrl) -{ - Parent::setContent(%this, %ctrl); - %this.checkCursor(); -} - -function GuiCanvas::pushDialog(%this, %ctrl, %layer, %center) -{ - Parent::pushDialog(%this, %ctrl, %layer, %center); - %this.checkCursor(); -} - -function GuiCanvas::popDialog(%this, %ctrl) -{ - Parent::popDialog(%this, %ctrl); - %this.checkCursor(); -} - -function GuiCanvas::popLayer(%this, %layer) -{ - Parent::popLayer(%this, %layer); - %this.checkCursor(); -} - -}; - -activatePackage(CanvasCursorPackage); diff --git a/Templates/BaseGame/game/core/fonts/Arial 10 (ansi).uft b/Templates/BaseGame/game/core/fonts/Arial 10 (ansi).uft deleted file mode 100644 index 2b564950050cfca995e66f048e0523428ff493b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 412 zcmZQ(U|?W%EXqvG;R3Qi07P>@F%ytx24VyN@mQf;5Dk%qsR4%?)Qy83;)lEIri7m zFZoExihWaFY>GaAyHfb_#$7>4rhD3-7VX{JcRHkY<;8EhWjEc^(!MS|x7jKnT~tu; z`y-fhfi55e9MJ#4lvSq~c?$DU2jYrb$q5Y1ZVG9@ Ja2IA^0RUczP(}a% diff --git a/Templates/BaseGame/game/core/fonts/Arial 12 (ansi).uft b/Templates/BaseGame/game/core/fonts/Arial 12 (ansi).uft deleted file mode 100644 index 67a177016766c6f06b5b601c3336b9fea2ac75ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 62 jcmZQ(U|?W%EXqvG;Q_Kh07P>_F*8U23jU*ldXO*xH#ZTF diff --git a/Templates/BaseGame/game/core/fonts/Arial 14 (ansi).uft b/Templates/BaseGame/game/core/fonts/Arial 14 (ansi).uft deleted file mode 100644 index 159010c6850f3424dbc7456533d0e2ae6f82e9bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5160 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 A=Kufz diff --git a/Templates/BaseGame/game/core/fonts/Arial 16 (ansi).uft b/Templates/BaseGame/game/core/fonts/Arial 16 (ansi).uft deleted file mode 100644 index 058fbb305a81a9670c8a346f4384647711e5f8ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13112 zcmc(kc|29y+rYPDDnm$y6i$dxC|xPxC`yx%3{f? zsTC%5z@$V>dLNTM#-z_M>2pk)fJxIa>3^8C1e2Cy($AQ*36pkV(g93L!lWqtqoVma zGKY?Xa|_Naxdta3g64nz3qhaqgf(1~rWwI`~VIYVf7C^x$WmGu04?%cX00jhiA?qUR75t6D-JkvuDvVMP zGctluWWC}j1uFmoEQ1JvK+qmoD5C<=fEkD#X_S)Vg}XlqLS;}2=2Hqn_n{Q@DD#X^ zIh4}=(5|DabQf_t);-?=geiLC_DBg1MA2gSU>V5&Mr99=;9&ul$oim0 zbiu8HhXqg&Gg%j*?(hg6mbG>7QP4kiy(#FQejlUs_go>TERaH%Z24Er!D~=33yC=b zrR0^6Ys7LSNn7ag+kfloYYN8>L_cKpzy~0a-72b0eT5lzx%60!qPL=#N`X}n4WPg$;upNv5zrpkK~TUfgnGa&0xUoW z2=D;xAeR4yTLf4@CV$T+1bL#Atn8GlqQK0#T7E&;_#)3T_oZ!485^u-;$v07}7J;13i~ zBf9c%3+RH~1~~!+)JQf|;1-~ixdN6EdJ?5T7mSjlLhNW^QUgqS1(TXlP_PnmCK124 zPztgEP8OiQo@XbNf|$Y611Qi#bnn2ezpvK|lRn0zK@^lSW+ao~@3O!9jisO+(k zC>64L$IY{O5X7!|Oj$|GA#5aUo7Kee{4%%xd^R?=b;>jXIQN0Ji=$dvc-H$2G?!FV zRA_PT2?+@VExZ^j2gf>Pm3}qaD4e^|D4vyL9SzI~_&xS>#y3rF_J6Omc`rh&sB8Kj^R5xdFGSFjik7l?(usJ zKS=R?aK$z?N>$04F0jFsgEgu2BFBBmWs;SRtz0rQT52F)_EW$y?wRwJ-1pKX)HyQ* z1iD{0PS^8jZE7fTn^bCy<$Eovq8ynDBiA+4DPyOINx9p#)e>Ulz%DrgZdyUsc zD#}8dkT2kn8$+e2RgXoM<2%_wH_iCNHaKVv0blfWu2F@8f;E>w-DF zrH{0$*l*&WPGHF&d@YyVZlUj@ccE#<#jWMma053tL*H(~*lv@0E~qNG;>p$eqbz(4 z)5@V~BOSt#5-%6os!3TPZ}K|~sHFy&{XZI?W3-IjIW}?x;z(-3@g}Ofw*)FMS}i|L zn0QLH$Hp%=Q-qMLlKcoiP~6Q#*eQ-%=wo~M(PE#&$M;8Vr!MwPOwmmARCqy6t-_kO zIYU^W$)W%5fAy9)eMh$6XWok@l*vwc_RyH<+;)6UhR(59x)*0TWy2YX4`yiYZz6`c zZR}duRw3|G__LY!-WEBW*%l2Yyrx)p7EVgEeFK!oY45;NR7lCS9G_|$Ik zUte;LV@FDga$>Sez-%7Tx7cK7$+VeHbhBvu3FU+-`;!$f%TtN|1!~ZTs~jpxd83_o zm|rm4&FK;QKgm zG_CpEyb|=Ori*$GZ&dgn)Z`zzJvT*tYx?2qhwbhj)Z1?FK4d z3;y(28|o3~*6Z0y*K41pfj z*eR4S_&p&?HP^$`rKiAdK<35#JeU6WH{r@(b}(i%Rq0=KaOh?&*9%C8GljH`=1)(qCn=}uS-|a^E(Wfy+pOj|lpJvZU;Pfa*|&MI$EVV}X$Kd-PjTpCm@D1Ee1q?b zn1|nFsN75eJ`xviE7cH=R@8x#2C}@-#cD{d~CT(=oSoWs1Q&BO0hP35<==*wdDG$0r|0RkB-|Y7= zBVnN4rM0bmMoG>!=?2{!m3rU6wiJOrpDVq`rElA`=bSp+>y#)E9Q1`nKBKZ{R}i1d ze!=3c+OqsRAPX~!Yuw(U1(0)R2uJ|S>En=^IcFT z9i$`Oa_YI98%;>~QricoPmzz@$2SwDtJZ~YAq*(k1|0g-^L{^%T#$Y^95IvRS#r8i1?9UGN?D*;ho_mz!jXJWP3L)dA{lSc+*Q8_H5Hz zjMB~#V=~w5i0+rd1KLc*3H?kZd0+bOhSL!Wqxp>w3ow>jD6CW0hosW1WoVw((@Keb zvCyzAz47RWI5a{x-pXd(F*3WXADaCo$Nv=n9&wu6^s@obW>$LTt&bmh6tc0Dbv8K& zY>57r>*1R09#;G{O?#1Ptc)q?V3BRYBW~@kq%>)BPy5R0K(^&3Q+gYglF+g=yzc9l z;ZA0eq9*@5KS2FdrbEtqYxT#s7XtfbHknjDfI8|9r7tn5_PBd~$Zi@wzk0s+%5H1g zl5m>ooQK8+|&T;82W%i_ZrRy__PFV!k<6=&` z=8s8kWJ zw1w|C>#yz=JrEs33baktwNVRV8+WcAHEyzhb0DAho(?~)ksS|Xq@&nL|gp83Fur_U?6E7EmSSL zZpSZ~a+FQCPMz&g%&^br$6HM2b6&sIXOMQ*e$MgFe@-+>hyVRH^G(fHc27l@X#{YInxK@zXS6rHh<|IZtNHUqnXwxMkH}J2BT3;d16J$1j(ehjuZO&M(5MJU{ z#Ec8h&5#Uw!FSB(#=)$KD;7@Uxu1G)^A-CE=I3jV*2S#faqW<+#pRkw>+h92L+b|P zY?|))oE@V2oS%6h5qgtb&liU)Ntw&SUD?n}U2?rsBoR`|b}5;u5b3C#_ITdTw~n|k zr(FXdT0JB0w0yq7T4!Ywzmcb7$$EM22lc)?yV`3-5dH|U)2N@-I4ic;M8YP0o}W%z{KN?GZM+ju9m ze`Q(3dtXDnv5gCJpFOeIm1i|_REFfMIDT*L@I>wDr!u&udXBl|`9a#b?LLoMiEqHm zoZ>d0e#eM@y<=eo`Qj(9YUEiiG*aI%pc1?Mf^Y608u|T(LYj3;B&vFyWftjK`~Fv= zojL4&-_CYVz6^wz1V z>9E!ur{PGdPvpAFbyr13^y+M+^?Fz9#cLzWJGmspI*biC32_ziUA5Bzl|yy?%_J3dLFA(BKM~yVbWyY%y9~rxEJ&{`HeDIX~^-7k4GmmBzG6#ANN_x>+=?t6}k!IcfD_LQ-U)0C8n7Yv}z^s&u~4^lKuK^OvZE3QjAmBo_S; zBv?dvu^b51eSEc+?zCI#lDy@!%bn~*k-_DA(6q!tPp}15U{J8_X6w#7+GZv(>6Y=T zy-yVx@c04AES|nau_B(fMzQ3~L!0_X&FkH?(|C4^+wg^t?Yy=XXS-Ts{sl#cKTnv2+7U1Qn}Oe%_sOc38tO6Y46t=yJsfz+IU&*?|hN6C*_AnWSk!xUAD2j zG@H8Blh(oP?Fs8v4qac{*Rz^O*ZVP#E-W$-8Q?ZwcYx~jJ zO`Spmj+s^tN$1(7nrqwcn2KwTTJ#89qF=rhBQKGu_%`k!Ur;S?D;HEz?mSj9Rle+= z`{3RXxH3nK9TsB0c89-$#IzE2h+Z{Nn}{VkMr(h~mOQwZGDN?>FT-T4&&#~s6 z%DW8}|>L3$K-j@&4%?c7;s-*5C3@tT6=Z5o;j+IavA$a z%$(VjV@nlgVMz28H^0F%Fap2mESwDqY1?F<6vkVzBb3gxII!LDtE;`@QjsC}bIJD@ zXRIpIK~9klQI>z|LV1;pL$)vYL$78ZL9#EPi%($#N<8UV=Z{N|4_&hMo(-RQ+@n{;K#Z7m(rrkII{&h8O&I4u#Fi8165lDU zwk|*%@4YqGIg2Rr3=L$-*=DckmC=0e*e8%E=bZ(V{pnhkg%4WuT~^YZC`x8lqrOxe zxHr_!@@uQyhK1YLso>cc7MDL-Zi#S+AE;tKk&n|a=+-x*lYYo8>glduC;-p>4b zvFiOzn@|~#e`~X3WSQ?TYi2ipEd9@j%@2-Zi1zWj8;Xiq+3;%E$2Pe{HO}m1Sh&#b znaLkpB>Gm3LrcgnPuIc%m|8_Q+6Y)SLfGCle171@8)=-cEPV{ENrUg~Th z^e@R76c6H?d5;P5<+^P>fT14B}?jbl5Z4sp?i>nE$YUaA|{D;bxZn;CN4dZEw z-&HMHaOqR!k}Jw#4!jW1 z%lzgk!b!OMk#|Eat=Ly0Jk7Dk$TGWm(z~+kEYoYKUAW5Uwd5g=v}RHdJ0q(oNoEko zagBH(l^DK3iaW?V)B{&{gh|}*(SxZFW;g0fRJVlaaprnoagb@z%~r+7y9Cu9PmkCW zV5)c^vA86Sp)L(ts(rI!0w0J*#-viA$qIply;Sm*-X4Ze+6A7q7v9~^I4xfKp_2gF zEfO8%6$%L|JmBT6Zb~bQ=Sone zR%qqpXWhG2pjlck0z^A!YSiIndLkn*y z^Pt=Z=2f8Sr%R+|w@4BeT`SUq?uyY5NFykIitF6F5v9U<`x z@>G-`*`4&|p#{@ro=;65cBhU%w8X7WE3$`_zZ2e_SaH&V;Y`TKy13mh2TxkkNrzNa z8t+bSuC&--6Y{C;`|h;)N=qunh2pzA&DgxpRdzp3kBQxBzWLL+>Iv=is3$3A9LeXZ zel(=VWu=(&4xOu6kV${>$jppAw59TUc6#hfGxII2E!8u2>CxfCW?cC#RiiWM@rA?Y z{EIC$D;unydu$zM^*m7d&BrPxdg};x*@5bDHLIwAu;ESd2dW0Et>QAnMz;1JsF|0r zdf{y_yfG-RvM<#tHrZf=r!lX3+QKS2v~8F(C$DN`)G9u|ZG>+&uV$H#^xX5{Fq^Ma zWlsbtCjQ{a<{GE!$qS^Ypn_qJG^eVe4pLlB!3gh|Q_Z3R>4op@VfM&{%Kjo!Y})OS gEu9P1v#zA*$faSf;)SZQ6;gch(lWimA=f+q2mLv4SO5S3 diff --git a/Templates/BaseGame/game/core/fonts/Arial 36 (ansi).uft b/Templates/BaseGame/game/core/fonts/Arial 36 (ansi).uft deleted file mode 100644 index 968441ce3b27703632299ab9837977bb7ee35234..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1046 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 Rs65Gnf66lkhDqo7I{?g*3BJNm1w(Cv{3L(q2 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 BNb3Lq diff --git a/Templates/BaseGame/game/core/gfxData/clouds.cs b/Templates/BaseGame/game/core/gfxData/clouds.cs deleted file mode 100644 index 00d56d6d3..000000000 --- a/Templates/BaseGame/game/core/gfxData/clouds.cs +++ /dev/null @@ -1,55 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//----------------------------------------------------------------------------- - -//------------------------------------------------------------------------------ -// CloudLayer -//------------------------------------------------------------------------------ - -singleton ShaderData( CloudLayerShader ) -{ - DXVertexShaderFile = $Core::CommonShaderPath @ "/cloudLayerV.hlsl"; - DXPixelShaderFile = $Core::CommonShaderPath @ "/cloudLayerP.hlsl"; - - OGLVertexShaderFile = $Core::CommonShaderPath @ "/gl/cloudLayerV.glsl"; - OGLPixelShaderFile = $Core::CommonShaderPath @ "/gl/cloudLayerP.glsl"; - - samplerNames[0] = "$normalHeightMap"; - - pixVersion = 2.0; -}; - -//------------------------------------------------------------------------------ -// BasicClouds -//------------------------------------------------------------------------------ - -singleton ShaderData( BasicCloudsShader ) -{ - DXVertexShaderFile = $Core::CommonShaderPath @ "/basicCloudsV.hlsl"; - DXPixelShaderFile = $Core::CommonShaderPath @ "/basicCloudsP.hlsl"; - - OGLVertexShaderFile = $Core::CommonShaderPath @ "/gl/basicCloudsV.glsl"; - OGLPixelShaderFile = $Core::CommonShaderPath @ "/gl/basicCloudsP.glsl"; - - samplerNames[0] = "$diffuseMap"; - - pixVersion = 2.0; -}; diff --git a/Templates/BaseGame/game/core/gfxData/commonMaterialData.cs b/Templates/BaseGame/game/core/gfxData/commonMaterialData.cs deleted file mode 100644 index c5d8ef5bc..000000000 --- a/Templates/BaseGame/game/core/gfxData/commonMaterialData.cs +++ /dev/null @@ -1,79 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -// Anim flag settings - must match material.h -// These cannot be enumed through script becuase it cannot -// handle the "|" operation for combining them together -// ie. Scroll | Wave does not work. -//----------------------------------------------------------------------------- -$scroll = 1; -$rotate = 2; -$wave = 4; -$scale = 8; -$sequence = 16; - - -// Common stateblock definitions -new GFXSamplerStateData(SamplerClampLinear) -{ - textureColorOp = GFXTOPModulate; - addressModeU = GFXAddressClamp; - addressModeV = GFXAddressClamp; - addressModeW = GFXAddressClamp; - magFilter = GFXTextureFilterLinear; - minFilter = GFXTextureFilterLinear; - mipFilter = GFXTextureFilterLinear; -}; - -new GFXSamplerStateData(SamplerClampPoint) -{ - textureColorOp = GFXTOPModulate; - addressModeU = GFXAddressClamp; - addressModeV = GFXAddressClamp; - addressModeW = GFXAddressClamp; - magFilter = GFXTextureFilterPoint; - minFilter = GFXTextureFilterPoint; - mipFilter = GFXTextureFilterPoint; -}; - -new GFXSamplerStateData(SamplerWrapLinear) -{ - textureColorOp = GFXTOPModulate; - addressModeU = GFXTextureAddressWrap; - addressModeV = GFXTextureAddressWrap; - addressModeW = GFXTextureAddressWrap; - magFilter = GFXTextureFilterLinear; - minFilter = GFXTextureFilterLinear; - mipFilter = GFXTextureFilterLinear; -}; - -new GFXSamplerStateData(SamplerWrapPoint) -{ - textureColorOp = GFXTOPModulate; - addressModeU = GFXTextureAddressWrap; - addressModeV = GFXTextureAddressWrap; - addressModeW = GFXTextureAddressWrap; - magFilter = GFXTextureFilterPoint; - minFilter = GFXTextureFilterPoint; - mipFilter = GFXTextureFilterPoint; -}; diff --git a/Templates/BaseGame/game/core/gfxData/scatterSky.cs b/Templates/BaseGame/game/core/gfxData/scatterSky.cs deleted file mode 100644 index 5add01d8b..000000000 --- a/Templates/BaseGame/game/core/gfxData/scatterSky.cs +++ /dev/null @@ -1,48 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//----------------------------------------------------------------------------- - -new GFXStateBlockData( ScatterSkySBData ) -{ - cullMode = "GFXCullNone"; - - zDefined = true; - zEnable = true; - zWriteEnable = false; - - samplersDefined = true; - samplerStates[0] = SamplerClampLinear; - samplerStates[1] = SamplerClampLinear; - vertexColorEnable = true; -}; - -singleton ShaderData( ScatterSkyShaderData ) -{ - DXVertexShaderFile = $Core::CommonShaderPath @ "/scatterSkyV.hlsl"; - DXPixelShaderFile = $Core::CommonShaderPath @ "/scatterSkyP.hlsl"; - - OGLVertexShaderFile = $Core::CommonShaderPath @ "/gl/scatterSkyV.glsl"; - OGLPixelShaderFile = $Core::CommonShaderPath @ "/gl/scatterSkyP.glsl"; - - samplerNames[0] = "$nightSky"; - - pixVersion = 2.0; -}; diff --git a/Templates/BaseGame/game/core/gfxData/shaders.cs b/Templates/BaseGame/game/core/gfxData/shaders.cs deleted file mode 100644 index da3b7c864..000000000 --- a/Templates/BaseGame/game/core/gfxData/shaders.cs +++ /dev/null @@ -1,152 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -// This file contains shader data necessary for various engine utility functions -//----------------------------------------------------------------------------- - - -singleton ShaderData( ParticlesShaderData ) -{ - DXVertexShaderFile = $Core::CommonShaderPath @ "/particlesV.hlsl"; - DXPixelShaderFile = $Core::CommonShaderPath @ "/particlesP.hlsl"; - - OGLVertexShaderFile = $Core::CommonShaderPath @ "/gl/particlesV.glsl"; - OGLPixelShaderFile = $Core::CommonShaderPath @ "/gl/particlesP.glsl"; - - samplerNames[0] = "$diffuseMap"; - samplerNames[1] = "$deferredTex"; - samplerNames[2] = "$paraboloidLightMap"; - - pixVersion = 2.0; -}; - -singleton ShaderData( OffscreenParticleCompositeShaderData ) -{ - DXVertexShaderFile = $Core::CommonShaderPath @ "/particleCompositeV.hlsl"; - DXPixelShaderFile = $Core::CommonShaderPath @ "/particleCompositeP.hlsl"; - - OGLVertexShaderFile = $Core::CommonShaderPath @ "/gl/particleCompositeV.glsl"; - OGLPixelShaderFile = $Core::CommonShaderPath @ "/gl/particleCompositeP.glsl"; - - samplerNames[0] = "$colorSource"; - samplerNames[1] = "$edgeSource"; - - pixVersion = 2.0; -}; - -//----------------------------------------------------------------------------- -// Planar Reflection -//----------------------------------------------------------------------------- -new ShaderData( ReflectBump ) -{ - DXVertexShaderFile = $Core::CommonShaderPath @ "/planarReflectBumpV.hlsl"; - DXPixelShaderFile = $Core::CommonShaderPath @ "/planarReflectBumpP.hlsl"; - - OGLVertexShaderFile = $Core::CommonShaderPath @ "/gl/planarReflectBumpV.glsl"; - OGLPixelShaderFile = $Core::CommonShaderPath @ "/gl/planarReflectBumpP.glsl"; - - samplerNames[0] = "$diffuseMap"; - samplerNames[1] = "$refractMap"; - samplerNames[2] = "$bumpMap"; - - pixVersion = 2.0; -}; - -new ShaderData( Reflect ) -{ - DXVertexShaderFile = $Core::CommonShaderPath @ "/planarReflectV.hlsl"; - DXPixelShaderFile = $Core::CommonShaderPath @ "/planarReflectP.hlsl"; - - OGLVertexShaderFile = $Core::CommonShaderPath @ "/gl/planarReflectV.glsl"; - OGLPixelShaderFile = $Core::CommonShaderPath @ "/gl/planarReflectP.glsl"; - - samplerNames[0] = "$diffuseMap"; - samplerNames[1] = "$refractMap"; - - pixVersion = 1.4; -}; - -//----------------------------------------------------------------------------- -// fxFoliageReplicator -//----------------------------------------------------------------------------- -new ShaderData( fxFoliageReplicatorShader ) -{ - DXVertexShaderFile = $Core::CommonShaderPath @ "/fxFoliageReplicatorV.hlsl"; - DXPixelShaderFile = $Core::CommonShaderPath @ "/fxFoliageReplicatorP.hlsl"; - - OGLVertexShaderFile = $Core::CommonShaderPath @ "/gl/fxFoliageReplicatorV.glsl"; - OGLPixelShaderFile = $Core::CommonShaderPath @ "/gl/fxFoliageReplicatorP.glsl"; - - samplerNames[0] = "$diffuseMap"; - samplerNames[1] = "$alphaMap"; - - pixVersion = 1.4; -}; - -singleton ShaderData( VolumetricFogDeferredShader ) -{ - DXVertexShaderFile = $Core::CommonShaderPath @ "/VolumetricFog/VFogPreV.hlsl"; - DXPixelShaderFile = $Core::CommonShaderPath @ "/VolumetricFog/VFogPreP.hlsl"; - - OGLVertexShaderFile = $Core::CommonShaderPath @ "/VolumetricFog/gl/VFogPreV.glsl"; - OGLPixelShaderFile = $Core::CommonShaderPath @ "/VolumetricFog/gl/VFogPreP.glsl"; - - pixVersion = 3.0; -}; -singleton ShaderData( VolumetricFogShader ) -{ - DXVertexShaderFile = $Core::CommonShaderPath @ "/VolumetricFog/VFogV.hlsl"; - DXPixelShaderFile = $Core::CommonShaderPath @ "/VolumetricFog/VFogP.hlsl"; - - OGLVertexShaderFile = $Core::CommonShaderPath @ "/VolumetricFog/gl/VFogV.glsl"; - OGLPixelShaderFile = $Core::CommonShaderPath @ "/VolumetricFog/gl/VFogP.glsl"; - - samplerNames[0] = "$deferredTex"; - samplerNames[1] = "$depthBuffer"; - samplerNames[2] = "$frontBuffer"; - samplerNames[3] = "$density"; - - pixVersion = 3.0; -}; -singleton ShaderData( VolumetricFogReflectionShader ) -{ - DXVertexShaderFile = $Core::CommonShaderPath @ "/VolumetricFog/VFogPreV.hlsl"; - DXPixelShaderFile = $Core::CommonShaderPath @ "/VolumetricFog/VFogRefl.hlsl"; - - OGLVertexShaderFile = $Core::CommonShaderPath @ "/VolumetricFog/gl/VFogPreV.glsl"; - OGLPixelShaderFile = $Core::CommonShaderPath @ "/VolumetricFog/gl/VFogRefl.glsl"; - - pixVersion = 3.0; -}; -singleton ShaderData( CubemapSaveShader ) -{ - DXVertexShaderFile = "shaders/common/cubemapSaveV.hlsl"; - DXPixelShaderFile = "shaders/common/cubemapSaveP.hlsl"; - - OGLVertexShaderFile = "shaders/common/gl/cubemapSaveV.glsl"; - OGLPixelShaderFile = "shaders/common/gl/cubemapSaveP.glsl"; - - samplerNames[0] = "$cubemapTex"; - - pixVersion = 3.0; -}; \ No newline at end of file diff --git a/Templates/BaseGame/game/core/gfxData/terrainBlock.cs b/Templates/BaseGame/game/core/gfxData/terrainBlock.cs deleted file mode 100644 index 69802b1da..000000000 --- a/Templates/BaseGame/game/core/gfxData/terrainBlock.cs +++ /dev/null @@ -1,36 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//----------------------------------------------------------------------------- - -/// Used when generating the blended base texture. -singleton ShaderData( TerrainBlendShader ) -{ - DXVertexShaderFile = $Core::CommonShaderPath @ "/terrain/blendV.hlsl"; - DXPixelShaderFile = $Core::CommonShaderPath @ "/terrain/blendP.hlsl"; - - OGLVertexShaderFile = $Core::CommonShaderPath @ "/terrain/gl/blendV.glsl"; - OGLPixelShaderFile = $Core::CommonShaderPath @ "/terrain/gl/blendP.glsl"; - - samplerNames[0] = "layerTex"; - samplerNames[1] = "textureMap"; - - pixVersion = 2.0; -}; diff --git a/Templates/BaseGame/game/core/gfxData/water.cs b/Templates/BaseGame/game/core/gfxData/water.cs deleted file mode 100644 index ec5e4be71..000000000 --- a/Templates/BaseGame/game/core/gfxData/water.cs +++ /dev/null @@ -1,208 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//----------------------------------------------------------------------------- - - - -//----------------------------------------------------------------------------- -// Water -//----------------------------------------------------------------------------- - -singleton ShaderData( WaterShader ) -{ - DXVertexShaderFile = $Core::CommonShaderPath @ "/water/waterV.hlsl"; - DXPixelShaderFile = $Core::CommonShaderPath @ "/water/waterP.hlsl"; - - OGLVertexShaderFile = $Core::CommonShaderPath @ "/water/gl/waterV.glsl"; - OGLPixelShaderFile = $Core::CommonShaderPath @ "/water/gl/waterP.glsl"; - - samplerNames[0] = "$bumpMap"; // noise - samplerNames[1] = "$deferredTex"; // #deferred - samplerNames[2] = "$reflectMap"; // $reflectbuff - samplerNames[3] = "$refractBuff"; // $backbuff - samplerNames[4] = "$skyMap"; // $cubemap - samplerNames[5] = "$foamMap"; // foam - samplerNames[6] = "$depthGradMap"; // depthMap ( color gradient ) - - pixVersion = 3.0; -}; - -new GFXSamplerStateData(WaterSampler) -{ - textureColorOp = GFXTOPModulate; - addressModeU = GFXAddressWrap; - addressModeV = GFXAddressWrap; - addressModeW = GFXAddressWrap; - magFilter = GFXTextureFilterLinear; - minFilter = GFXTextureFilterAnisotropic; - mipFilter = GFXTextureFilterLinear; - maxAnisotropy = 4; -}; - -singleton GFXStateBlockData( WaterStateBlock ) -{ - samplersDefined = true; - samplerStates[0] = WaterSampler; // noise - samplerStates[1] = SamplerClampPoint; // #deferred - samplerStates[2] = SamplerClampLinear; // $reflectbuff - samplerStates[3] = SamplerClampPoint; // $backbuff - samplerStates[4] = SamplerWrapLinear; // $cubemap - samplerStates[5] = SamplerWrapLinear; // foam - samplerStates[6] = SamplerClampLinear; // depthMap ( color gradient ) - cullDefined = true; - cullMode = "GFXCullCCW"; -}; - -singleton GFXStateBlockData( UnderWaterStateBlock : WaterStateBlock ) -{ - cullMode = "GFXCullCW"; -}; - -singleton CustomMaterial( WaterMat ) -{ - sampler["deferredTex"] = "#deferred"; - sampler["reflectMap"] = "$reflectbuff"; - sampler["refractBuff"] = "$backbuff"; - // These samplers are set in code not here. - // This is to allow different WaterObject instances - // to use this same material but override these textures - // per instance. - //sampler["bumpMap"] = ""; - //sampler["skyMap"] = ""; - //sampler["foamMap"] = ""; - //sampler["depthGradMap"] = ""; - - shader = WaterShader; - stateBlock = WaterStateBlock; - version = 3.0; - - useAnisotropic[0] = true; -}; - -//----------------------------------------------------------------------------- -// Underwater -//----------------------------------------------------------------------------- - -singleton ShaderData( UnderWaterShader : WaterShader ) -{ - defines = "UNDERWATER"; -}; - -singleton CustomMaterial( UnderwaterMat ) -{ - // These samplers are set in code not here. - // This is to allow different WaterObject instances - // to use this same material but override these textures - // per instance. - //sampler["bumpMap"] = "core/art/water/noise02"; - //sampler["foamMap"] = "core/art/water/foam"; - - sampler["deferredTex"] = "#deferred"; - sampler["refractBuff"] = "$backbuff"; - - shader = UnderWaterShader; - stateBlock = UnderWaterStateBlock; - specular = "0.75 0.75 0.75 1.0"; - specularPower = 48.0; - version = 3.0; -}; - -//----------------------------------------------------------------------------- -// Basic Water -//----------------------------------------------------------------------------- - -singleton ShaderData( WaterBasicShader ) -{ - DXVertexShaderFile = $Core::CommonShaderPath @ "/water/waterBasicV.hlsl"; - DXPixelShaderFile = $Core::CommonShaderPath @ "/water/waterBasicP.hlsl"; - - OGLVertexShaderFile = $Core::CommonShaderPath @ "/water/gl/waterBasicV.glsl"; - OGLPixelShaderFile = $Core::CommonShaderPath @ "/water/gl/waterBasicP.glsl"; - - samplerNames[0] = "$bumpMap"; - samplerNames[2] = "$reflectMap"; - samplerNames[3] = "$refractBuff"; - samplerNames[4] = "$skyMap"; - samplerNames[5] = "$depthGradMap"; - - pixVersion = 2.0; -}; - -singleton GFXStateBlockData( WaterBasicStateBlock ) -{ - samplersDefined = true; - samplerStates[0] = WaterSampler; // noise - samplerStates[2] = SamplerClampLinear; // $reflectbuff - samplerStates[3] = SamplerClampPoint; // $backbuff - samplerStates[4] = SamplerWrapLinear; // $cubemap - cullDefined = true; - cullMode = "GFXCullCCW"; -}; - -singleton GFXStateBlockData( UnderWaterBasicStateBlock : WaterBasicStateBlock ) -{ - cullMode = "GFXCullCW"; -}; - -singleton CustomMaterial( WaterBasicMat ) -{ - // These samplers are set in code not here. - // This is to allow different WaterObject instances - // to use this same material but override these textures - // per instance. - //sampler["bumpMap"] = "core/art/water/noise02"; - //sampler["skyMap"] = "$cubemap"; - - //sampler["deferredTex"] = "#deferred"; - sampler["reflectMap"] = "$reflectbuff"; - sampler["refractBuff"] = "$backbuff"; - - cubemap = NewLevelSkyCubemap; - shader = WaterBasicShader; - stateBlock = WaterBasicStateBlock; - version = 2.0; -}; - -//----------------------------------------------------------------------------- -// Basic UnderWater -//----------------------------------------------------------------------------- - -singleton ShaderData( UnderWaterBasicShader : WaterBasicShader) -{ - defines = "UNDERWATER"; -}; - -singleton CustomMaterial( UnderwaterBasicMat ) -{ - // These samplers are set in code not here. - // This is to allow different WaterObject instances - // to use this same material but override these textures - // per instance. - //sampler["bumpMap"] = "core/art/water/noise02"; - //samplers["skyMap"] = "$cubemap"; - - //sampler["deferredTex"] = "#deferred"; - sampler["refractBuff"] = "$backbuff"; - - shader = UnderWaterBasicShader; - stateBlock = UnderWaterBasicStateBlock; - version = 2.0; -}; \ No newline at end of file diff --git a/Templates/BaseGame/game/core/gfxprofile/D3D9.ATITechnologiesInc.cs b/Templates/BaseGame/game/core/gfxprofile/D3D9.ATITechnologiesInc.cs deleted file mode 100644 index 10c6bdf5b..000000000 --- a/Templates/BaseGame/game/core/gfxprofile/D3D9.ATITechnologiesInc.cs +++ /dev/null @@ -1,36 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//----------------------------------------------------------------------------- - -// ATI Vendor Profile Script -// -// This script is responsible for setting global -// capability strings based on the nVidia vendor. - -if(GFXCardProfiler::getVersion() < 64.44) -{ - $GFX::OutdatedDrivers = true; - $GFX::OutdatedDriversLink = "You can get newer drivers here.."; -} -else -{ - $GFX::OutdatedDrivers = false; -} diff --git a/Templates/BaseGame/game/core/gfxprofile/D3D9.NVIDIA.GeForce8600.cs b/Templates/BaseGame/game/core/gfxprofile/D3D9.NVIDIA.GeForce8600.cs deleted file mode 100644 index 328788dac..000000000 --- a/Templates/BaseGame/game/core/gfxprofile/D3D9.NVIDIA.GeForce8600.cs +++ /dev/null @@ -1,36 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//----------------------------------------------------------------------------- - -// nVidia Vendor Profile Script -// -// This script is responsible for setting global -// capability strings based on the nVidia vendor. - -if(GFXCardProfiler::getVersion() < 1.2) -{ - $GFX::OutdatedDrivers = true; - $GFX::OutdatedDriversLink = "You can get newer drivers here.."; -} -else -{ - $GFX::OutdatedDrivers = false; -} diff --git a/Templates/BaseGame/game/core/gfxprofile/D3D9.NVIDIA.QuadroFXGo1000.cs b/Templates/BaseGame/game/core/gfxprofile/D3D9.NVIDIA.QuadroFXGo1000.cs deleted file mode 100644 index 5681b2f6d..000000000 --- a/Templates/BaseGame/game/core/gfxprofile/D3D9.NVIDIA.QuadroFXGo1000.cs +++ /dev/null @@ -1,39 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//----------------------------------------------------------------------------- - -// nVidia Vendor Profile Script -// -// This script is responsible for setting global -// capability strings based on the nVidia vendor. - -if(GFXCardProfiler::getVersion() < 53.82) -{ - $GFX::OutdatedDrivers = true; - $GFX::OutdatedDriversLink = "You can get newer drivers here.."; -} -else -{ - $GFX::OutdatedDrivers = false; -} - -// Silly card has trouble with this! -GFXCardProfiler::setCapability("autoMipmapLevel", false); diff --git a/Templates/BaseGame/game/core/gfxprofile/D3D9.NVIDIA.cs b/Templates/BaseGame/game/core/gfxprofile/D3D9.NVIDIA.cs deleted file mode 100644 index b33b8d5d3..000000000 --- a/Templates/BaseGame/game/core/gfxprofile/D3D9.NVIDIA.cs +++ /dev/null @@ -1,36 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//----------------------------------------------------------------------------- - -// nVidia Vendor Profile Script -// -// This script is responsible for setting global -// capability strings based on the nVidia vendor. - -if(GFXCardProfiler::getVersion() < 56.72) -{ - $GFX::OutdatedDrivers = true; - $GFX::OutdatedDriversLink = "You can get newer drivers here.."; -} -else -{ - $GFX::OutdatedDrivers = false; -} diff --git a/Templates/BaseGame/game/core/gfxprofile/D3D9.cs b/Templates/BaseGame/game/core/gfxprofile/D3D9.cs deleted file mode 100644 index e1e299341..000000000 --- a/Templates/BaseGame/game/core/gfxprofile/D3D9.cs +++ /dev/null @@ -1,26 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//----------------------------------------------------------------------------- - -// Direct3D 9 Renderer Profile Script -// -// This script is responsible for setting global -// capability strings based on the D3D9 renderer type. \ No newline at end of file diff --git a/Templates/BaseGame/game/core/globals.cs b/Templates/BaseGame/game/core/globals.cs deleted file mode 100644 index d4e4f1ca3..000000000 --- a/Templates/BaseGame/game/core/globals.cs +++ /dev/null @@ -1,102 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//----------------------------------------------------------------------------- - -// ---------------------------------------------------------------------------- -// DInput keyboard, mouse, and joystick prefs -// ---------------------------------------------------------------------------- - -$pref::Input::MouseEnabled = 1; -$pref::Input::LinkMouseSensitivity = 1; -$pref::Input::KeyboardEnabled = 1; -$pref::Input::KeyboardTurnSpeed = 0.1; -$pref::Input::JoystickEnabled = 0; - -// ---------------------------------------------------------------------------- -// Video Preferences -// ---------------------------------------------------------------------------- - -// Set directory paths for various data or default images. -$pref::Video::ProfilePath = "core/gfxprofile"; -$pref::Video::missingTexturePath = "core/images/missingTexture.png"; -$pref::Video::unavailableTexturePath = "core/images/unavailable.png"; -$pref::Video::warningTexturePath = "core/images/warnMat.dds"; - -$pref::Video::disableVerticalSync = 1; -$pref::Video::mode = "800 600 false 32 60 4"; -$pref::Video::defaultFenceCount = 0; - -// This disables the hardware FSAA/MSAA so that we depend completely on the FXAA -// post effect which works on all cards and in deferred mode. Note that the new -// Intel Hybrid graphics on laptops will fail to initialize when hardware AA is -// enabled... so you've been warned. -$pref::Video::disableHardwareAA = true; - -$pref::Video::disableNormalmapping = false; -$pref::Video::disablePixSpecular = false; -$pref::Video::disableCubemapping = false; -$pref::Video::disableParallaxMapping = false; - -// The number of mipmap levels to drop on loaded textures to reduce video memory -// usage. It will skip any textures that have been defined as not allowing down -// scaling. -$pref::Video::textureReductionLevel = 0; - -$pref::Video::defaultAnisotropy = 1; -//$pref::Video::Gamma = 1.0; - -/// AutoDetect graphics quality levels the next startup. -$pref::Video::autoDetect = 1; - -// ---------------------------------------------------------------------------- -// Shader stuff -// ---------------------------------------------------------------------------- - -// This is the path used by ShaderGen to cache procedural shaders. If left -// blank ShaderGen will only cache shaders to memory and not to disk. -$shaderGen::cachePath = "data/shaderCache"; - -// Uncomment to disable ShaderGen, useful when debugging -//$ShaderGen::GenNewShaders = false; - -// Uncomment to dump disassembly for any shader that is compiled to disk. These -// will appear as shadername_dis.txt in the same path as the shader file. -//$gfx::disassembleAllShaders = true; - -// ---------------------------------------------------------------------------- -// Lighting and shadowing -// ---------------------------------------------------------------------------- - -// Uncomment to enable AdvancedLighting on the Mac (T3D 2009 Beta 3) -//$pref::machax::enableAdvancedLighting = true; - -$sceneLighting::cacheSize = 20000; -$sceneLighting::purgeMethod = "lastCreated"; -$sceneLighting::cacheLighting = 1; - -$pref::Shadows::textureScalar = 1.0; -$pref::Shadows::disable = false; - -// Sets the shadow filtering mode. -// None - Disables filtering. -// SoftShadow - Does a simple soft shadow -// SoftShadowHighQuality -$pref::Shadows::filterMode = "SoftShadow"; diff --git a/Templates/BaseGame/game/core/helperFunctions.cs b/Templates/BaseGame/game/core/helperFunctions.cs deleted file mode 100644 index 1b98f1ea5..000000000 --- a/Templates/BaseGame/game/core/helperFunctions.cs +++ /dev/null @@ -1,1158 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//----------------------------------------------------------------------------- - - -//------------------------------------------------------------------------------ -// Check if a script file exists, compiled or not. -function isScriptFile(%path) -{ - if( isFile(%path @ ".dso") || isFile(%path) ) - return true; - - return false; -} - -function loadMaterials() -{ - // Load any materials files for which we only have DSOs. - - for( %file = findFirstFile( "*/materials.cs.dso" ); - %file !$= ""; - %file = findNextFile( "*/materials.cs.dso" )) - { - // Only execute, if we don't have the source file. - %csFileName = getSubStr( %file, 0, strlen( %file ) - 4 ); - if( !isFile( %csFileName ) ) - exec( %csFileName ); - } - - // Load all source material files. - - for( %file = findFirstFile( "*/materials.cs" ); - %file !$= ""; - %file = findNextFile( "*/materials.cs" )) - { - exec( %file ); - } - - // Load all materials created by the material editor if - // the folder exists - if( IsDirectory( "materialEditor" ) ) - { - for( %file = findFirstFile( "materialEditor/*.cs.dso" ); - %file !$= ""; - %file = findNextFile( "materialEditor/*.cs.dso" )) - { - // Only execute, if we don't have the source file. - %csFileName = getSubStr( %file, 0, strlen( %file ) - 4 ); - if( !isFile( %csFileName ) ) - exec( %csFileName ); - } - - for( %file = findFirstFile( "materialEditor/*.cs" ); - %file !$= ""; - %file = findNextFile( "materialEditor/*.cs" )) - { - exec( %file ); - } - } -} - -function reloadMaterials() -{ - reloadTextures(); - loadMaterials(); - reInitMaterials(); -} - -function loadDatablockFiles( %datablockFiles, %recurse ) -{ - if ( %recurse ) - { - recursiveLoadDatablockFiles( %datablockFiles, 9999 ); - return; - } - - %count = %datablockFiles.count(); - for ( %i=0; %i < %count; %i++ ) - { - %file = %datablockFiles.getKey( %i ); - if ( !isFile(%file @ ".dso") && !isFile(%file) ) - continue; - - exec( %file ); - } - - // Destroy the incoming list. - //%datablockFiles.delete(); -} - -function recursiveLoadDatablockFiles( %datablockFiles, %previousErrors ) -{ - %reloadDatablockFiles = new ArrayObject(); - - // Keep track of the number of datablocks that - // failed during this pass. - %failedDatablocks = 0; - - // Try re-executing the list of datablock files. - %count = %datablockFiles.count(); - for ( %i=0; %i < %count; %i++ ) - { - %file = %datablockFiles.getKey( %i ); - if ( !isFile(%file @ ".dso") && !isFile(%file) ) - continue; - - // Start counting copy constructor creation errors. - $Con::objectCopyFailures = 0; - - exec( %file ); - - // If errors occured then store this file for re-exec later. - if ( $Con::objectCopyFailures > 0 ) - { - %reloadDatablockFiles.add( %file ); - %failedDatablocks = %failedDatablocks + $Con::objectCopyFailures; - } - } - - // Clear the object copy failure counter so that - // we get console error messages again. - $Con::objectCopyFailures = -1; - - // Delete the old incoming list... we're done with it. - //%datablockFiles.delete(); - - // If we still have datablocks to retry. - %newCount = %reloadDatablockFiles.count(); - if ( %newCount > 0 ) - { - // If the datablock failures have not been reduced - // from the last pass then we must have a real syntax - // error and not just a bad dependancy. - if ( %previousErrors > %failedDatablocks ) - recursiveLoadDatablockFiles( %reloadDatablockFiles, %failedDatablocks ); - - else - { - // Since we must have real syntax errors do one - // last normal exec to output error messages. - loadDatablockFiles( %reloadDatablockFiles, false ); - } - - return; - } - - // Cleanup the empty reload list. - %reloadDatablockFiles.delete(); -} - -function getUserPath() -{ - %temp = getUserHomeDirectory(); - echo(%temp); - if(!isDirectory(%temp)) - { - %temp = getUserDataDirectory(); - echo(%temp); - if(!isDirectory(%temp)) - { - %userPath = "data"; - } - else - { - //put it in appdata/roaming - %userPath = %temp @ "/" @ $appName; - } - } - else - { - //put it in user/documents - %userPath = %temp @ "/" @ $appName; - } - return %userPath; -} - -function getPrefpath() -{ - $prefPath = getUserPath() @ "/preferences"; - return $prefPath; -} - -function updateTSShapeLoadProgress(%progress, %msg) -{ - // Check if the loading GUI is visible and use that instead of the - // separate import progress GUI if possible - /* if ( isObject(LoadingGui) && LoadingGui.isAwake() ) - { - // Save/Restore load progress at the start/end of the import process - if ( %progress == 0 ) - { - ColladaImportProgress.savedProgress = LoadingProgress.getValue(); - ColladaImportProgress.savedText = LoadingProgressTxt.getValue(); - - ColladaImportProgress.msgPrefix = "Importing " @ %msg; - %msg = "Reading file into memory..."; - } - else if ( %progress == 1.0 ) - { - LoadingProgress.setValue( ColladaImportProgress.savedProgress ); - LoadingProgressTxt.setValue( ColladaImportProgress.savedText ); - } - - %msg = ColladaImportProgress.msgPrefix @ ": " @ %msg; - - %progressCtrl = LoadingProgress; - %textCtrl = LoadingProgressTxt; - } - else - { - //it's probably the editors using it - if(isFunction("updateToolTSShapeLoadProgress")) - { - updateToolTSShapeLoadProgress(%progress, %msg); - } - } - - // Update progress indicators - if (%progress == 0) - { - %progressCtrl.setValue(0.001); - %textCtrl.setText(%msg); - } - else if (%progress != 1.0) - { - %progressCtrl.setValue(%progress); - %textCtrl.setText(%msg); - } - - Canvas.repaint(33);*/ -} - -/// A helper function which will return the ghosted client object -/// from a server object when connected to a local server. -function serverToClientObject( %serverObject ) -{ - assert( isObject( LocalClientConnection ), "serverToClientObject() - No local client connection found!" ); - assert( isObject( ServerConnection ), "serverToClientObject() - No server connection found!" ); - - %ghostId = LocalClientConnection.getGhostId( %serverObject ); - if ( %ghostId == -1 ) - return 0; - - return ServerConnection.resolveGhostID( %ghostId ); -} - -//---------------------------------------------------------------------------- -// Debug commands -//---------------------------------------------------------------------------- - -function netSimulateLag( %msDelay, %packetLossPercent ) -{ - if ( %packetLossPercent $= "" ) - %packetLossPercent = 0; - - commandToServer( 'NetSimulateLag', %msDelay, %packetLossPercent ); -} - -//Various client functions - -function validateDatablockName(%name) -{ - // remove whitespaces at beginning and end - %name = trim( %name ); - - // remove numbers at the beginning - %numbers = "0123456789"; - while( strlen(%name) > 0 ) - { - // the first character - %firstChar = getSubStr( %name, 0, 1 ); - // if the character is a number remove it - if( strpos( %numbers, %firstChar ) != -1 ) - { - %name = getSubStr( %name, 1, strlen(%name) -1 ); - %name = ltrim( %name ); - } - else - break; - } - - // replace whitespaces with underscores - %name = strreplace( %name, " ", "_" ); - - // remove any other invalid characters - %invalidCharacters = "-+*/%$&§=()[].?\"#,;!~<>|°^{}"; - %name = stripChars( %name, %invalidCharacters ); - - if( %name $= "" ) - %name = "Unnamed"; - - return %name; -} - -//-------------------------------------------------------------------------- -// Finds location of %word in %text, starting at %start. Works just like strPos -//-------------------------------------------------------------------------- - -function wordPos(%text, %word, %start) -{ - if (%start $= "") %start = 0; - - if (strpos(%text, %word, 0) == -1) return -1; - %count = getWordCount(%text); - if (%start >= %count) return -1; - for (%i = %start; %i < %count; %i++) - { - if (getWord( %text, %i) $= %word) return %i; - } - return -1; -} - -//-------------------------------------------------------------------------- -// Finds location of %field in %text, starting at %start. Works just like strPos -//-------------------------------------------------------------------------- - -function fieldPos(%text, %field, %start) -{ - if (%start $= "") %start = 0; - - if (strpos(%text, %field, 0) == -1) return -1; - %count = getFieldCount(%text); - if (%start >= %count) return -1; - for (%i = %start; %i < %count; %i++) - { - if (getField( %text, %i) $= %field) return %i; - } - return -1; -} - -//-------------------------------------------------------------------------- -// returns the text in a file with "\n" at the end of each line -//-------------------------------------------------------------------------- - -function loadFileText( %file) -{ - %fo = new FileObject(); - %fo.openForRead(%file); - %text = ""; - while(!%fo.isEOF()) - { - %text = %text @ %fo.readLine(); - if (!%fo.isEOF()) %text = %text @ "\n"; - } - - %fo.delete(); - return %text; -} - -function setValueSafe(%dest, %val) -{ - %cmd = %dest.command; - %alt = %dest.altCommand; - %dest.command = ""; - %dest.altCommand = ""; - - %dest.setValue(%val); - - %dest.command = %cmd; - %dest.altCommand = %alt; -} - -function shareValueSafe(%source, %dest) -{ - setValueSafe(%dest, %source.getValue()); -} - -function shareValueSafeDelay(%source, %dest, %delayMs) -{ - schedule(%delayMs, 0, shareValueSafe, %source, %dest); -} - - -//------------------------------------------------------------------------------ -// An Aggregate Control is a plain GuiControl that contains other controls, -// which all share a single job or represent a single value. -//------------------------------------------------------------------------------ - -// AggregateControl.setValue( ) propagates the value to any control that has an -// internal name. -function AggregateControl::setValue(%this, %val, %child) -{ - for(%i = 0; %i < %this.getCount(); %i++) - { - %obj = %this.getObject(%i); - if( %obj == %child ) - continue; - - if(%obj.internalName !$= "") - setValueSafe(%obj, %val); - } -} - -// AggregateControl.getValue() uses the value of the first control that has an -// internal name, if it has not cached a value via .setValue -function AggregateControl::getValue(%this) -{ - for(%i = 0; %i < %this.getCount(); %i++) - { - %obj = %this.getObject(%i); - if(%obj.internalName !$= "") - { - //error("obj = " @ %obj.getId() @ ", " @ %obj.getName() @ ", " @ %obj.internalName ); - //error(" value = " @ %obj.getValue()); - return %obj.getValue(); - } - } -} - -// AggregateControl.updateFromChild( ) is called by child controls to propagate -// a new value, and to trigger the onAction() callback. -function AggregateControl::updateFromChild(%this, %child) -{ - %val = %child.getValue(); - if(%val == mCeil(%val)){ - %val = mCeil(%val); - }else{ - if ( %val <= -100){ - %val = mCeil(%val); - }else if ( %val <= -10){ - %val = mFloatLength(%val, 1); - }else if ( %val < 0){ - %val = mFloatLength(%val, 2); - }else if ( %val >= 1000){ - %val = mCeil(%val); - }else if ( %val >= 100){ - %val = mFloatLength(%val, 1); - }else if ( %val >= 10){ - %val = mFloatLength(%val, 2); - }else if ( %val > 0){ - %val = mFloatLength(%val, 3); - } - } - %this.setValue(%val, %child); - %this.onAction(); -} - -// default onAction stub, here only to prevent console spam warnings. -function AggregateControl::onAction(%this) -{ -} - -// call a method on all children that have an internalName and that implement the method. -function AggregateControl::callMethod(%this, %method, %args) -{ - for(%i = 0; %i < %this.getCount(); %i++) - { - %obj = %this.getObject(%i); - if(%obj.internalName !$= "" && %obj.isMethod(%method)) - eval(%obj @ "." @ %method @ "( " @ %args @ " );"); - } - -} - -//------------------------------------------------------------------------------ -// Altered Version of TGB's QuickEditDropDownTextEditCtrl -//------------------------------------------------------------------------------ -function QuickEditDropDownTextEditCtrl::onRenameItem( %this ) -{ -} - -function QuickEditDropDownTextEditCtrl::updateFromChild( %this, %ctrl ) -{ - if( %ctrl.internalName $= "PopUpMenu" ) - { - %this->TextEdit.setText( %ctrl.getText() ); - } - else if ( %ctrl.internalName $= "TextEdit" ) - { - %popup = %this->PopupMenu; - %popup.changeTextById( %popup.getSelected(), %ctrl.getText() ); - %this.onRenameItem(); - } -} - -// Writes out all script functions to a file. -function writeOutFunctions() -{ - new ConsoleLogger(logger, "scriptFunctions.txt", false); - dumpConsoleFunctions(); - logger.delete(); -} - -// Writes out all script classes to a file. -function writeOutClasses() -{ - new ConsoleLogger(logger, "scriptClasses.txt", false); - dumpConsoleClasses(); - logger.delete(); -} - -// -function compileFiles(%pattern) -{ - %path = filePath(%pattern); - - %saveDSO = $Scripts::OverrideDSOPath; - %saveIgnore = $Scripts::ignoreDSOs; - - $Scripts::OverrideDSOPath = %path; - $Scripts::ignoreDSOs = false; - %mainCsFile = makeFullPath("main.cs"); - - for (%file = findFirstFileMultiExpr(%pattern); %file !$= ""; %file = findNextFileMultiExpr(%pattern)) - { - // we don't want to try and compile the primary main.cs - if(%mainCsFile !$= %file) - compile(%file, true); - } - - $Scripts::OverrideDSOPath = %saveDSO; - $Scripts::ignoreDSOs = %saveIgnore; - -} - -function displayHelp() -{ - // Notes on logmode: console logging is written to console.log. - // -log 0 disables console logging. - // -log 1 appends to existing logfile; it also closes the file - // (flushing the write buffer) after every write. - // -log 2 overwrites any existing logfile; it also only closes - // the logfile when the application shuts down. (default) - - error( - "Torque Demo command line options:\n"@ - " -log Logging behavior; see main.cs comments for details\n"@ - " -game Reset list of mods to only contain \n"@ - " Works like the -game argument\n"@ - " -dir Add to list of directories\n"@ - " -console Open a separate console\n"@ - " -jSave Record a journal\n"@ - " -jPlay Play back a journal\n"@ - " -help Display this help message\n" - ); -} - -// Execute startup scripts for each mod, starting at base and working up -function loadDir(%dir) -{ - pushback($userDirs, %dir, ";"); - - if (isScriptFile(%dir @ "/main.cs")) - exec(%dir @ "/main.cs"); -} - -function loadDirs(%dirPath) -{ - %dirPath = nextToken(%dirPath, token, ";"); - if (%dirPath !$= "") - loadDirs(%dirPath); - - if(exec(%token @ "/main.cs") != true) - { - error("Error: Unable to find specified directory: " @ %token ); - $dirCount--; - } -} - -//------------------------------------------------------------------------------ -// Utility remap functions: -//------------------------------------------------------------------------------ - -function ActionMap::copyBind( %this, %otherMap, %command ) -{ - if ( !isObject( %otherMap ) ) - { - error( "ActionMap::copyBind - \"" @ %otherMap @ "\" is not an object!" ); - return; - } - - %bind = %otherMap.getBinding( %command ); - if ( %bind !$= "" ) - { - %device = getField( %bind, 0 ); - %action = getField( %bind, 1 ); - %flags = %otherMap.isInverted( %device, %action ) ? "SDI" : "SD"; - %deadZone = %otherMap.getDeadZone( %device, %action ); - %scale = %otherMap.getScale( %device, %action ); - %this.bind( %device, %action, %flags, %deadZone, %scale, %command ); - } -} - -//------------------------------------------------------------------------------ -function ActionMap::blockBind( %this, %otherMap, %command ) -{ - if ( !isObject( %otherMap ) ) - { - error( "ActionMap::blockBind - \"" @ %otherMap @ "\" is not an object!" ); - return; - } - - %bind = %otherMap.getBinding( %command ); - if ( %bind !$= "" ) - %this.bind( getField( %bind, 0 ), getField( %bind, 1 ), "" ); -} - -//Dev helpers -/// Shortcut for typing dbgSetParameters with the default values torsion uses. -function dbgTorsion() -{ - dbgSetParameters( 6060, "password", false ); -} - -/// Reset the input state to a default of all-keys-up. -/// A helpful remedy for when Torque misses a button up event do to your breakpoints -/// and can't stop shooting / jumping / strafing. -function mvReset() -{ - for ( %i = 0; %i < 6; %i++ ) - setVariable( "mvTriggerCount" @ %i, 0 ); - - $mvUpAction = 0; - $mvDownAction = 0; - $mvLeftAction = 0; - $mvRightAction = 0; - - // There are others. -} - -//Persistance Manager tests - -new PersistenceManager(TestPManager); - -function runPManTest(%test) -{ - if (!isObject(TestPManager)) - return; - - if (%test $= "") - %test = 100; - - switch(%test) - { - case 0: - TestPManager.testFieldUpdates(); - case 1: - TestPManager.testObjectRename(); - case 2: - TestPManager.testNewObject(); - case 3: - TestPManager.testNewGroup(); - case 4: - TestPManager.testMoveObject(); - case 5: - TestPManager.testObjectRemove(); - case 100: - TestPManager.testFieldUpdates(); - TestPManager.testObjectRename(); - TestPManager.testNewObject(); - TestPManager.testNewGroup(); - TestPManager.testMoveObject(); - TestPManager.testObjectRemove(); - } -} - -function TestPManager::testFieldUpdates(%doNotSave) -{ - // Set some objects as dirty - TestPManager.setDirty(AudioGui); - TestPManager.setDirty(AudioSim); - TestPManager.setDirty(AudioMessage); - - // Alter some of the existing fields - AudioEffect.isLooping = true; - AudioMessage.isLooping = true; - AudioEffect.is3D = true; - - // Test removing a field - TestPManager.removeField(AudioGui, "isLooping"); - - // Alter some of the persistent fields - AudioGui.referenceDistance = 0.8; - AudioMessage.referenceDistance = 0.8; - - // Add some new dynamic fields - AudioGui.foo = "bar"; - AudioEffect.foo = "bar"; - - // Remove an object from the dirty list - // It shouldn't get updated in the file - TestPManager.removeDirty(AudioEffect); - - // Dirty an object in another file as well - TestPManager.setDirty(WarningMaterial); - - // Update a field that doesn't exist - WarningMaterial.glow[0] = true; - - // Drity another object to test for crashes - // when a dirty object is deleted - TestPManager.setDirty(SFXPausedSet); - - // Delete the object - SFXPausedSet.delete(); - - // Unless %doNotSave is set (by a batch/combo test) - // then go ahead and save now - if (!%doNotSave) - TestPManager.saveDirty(); -} - -function TestPManager::testObjectRename(%doNotSave) -{ - // Flag an object as dirty - if (isObject(AudioGui)) - TestPManager.setDirty(AudioGui); - else if (isObject(AudioGuiFoo)) - TestPManager.setDirty(AudioGuiFoo); - - // Rename it - if (isObject(AudioGui)) - AudioGui.setName(AudioGuiFoo); - else if (isObject(AudioGuiFoo)) - AudioGuiFoo.setName(AudioGui); - - // Unless %doNotSave is set (by a batch/combo test) - // then go ahead and save now - if (!%doNotSave) - TestPManager.saveDirty(); -} - -function TestPManager::testNewObject(%doNotSave) -{ - // Test adding a new named object - new SFXDescription(AudioNew) - { - volume = 0.5; - isLooping = true; - channel = $GuiAudioType; - foo = 2; - }; - - // Flag it as dirty - TestPManager.setDirty(AudioNew, "core/scripts/client/audio.cs"); - - // Test adding a new unnamed object - %obj = new SFXDescription() - { - volume = 0.75; - isLooping = true; - bar = 3; - }; - - // Flag it as dirty - TestPManager.setDirty(%obj, "core/scripts/client/audio.cs"); - - // Test adding an "empty" object - new SFXDescription(AudioEmpty); - - TestPManager.setDirty(AudioEmpty, "core/scripts/client/audio.cs"); - - // Unless %doNotSave is set (by a batch/combo test) - // then go ahead and save now - if (!%doNotSave) - TestPManager.saveDirty(); -} - -function TestPManager::testNewGroup(%doNotSave) -{ - // Test adding a new named SimGroup - new SimGroup(TestGroup) - { - foo = "bar"; - - new SFXDescription(TestObject) - { - volume = 0.5; - isLooping = true; - channel = $GuiAudioType; - foo = 1; - }; - new SimGroup(SubGroup) - { - foo = 2; - - new SFXDescription(SubObject) - { - volume = 0.5; - isLooping = true; - channel = $GuiAudioType; - foo = 3; - }; - }; - }; - - // Flag this as dirty - TestPManager.setDirty(TestGroup, "core/scripts/client/audio.cs"); - - // Test adding a new unnamed SimGroup - %group = new SimGroup() - { - foo = "bar"; - - new SFXDescription() - { - volume = 0.75; - channel = $GuiAudioType; - foo = 4; - }; - new SimGroup() - { - foo = 5; - - new SFXDescription() - { - volume = 0.75; - isLooping = true; - channel = $GuiAudioType; - foo = 6; - }; - }; - }; - - // Flag this as dirty - TestPManager.setDirty(%group, "core/scripts/client/audio.cs"); - - // Test adding a new unnamed SimSet - %set = new SimSet() - { - foo = "bar"; - - new SFXDescription() - { - volume = 0.75; - channel = $GuiAudioType; - foo = 7; - }; - new SimGroup() - { - foo = 8; - - new SFXDescription() - { - volume = 0.75; - isLooping = true; - channel = $GuiAudioType; - foo = 9; - }; - }; - }; - - // Flag this as dirty - TestPManager.setDirty(%set, "core/scripts/client/audio.cs"); - - // Unless %doNotSave is set (by a batch/combo test) - // then go ahead and save now - if (!%doNotSave) - TestPManager.saveDirty(); -} - -function TestPManager::testMoveObject(%doNotSave) -{ - // First add a couple of groups to the file - new SimGroup(MoveGroup1) - { - foo = "bar"; - - new SFXDescription(MoveObject1) - { - volume = 0.5; - isLooping = true; - channel = $GuiAudioType; - foo = 1; - }; - - new SimSet(SubGroup1) - { - new SFXDescription(SubObject1) - { - volume = 0.75; - isLooping = true; - channel = $GuiAudioType; - foo = 2; - }; - }; - }; - - // Flag this as dirty - TestPManager.setDirty(MoveGroup1, "core/scripts/client/audio.cs"); - - new SimGroup(MoveGroup2) - { - foo = "bar"; - - new SFXDescription(MoveObject2) - { - volume = 0.5; - isLooping = true; - channel = $GuiAudioType; - foo = 3; - }; - }; - - // Flag this as dirty - TestPManager.setDirty(MoveGroup2, "core/scripts/client/audio.cs"); - - // Unless %doNotSave is set (by a batch/combo test) - // then go ahead and save now - if (!%doNotSave) - TestPManager.saveDirty(); - - // Set them as dirty again - TestPManager.setDirty(MoveGroup1); - TestPManager.setDirty(MoveGroup2); - - // Give the subobject an new value - MoveObject1.foo = 4; - - // Move it into the other group - MoveGroup1.add(MoveObject2); - - // Switch the other subobject - MoveGroup2.add(MoveObject1); - - // Also add a new unnamed object to one of the groups - %obj = new SFXDescription() - { - volume = 0.75; - isLooping = true; - bar = 5; - }; - - MoveGroup1.add(%obj); - - // Unless %doNotSave is set (by a batch/combo test) - // then go ahead and save now - if (!%doNotSave) - TestPManager.saveDirty(); -} - -function TestPManager::testObjectRemove(%doNotSave) -{ - TestPManager.removeObjectFromFile(AudioSim); -} - -//Game Object management -function findGameObject(%name) -{ - //find all GameObjectAssets - %assetQuery = new AssetQuery(); - if(!AssetDatabase.findAssetType(%assetQuery, "GameObjectAsset")) - return 0; //if we didn't find ANY, just exit - - %count = %assetQuery.getCount(); - - for(%i=0; %i < %count; %i++) - { - %assetId = %assetQuery.getAsset(%i); - - %assetName = AssetDatabase.getAssetName(%assetId); - - if(%assetName $= %name) - { - %gameObjectAsset = AssetDatabase.acquireAsset(%assetId); - - %assetQuery.delete(); - return %gameObjectAsset; - } - } - - %assetQuery.delete(); - return 0; -} - -function spawnGameObject(%name, %addToMissionGroup) -{ - if(%addToMissionGroup $= "") - %addToMissionGroup = true; - - //First, check if this already exists in our GameObjectPool - if(isObject(GameObjectPool)) - { - %goCount = GameObjectPool.countKey(%name); - - //if we have some already in the pool, pull it out and use that - if(%goCount != 0) - { - %goIdx = GameObjectPool.getIndexFromKey(%name); - %go = GameObjectPool.getValue(%goIdx); - - %go.setHidden(false); - %go.setScopeAlways(); - - if(%addToMissionGroup == true) //save instance when saving level - MissionGroup.add(%go); - else // clear instance on level exit - MissionCleanup.add(%go); - - //remove from the object pool's list - GameObjectPool.erase(%goIdx); - - return %go; - } - } - - //We have no existing pool, or no existing game objects of this type, so spawn a new one - - %gameObjectAsset = findGameObject(%name); - - if(isObject(%gameObjectAsset)) - { - %newSGOObject = TamlRead(%gameObjectAsset.TAMLFilePath); - - if(%addToMissionGroup == true) //save instance when saving level - MissionGroup.add(%newSGOObject); - else // clear instance on level exit - MissionCleanup.add(%newSGOObject); - - return %newSGOObject; - } - - return 0; -} - -function saveGameObject(%name, %tamlPath, %scriptPath) -{ - %gameObjectAsset = findGameObject(%name); - - //find if it already exists. If it does, we'll update it, if it does not, we'll make a new asset - if(isObject(%gameObjectAsset)) - { - %assetID = %gameObjectAsset.getAssetId(); - - %gameObjectAsset.TAMLFilePath = %tamlPath; - %gameObjectAsset.scriptFilePath = %scriptPath; - - TAMLWrite(%gameObjectAsset, AssetDatabase.getAssetFilePath(%assetID)); - AssetDatabase.refreshAsset(%assetID); - } - else - { - //Doesn't exist, so make a new one - %gameObjectAsset = new GameObjectAsset() - { - assetName = %name @ "Asset"; - gameObjectName = %name; - TAMLFilePath = %tamlPath; - scriptFilePath = %scriptPath; - }; - - //Save it alongside the taml file - %path = filePath(%tamlPath); - - TAMLWrite(%gameObjectAsset, %path @ "/" @ %name @ ".asset.taml"); - AssetDatabase.refreshAllAssets(true); - } -} - -//Allocates a number of a game object into a pool to be pulled from as needed -function allocateGameObjects(%name, %amount) -{ - //First, we need to make sure our pool exists - if(!isObject(GameObjectPool)) - { - new ArrayObject(GameObjectPool); - } - - //Next, we loop and generate our game objects, and add them to the pool - for(%i=0; %i < %amount; %i++) - { - %go = spawnGameObject(%name, false); - - //When our object is in the pool, it's not "real", so we need to make sure - //that we don't ghost it to clients untill we actually spawn it. - %go.clearScopeAlways(); - - //We also hide it, so that we don't 'exist' in the scene until we spawn - %go.hidden = true; - - //Lastly, add us to the pool, with the key being our game object type - GameObjectPool.add(%name, %go); - } -} - -function Entity::delete(%this) -{ - //we want to intercept the delete call, and add it to our GameObjectPool - //if it's a game object - if(%this.gameObjectAsset !$= "") - { - %this.setHidden(true); - %this.clearScopeAlways(); - - if(!isObject(GameObjectPool)) - { - new ArrayObject(GameObjectPool); - } - - GameObjectPool.add(%this.gameObjectAsset, %this); - - %missionSet = %this.getGroup(); - %missionSet.remove(%this); - } - else - { - %this.superClass.delete(); - } -} - -function clearGameObjectPool() -{ - if(isObject(GameObjectPool)) - { - %count = GameObjectPool.count(); - - for(%i=0; %i < %count; %i++) - { - %go = GameObjectPool.getValue(%i); - - %go.superClass.delete(); - } - - GameObjectPool.empty(); - } -} - -// -function switchCamera(%client, %newCamEntity) -{ - if(!isObject(%client) || !isObject(%newCamEntity)) - return error("SwitchCamera: No client or target camera!"); - - %cam = %newCamEntity.getComponent(CameraComponent); - - if(!isObject(%cam)) - return error("SwitchCamera: Target camera doesn't have a camera behavior!"); - - //TODO: Cleanup clientOwner for previous camera! - if(%cam.clientOwner == 0 || %cam.clientOwner $= "") - %cam.clientOwner = 0; - - %cam.scopeToClient(%client); - %cam.setDirty(); - - %client.setCameraObject(%newCamEntity); - %client.setControlCameraFov(%cam.FOV); - - %client.camera = %newCamEntity; -} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/images/AreaMap33.dds b/Templates/BaseGame/game/core/images/AreaMap33.dds deleted file mode 100644 index e01982a94528594a375ae6e61c44780a8e1c0b68..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 109028 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 RBF+E+002ovPDHLkV1nj@91s8i diff --git a/Templates/BaseGame/game/core/images/caustics_2.png b/Templates/BaseGame/game/core/images/caustics_2.png deleted file mode 100644 index 99097fa0ed112c28958363f2951478a0955218ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33963 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 diff --git a/Templates/BaseGame/game/core/images/checkbox.png b/Templates/BaseGame/game/core/images/checkbox.png deleted file mode 100644 index 46e0ac959fc26d224015f316df050c2f137af4d0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3943 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 S3QYOT0XMIk>c74QkN6*F=2BAt diff --git a/Templates/BaseGame/game/core/images/group-border.png b/Templates/BaseGame/game/core/images/group-border.png deleted file mode 100644 index 61234ae1fb3dee29eda38a371165d36b060ee426..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1273 zcmVRq)0SqBM&U{ zK~RE8k;)fTv@rNVFsUphN-&N10jmTOk|LETicKV_m54TpVAK!`|L<7|`4E(7K4ARB zDus5>J(HaE?!4W7v&qH}czMI@+&44#&Ye5=o}G2_O1ZzkpGs6d@8oj17WcW!E!8%I zG7SwXm(AMBn08BdCX>0T948-RoKK$0X0t6*Q&aiH#l^fexw~LXm>2UyPMmS3yc8^% zPN&txvs=#V2iKgriKmXs^9tJFqjWWIBOj#Opr!-61IK}Xx1-s?{L4G0_&?_ilXv4x zqfZ_btu8MwSK|-wsQY~v)cnk(&+H?8J(|C{sz$fn!M^&){#~l$>@n5f-deC_;MX2J zsxZHFtA)8SUGF$_vOr$N_B~qGz~m2~oD@4WwsorNs!FYtyCThVSEZ(BX4T=g^Lm1w z!FRq%(Y|`AS3jc65Sso~f)<#1w-6X-QZF0;z1&IJw>OAO*=w$5nIM949%2g^Yzljy(oWy)Hf= zKP~7s_`nZIkS{YqF~l(je$;4#Z=xBAo(3O1_wqgCBii5tJte9r;~AA?zGq4`(Ts_n zWQL)#a^A!gm6r6qM+nP?0Sc)kNm@4Xtw-=SGYrxowl6GaQ(5@5B&1Y;X$f*x_i`5k zxlG?JMp&eYe3Cfrf#}H=#@X;~|BtO`5XzBM3_XQWv3X-F3LkUd8np$mW$;ZD@}tlb z@grOWzKMePX$!hz`6y0z95fS#p0K!L8Eqx>`_a=%75$H%65feFik{-gOB_87-@a&t zo=kbNraT|vFoAMIeOeI8_0#*bHBgfWlms3M{F=|;vk&HAk-V?7qf70j+dSQteXuCB zxme0WXRY7zZQiQU6W{Gki*a6ad*$6z80sP_3%q+`TtsI83dY1J6eRh$8vuYoz-JP{ zd_mbs-aVmUVdndNBq%XE#kqTuz$8gP5_U;MoS^NwxEOTzWZpMPmn%SJ z?(zSC4+0292nh@kvId`u$uPqZCPNED8bgi@LmbC`Ql1P|ln1?_pHA~@{Z%BXuPKfW j%4_?bDUt6}KLr>7B{DrC{G$C100000NkvXXu0mjfaJE^D diff --git a/Templates/BaseGame/game/core/images/inactive-overlay.png b/Templates/BaseGame/game/core/images/inactive-overlay.png deleted file mode 100644 index feab83209cc442c5ad8dc73c2b86e0a8115c4743..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 131 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE;=WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!foRZkbkkcwMLfBw9D?8~Obq{gPz9LVg>D`Q%4bP0l+XkKL$W0) diff --git a/Templates/BaseGame/game/core/images/loadingbar.png b/Templates/BaseGame/game/core/images/loadingbar.png deleted file mode 100644 index 34f5944030dce5a174233bcef11b7d7210bbeac8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 635 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 IM6N<$f@#CI-2eap diff --git a/Templates/BaseGame/game/core/images/null_color_ramp.png b/Templates/BaseGame/game/core/images/null_color_ramp.png deleted file mode 100644 index 5f5a52186eb93cb7ace739e645e5e8f8e6b8050d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2843 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

y=B0vFoY*eFT;806|)ERK!%dbrTa%1TK9Bjd-9 zr^}Zwi-N<44;PRUD|p8mJa{mjI(14AQ>RXy1kGcDhbtX7ZX8XXJXzkw;#?xT(6?{j z3J3uh>Ba9w{MtcKu%x6!T&t}`aS|7W2Z3^ccTP&GivWbIUcH(oO`0Ui9XxnYavbA4 z%5?&-1*M?e%a<=BO5(h$uP-kz7Yjmkmb6|ZFE2pFMP2CIHEU?vv}sa=9LG41awk#B zq7Ia{QxaviS3x(c2?E@105;E zR9{~&)}l)PttOOhZ4I|2jx8a+gcuZitEhD4$`!Ms zqC#Rpix)38j~_p7vL`X?Id;V^)8uz~lf9ey`0?YYbl|`NbLrBhsl}e~gpM6MmSaf# z4vshyr^beQs(JmIo;`aOl}3*qEj}EA0K<$KpHnmYb-2Cy`a0>A>greGimhql#EIf{ zQjw&e`c!V3Oxq|YTv72CD&=tqUmt1-QPA>^J$LS0?e%#WP%j>b2t4qxk)&k#^5x0s z71t(8Q9LZ8M*WU3_*)q908x1nc$Lp*%%DMo2E{4rrM;IrQC4khIDr8hqD>W0WMK?v!wXo*Sox6w^%mnQ(TC_-zKFZS8^{EVS zw8ffyettoOj)7h%>FMkg2ntlMeRelK&RT}s7JUfZ@!Pi-cVw4ae$%~oO))8A$|GfAL#3^{}?&;db3pOiK3Vbm7-lsLCqW$rzmzSf~tuG+U5+V zVXEU)6!6+MGU2Q63p@-Ii4Dgv|CzlIPvV?FXa!eP9ecf5D)rhdDqD7VZzm^s6_5ed zvATFL*uvwpQIcZas^e4?@Y+@sZRN44Hk?X#VqekwO{wZa04bQlkd&h8*z3(wspp$j z5&tR*cDQ0W=(-9_a6EL`lmL_h1w*(07|LK40No;%f}xJHp|J7v=~MI2p+k`!3$Zta zudn2Hr!Bl(quZU34PWn{l{=8Jow`mDubt{-#iH18 z8mX&%Art`E>G4is6t7)JdqnF zTQ{Ikk}k)E6-v_O$=*DXcE(HIdgj!iH}mZ9Z6_!B?Z}atAEOE->2fHjP?9cB#4^d& z^)Dz%_7`Wmoo_5^VDG1sH4sUD!e1e9l7Sz8obiXr@Qttc&B~q5qToJHnKFgOefF7b zTeB1JoR=+IM&-N`?Y735a_lLxXE`S3g#FBjOTps0m=oerh)ZQ9_7odyQpbo#sU70F zm=oerUUq}0W9o{4lDL?YWiHUgoDh%7mP8bdjX7E8EM3eA@u+M`1U>0uPFD038*@TD zDq9lJ#heh2Qlg7FAs&@23Fu-@h({^W#hmQEuahaoedFu>r|5?ob5cVopo=+Kw*={8 zPKZY#E|m?@q9+8;7A#mm13vml>+7N9`t|GSHykF3+Fsfd5jlj}TcX9f=zv}*>dx>;V=&NpN9e@jtbDyKdCUjy1xJXsWE znAx*ux2K+D`2Jx+ck@Rk#fmp?-lW5a54WpDwOtRsGCpq%!8$1@@9io6?0Rb#Tc7lk zCr=XojYoS*RM+E^-Kx7^y?RCS=g$}25H%UW|2(2S#h+c@o)&Yv_kRJO_n_Zf_&8bs O0000(_@_GbJ<_dZw^Q+&I7EPrEnI(eqE51YbYz7T13zwEE$$n>MSVv_3!WR xqwIV#4BRgm4JXvHMKX&S7St`!IKaTf!=UB9TBWi;$P?&J22WQ%mvv4FO#lthVzU4M diff --git a/Templates/BaseGame/game/core/images/thumbHighlightButton.png b/Templates/BaseGame/game/core/images/thumbHighlightButton.png deleted file mode 100644 index 9d83b75f31b965b79ff082e3a0f6e37e4c757c1b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 778 zcmV+l1NHogP)^%4Aj<$I1_}WqRRR$d z1~4y>8i*8ofd!i&&^88q;$hSbL@LC>f3!$o1Vs!3BNnyT#Q(FzWmcoc0=>O348mYE z7Di)XG#${gULYk9sZ%c;*}t7K1LT!85hAQlXK)Rq9_nInN)!ayOp3q3h5+?ZB@mfF0rU0$f5zPxzJM_-aIs(% zaacePd~O^y0Gb=Qf!I}_n|uR62^f})T}Q)U#D)ReA_iudz%LMg;eTdyg}>q%QN>TK zMd@&GqN(S^VIe239t#(mI2R5BxNsT3gC@>{!vG#!2JoSY^WiXn50?SFXyUv$4B(}@ z3n;D^SU}}Ft66XpQhe_P#$P)N-;>uu0ogpTEtG2ypD`}kb`^|A zTPQ=eg`y=V3C3g_aP84^23RtV84ZIG8wR5-l+hN-XbXi3Efk;Vaufm3qytH#c_6Z< zE(Ia9w3GDg3<4Lg-UZX@LvA#W$v3*3@#f9jjG!4Dq}d&UEfkp8X#0Q~5|tAdDOXK#LK`1pomC0NWAfc{C??-~a#s07*qo IM6N<$f>^aj6#xJL diff --git a/Templates/BaseGame/game/core/images/unavailable.png b/Templates/BaseGame/game/core/images/unavailable.png deleted file mode 100644 index 9d818a3765d48243dea04cf3d9a43e54b1b74bac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26528 zcmd42cQjn#+b%o>(Mxm^glN$_Nid?fAR?mo-Xe%@CZd;!AZqk3N{C(ti4sJK-lIj& z=!RkDY`^!9bN)JKecyY&wZ663EX(Zu?7KbJecjg+t@~7!jF^cS1Okz%t0_GLfgr%I z5D*~&@Z-d9;u845=&k(HTi?Up+t=!~9Z12}!`hBb-Ob9u?wOsHt-t3_yT>4q!xMES zh39^Ad!LE2XnJOG6%OD8HZ~Tb{5zrjMNjDBm^itZBzj8~w0}s!C8{%ikWkyiiS)S$ zR+sACPT?q#429fJw8d|{9D<6wY6SMy7w{++;`w^_i^ZN{@3RX@=UzE zyi(;r0s;bNml!Xs4DP?o{olCf|LINtuXyTzdHv4+IQc(!{r@B={`08+Mo|6NQfUiK zG&MB=OaJ=y>;Ko5)`hls5`uD*)>0m?_)lIv&QT->Jo<``Gpyis-^Bd`^ArOMnMjsi zAlXLCl**a*OHi24d5I@GXt@wWq}=JQsLED5@tr^;G}MkTw`2Z6Z#b4#z86zx-yJnz;G8Im@u?n8vqFc2MTP2AdPf2;{HrgO9JBUfM7j za$E#0O?6)EZ2oMeQ~cwwB5iQc{JP**)qNhp>0){>*#IKOckdY_=lu`(H}7kofy98i zP-?a|_cmhkq$4EGXcYI?>2K%sSr0`mo*T z3d(-Rox1ksL5u|C6|S^ZI(=#2LqG}1y(IghxW+`UT(s|Ts;w8iQa7QcuY(#DDE|I@&3%DQ+Do* z>zFtmrQsQ&|AqKTSUQV%kcs#fijrXhr>co*pQPE6w~+#W>8>`9QRy=LAtyq{Y> zmGdnTseR&hZZ<4n1nvaECVQ4+zZJ(&2`lTXGlGk9M+}*QEH08*V*(u^p*ROoh;t*X zUJFry&J0_gBy3X35DcZ_{uj@66?sHa)WJz$H5)=xQiQhJ zRoJHMlY63;1iuN90&@w}*Zs#kK5k7f+QW`NB)jXxV3SB;znf1;Hzj@&T0#J0N0S*- z87$PZ@s&t@A&+-ezYU|kI*=?yPmg0;(3{_J)n^xju82I%+>cyrPbsxlvo)OvKC)|1 z6W030Sud$pt5ui4{2HFavksVRb(;HGrOaZp-v}_*-FjawsztKQXKE?!6q#STk_`QKL}MC$U;9= zgPx$b=+b9wM1}#fh{sUJNyL7e`@sc6;(*cw>v&(z{j2Qaixr6seZl5YhV_##i0nnt zbjn-QXYA7c6l||DmMdJt+R$*S?$QvFAPw)kAUzJgZ<>S zFq>{%xpRHI3Ri1GFjF@~R5Z^TyW$8NVGEJ4GG>wvFSQg|IH<0(KQF4Yvpiu;yLe}7 z+RnwrCBcDCVD2)U-eT`~_z~*lWrMd9>U4Mde5S@q@qA-2_5A5EzSMHiF~u7uVav)k zdB@S*schN6kec19)(#oVPK0l70xPcA=1k?+!j{pUOvVG!bZDkto+OYA9~O*nQGL?8 zA~Df_W%7}#M!ac?6vl(KLWbz;>!*SHBUgo_wn>QL$H`S7s)d0*nO}J5jHBmXj+R+y zsiGmmA9kQsJdPYo_9J$=N;9uR!-9~^KPK!U2J2qN0vdZh=>9Aj*3aiBu^4P{89%Om`~0TY3=mCQ}@& zpeRJj#U{$A8{P_eR)T{Eb>ZhUoi7Du?s`7UNqcnuQ1Kl~MjTBmloqFc(Mpr?_uF&$ z(|IkGTt7JW>cT|+bV7e#{&YR*I+fq3)=d`fC|bbQsLJAR`)AV7Lg4ajAM@{E<-4Ia zdZOeL{Bk@er2W9}T^H#(85e8>U3v-%@cp3HPjFKR5JWrzYWmEE1`Fl&cs237`o(+a zgM8INY^7jFl3FnP9ULohaE(b%#4~%yg9Tbjscegce_r{$ed-(~N^luPAZE5LlF*sY zun%Me7IR{$Ld>pWr?*4#NiK)eont<9a$yrixms;{$V`0Ui`wW9t4!)<}@%!_( znmKIw+x98zhCQ^D1Vjp>r^3wiYdbX+gd6x!Hnf&#Gy9G@$YW6E?SV*o;&ygy$OkZ? zAr1f3-7Pclim#@~!%>LHCMQ#5sF#-R*9*o?wG@r$Y1<4Pa1iAJUUzFK(WuiTFv1?P}Om{ z<9UnKd(^6NA?SFNO*+ZMcO#@p!YQ*7EzZ60H}}Ai?k5PgNgr$@UZIow%=O!D@?7@u z2%LQ00o9(0I{v9s^&w$$0xm4^N;;oyp-00P-_J=4M$iJ9$g?e`g3t<}0Sj$O*yb4K zt81U{7Cf~rhYuJS2DcRz*;yK1<_!dZo$&rOt-Vi7;?fS_>L>JzaD|y@slcLsTSfG? zfb8y)i-K)Ixv@%E&edY&aTz!3oQ&i7W$fA7TL$s%bdX!A^#cFvyRs@zr1?S59iV?& zDD}90$T#g5+k(0=i|bsh7J>Wqt?>P1eezxBRS!{!DvRfjE-{DUJ%@hKOf5Lz1)HQ; zp}@8_7qDfT{UrRMm1jKN;b!#5XScGEoTA5~IX()xM9Zd8B6Idk(p^0kT$ZrAh!e7A zy1YMbsCPIWqZWIO=~}ZMkZ)rx#J1v}&xhkIaF>S2YWTj(Egkruw~3!6CUfX!B@Wt; zhv#u$ekPqiNDCFvckNFqc+am-s|!8}m`w3$k?^s9 z)bD#6s~tR?`6+JvZ-x*@_o4N_%oa#(GPu;6i%st;yt%(xT^$wKy(|!S_0DT{zp`;@ zZuMwT(52(#qvn~%!~oWrg9JZ8`s(0&v390pCjiZSz|mYVH)82k2GG`%2$;pJ&=*MQ z=F^`%2Xih}j0Ge}I^Z1gPW}t?M1-`Xw{aEDdDlKJrPd|L6JA6Lme8Eee zgX9X$*vp|xW(p)cCM)Q-ItG6hWOmicyXqkZO?2t8P6m?P>^?P{_ll7HEm2A$e)BfJ zNY%eX7iqT@RAPFy%)rG_jYIsf-=2d{ihtP6uDowibjd+-9(fpE)Xa0WvASEW!{^-^ zR z`IL!=8_U_fipf>>hb~rC#73aZKl7KmyLKSg?&XyUxM^38`qg9$nO&4c+L?#W#b92r zuTEyeEqUb82j$R`&jC9Q@9w>8Iq;?CZG{Sh0c%-PA$fnte!F5+czS$^nfG9|&!mQ_ zKdRt$Tw4I$b)5O)12Q??yHFq)E_1_~BK4JfEYvZo53ogvNxZl!(-jN#bv3XN8_(V` z-ukK*!Wi|A2v|717{qubA+_d3z#>qWZmIB_)>tyv^TEEDzZK;79=mAgKSa3!&@M(M#)cSVNA8KOKEufOtsS0ckLM5 zNXX^*HRF=u-St;pIP8w0d;uw~mMFMqr6a;Meg6td0BT87?415;KP1MRXj6iQDcfiL<;hag> z1zESbQJ3mwd)6OF$^N`h2l%cDrY{Zg(G}6KF8ZHTmN^n?z%h!0pQ#m_`b;voDZyH) zbd}XASOIs@l?~G!!!mxjR8$*)_dB4&H+Kml%Iigt@_`QB)i+bO2oXVh@SKR!F(dP!e~rni6_K zxT{lX%bf!LU@;hhmo=8HC7UBC?#Km+0napSCzRuS(RX>{8gp*pMinw%zY>eSxZwn`=5$>}aq6`Gga@ORzGqFe^ ze|4}Cu7;AW)N}dG^v!fML-UYA4BWH*bi5FUIoUo|c;^6Fy}Z^oLY$T3=*|7CTED=X zbwZAk28XjA`yYO|r?^C>Y|)%jx4JT+tuYxMF|DVV?Uoy3FDuAmt;h(@W}8H3?M|W z)o_*!)P6YYLT^R*L1zt1z)v*#$ezRz{?oEsH7`+NfXnpgxVXig^{P8`8HYWu zBk9JyS4PJsD2`1lEpnYDPP-KUfnMV@ID|J0kr}}!W2!XtG9@Y*D&TAJk z%T>h6tK1~?-H_`Fi~W16B~=1ORNAz-H1*dHW4Cr21#NKi1vm_<)gzTZqzrqFsczqx zGQoxPraN@J^qaA##C`llbHT^HM0f6+#QR|+e1zV8e*H~%GvX`G_ohOdt0~N(kfXETCxpy_=P7O3kROTi><9jdMtOK=EIhb zOfzqfMdq8+yf&EF_*n&!X{o9E%@t)J`Yu5&_q83mqQ zC50`WWzmgAo@?KXqZrUO!A+e^ zDC`M^jE#hI!B7OkE{<#Uo}AmHJ%ogPP6$-{`I440PV`9r@CS7&FJzgH1KTS=xgEqd z;me0YI@JJ@31)M<@ultzK3o2GknEsW zJkx1lM5GfPcmTk)ZmP|HpM3gZ5q&jpt%YzJj5J|bjBI?{&n$K7bHuuF(dLY2O{%ai zVYEyBVfJqNhDcP%@1xEMd`l3hHkzhtP^i`QTMa1*X&uOltCO!t|IV%P1C`SePkYNL zdF+@x-?HKh%&pZNoqLyV5z~#lkSdY@ylan7{IJ4`PD{d=S;VNT8uf>wF|fiXZg+#u zteOPK&5F-}+SB`?*=zG`lBt2Ko}^Qh31%kQBsK|Q5M$}CxwPnloqkZZHk$E}8Mb(V z$^5Z!l!a|<%LeP_2dSIG<7cD|ybn=%RHGh>dQ#CyuB)9-sRhtlQ5}T%Ab^0CEMgBf z`MW(bo-y5cS3!`j&;i`tFV9av${PDy5OEfAtfF&^;Tco3K6v?fQy!I^a*h1cCm-?+ zh$ZIR?AMa-qB67jo|1eaz=)X0Wj&M@#^+KTwHGFI3os0ICII%qx)l?LoNLDy?+C8Mdlb42kVBY zMst9&LoT;lm_g~6xG~(-NRU9jN1YPdErLg${VJo>jY?(+C83bsNb=V&csUd1E?o^Kz! zD;DAbU{ujeQJq7m0#{eFY=J#W&5kL8g(Ngu`oj+uYoExXT(nZF4bdtG{xkKNT1U?ov-fJm-W zedmV`6OU_mC`(M!iF+#*04HZVmL3^VVtwCTTpz#B6kOt@LNZ;rjBrzlK%G_ChG?R+ zPr>Cs`?)6x`uDeN-Wz?w7rQ{)BPoPi2J1`q#JF zyi}GVki`9T<=BRb^I@Hb|C)N(GX_Sum9C2WEoQV}w|Fu@0B`e=h;kqb`qk;xFdSf(V*zgCa_+9J(HVr`f%iDec|KaGUR4y2anN>Yq%wHBl!cVW96 zfWn0lQGYVZhfjMWEtC(ZfxTG}zlaOQ`rxHF7~nXE5JA|wTP!cnslX$$=L=Jz-+(~N z6=NrXR0Fu@u;qZy3#{~)i1M#`C==ax@xH`f>|q~kbs!E0&++~p%bSl2h=Tvb>~O*O zgopU*!TxSMR%4WRJl7L7cZ2un1x=eitC{nKY5@&?u4sQ~wQty(Vv;=Dl;?FDMP`mO1sjT_{JN0KrgxieaO@a-K}v<(IbA+m{d zBdPzMlD=&@-5%e3m&l=7^=0!A?lW7v#C}~P|AOEL2$b9>Iq#17C-^<0vTDNt`|oVt z_dnFwCqcw*YBnbMYbO&DSUalHy#12nbm6C7fl6gVRQpf7b%7@qWueIDTre*P=XcUc zh=Ln?-s;-nT3>bP=3y$MXeFiYODzt-{13kC0GuP8(Un2PhzUUbZA>t`GZaO^ZT&2x zrpP`FUTVCJ>8Q|W%p5|9q?n)}og;T%brQep-xT125e9}ME!ND=ZFa!yVT_0akDawc zpn+&vnjQsOp5}VBs)K|IDj*XOk3{$RxI@Y|0CX?m(tpD@_D(=c^K<44zmkdF866)| za8*8!73!F&TY7Xy3zI4R$znzy7ZULvDQ66;rXKY;hTb9%YFsJ+)5#xev1(4}P_Y4i zc-S9p;k-yId>X<0#?YRCpAP(>ampA$(9Ly~INf$Mzz3L~Z&R)eF7L#i6Oaz7r|&e( zj`#VDx!K_0%MYlttXJ@)h%(!!Bw>>4dcf!S-9|UqKlcY#IJDH@+{=y$w6( zV!{;1K8^*Np7Oya&$TH4uzoEz1H&%{Eg~8l8qS1$plK0MN$0iH8q`uu3g50XDBx`G z;w|TIdJ!Ygy`A~L;-V2MY$zWAhzcBxYVA#V+sNfgZNuL?A85VcW_-`d@rvV>M;QNAuGsxo5py$ zvsABO%6{Y7Yd@C5J`m{nCod#s@e>f$3(a1)hSJ3xOnUIPfD!}|Uq$svLM_)lcBd+L zvpMh5ZeL#4*+bYdRkDIiP&e(jXC)g!pwoqOsTb8t&xBVf0LPg3J0H9we^^?qUtkW9 zcE2=e+y+77A7=uI0L!~r_-~}hoh}@Hwdt#(bx*pu|LYPM*==rt@=Y~Rvpsf9()sBt8uw3oM}0w^tt24<@;&U zo~r}E&OYH9;%!9fcVU+*;kBNp5sI=7xlv<$JO&!>i~2p{4_?s6uW;Ab(nmM?j8b+~ z$MI9wQ-9fFqU?u0&RziA_8lgF{xOUyqj2(uDI-b6cXXE3uGu4QTDja+ef7qH7GFY3A$RTN(a`Cp-1%Nz zFn{QBdT&7^%41YQcVPm*B$T(T&Yr8T;Y1YpXwt`oS!X%z8X%*#x=ENr+(F|(Cl3H- z&1hN>k!lgr?E7ThBS6jz;4WXw1bv~o^1lR%dFQ-GyMbXH<2bFYaSj-GbK3ZaR}9cm zE}Z$UQ)rI=-}Dg1n4yQ(5LdDmdF%E57D2^U*ICg;(7Lr2EbCrrU|6-%MP5T{;nnH< z0j}fZXwb(j>E0Ic5t+%{-i@ecAO>p_4_odCmb!6)&(~Z6vFF7EkG%Bv2b3L&P0n-U zpJ^ksPpFlfSjOO5IHcfZxlDg}X1D0yCL-SaIAD&K3A`3$bQQq<^*{PYf(O;1#z zAzA*0=h8KR{^3gp8C=aL3s?Ye$=Za&t{9o~tEnGiy3HvZwYR4N31_~*uWTa2`j-u^ zT-@;3*U+aY$e=F#B+7}3Y&%q<9%`e_U+pV_1ForrAPu&FA6S4t7d;I!jVLY(xz~q`4%rt$0wqM`^dvit-^tU>>lSO; zzEpcd)0n*BCtG6`JIy1z)71b$w&;5<7S*x+H5NVnm^zpIP(L4Mnv2=TR1w1uTF&P2 zN$4gdpp;kde-q2$zXcu<6NOZxgeOrsJ^~7JPSwWyfu7JESyR4nDxOP3nhazv;e!17 za#FT}${V^)+MUD2Oi8uDq>KY}0|J*L_~%{CJN%(KM5~qnlZhbS$zR2qxb3$o{;ViIF`^oQ5-3$01 z8ccFCxH{7=6QZ$Rc?T8vh?O_X!RM2~y+8l{{fmoQUzKMM0j$2^chGgKv0hwUebr(J z5`?-srk@JP`13^-yK^|<42~m!o#CdA80MOe;W*!1g}qFrOZT_Vag+z7tE|yj#Y97n zpdys~?dw5p!G{K@9r#a{z`Zdh8%nAm;O3KJpze=gwS^9^f6ZPpVSh`t#qeHm2nV4L z3{ICWo`^rT{gojhOUeb4f(Xun?mdvQ(gmQ@;mCGR$befC?@{XfJ`!WLSf_qN(3l7# zJou1}Gp>obk8Wa+^H4*>a90sJ?*W8w=d_EA_ABnk4HrPEo>~O;TX)_xS4wPW+A&+Z zT%F%~G7zxFaVGGZYY5jN#rUge1KPdhE`|eh>XKM&5Q@P^rEj)+!0#SU^V-pG!dl={Ly%rF?H_wuhgjK?RwAd>Y^i# zRo46r&?ITtxkvNG-^IFDZ7En>TU0glRXPg;P#f-wLOjQilcXp6^XJ#bI@DPTV-)zy z2|REoDMW~t-QCW4(YsmUsKXmVdY0|XDGpHmqO*Dr3jNmi4-P0rs>xcf*lC{QRoch;Hc1fsN;@n5Tw#yE`+d!om6g}N^jPv!%!&xPyA$pwux;{(3J{0*$vdXS z#3#G@N;atP3p_JfQE7PTrcjV`GsoU^YnZk7#&=B2bT0RPNBdzJj=N5Eu-ild%+R83 zN?Tm+cdXZS$0vIVj(?^HEow1KpQxf{U(+Q@(Q->N{*Yg2DTCwAW*tzRE_Z8R#Q}4t zk&Tt+b1CgRdFIp|>{nEW3F#&fz@=sNNZTw=p63J0^WpM-cb0^JNi@K@9PEE5f8;6> zIpK;YK1RWeJ9`n*i2!?0Fo`=Fym$j(ZK1`A`uh4vb~G1t?$TeaUbekDUmEY}O5R?= zG%baHnGT;PO{1E`MB={r=E$K~j+#e)p1=>!Y0Pi!pq@6nYo&Aj2jH(7f$~(@jh{dJ z0@nQ@@7j69o#nTB{O%To`L8h=PJM_=pICJU--Tay7?EaO?eS~QUR0LXaEQxv)gnJ7 z+Fg>GO(Y6_D6=A$!KS{K`OJNv5n+MbF;v{JRW*`n01(kMU(BD1>9?$2tia2jQdjA& zLszC78){7ctS9M&w2-hiezbxI#2D@q5GLdV1x<{pBD0DFX^i-NZy;V3&15)Nu8G2N ztNPp2Fy%KZYr0po(9z^4fPP7K(qm^A#icQR-P6~&@Olto;?eHY$Zy8ech`5pYsa6$ zBV{>7;2Kpiu609(F?Cx6?Pc<2fQndh9SKxW4f7d_a_7wsG7&|+uwSL6V-|jUXSkCR zi~isA8Gx`A!D{hJq0SwWOo|YPEGB;iDuIY2(uV4=@LRC8tq0Y$dpX+Tde_3C98%fb z?C%6HSW=FEjYbH|PNhRhZ<;4bV!G!+E`0MTG(2UC;21{2Sjha-NBiHxYpd&GnaiW1 zi3=VI^f3P{48k7gSbVG(x}5>4e*~NDc0{Jp>c%4$NS`bwQ*Lt;A>ASD-8lw_sada9 zqhrNa5~7eyt9^wy5j>!{m#cj39k8W3F}xN3sf;hTDR>Q7Q--BiDq=4Fwg|YEL02Uj zpw+CjVLWJ!6V}-$9F!eg;ZdzB*DZfku_$GLe`k+f6^eblabcj3D_)iVb^jw4z{wLj zofG{AE^$EumqPa7^?kXVtMy%KF0HMhaXbupsL+IKOc{f&6j)SaXf-uO0?Z9Gmt8kB z^za8Fo|q1M0@qcKKtc5_AE@5K4gWFA%bn9U4bbJXk7N5#g-JTu^h^%*gIYYw^^(*8 zL`1}hpvp=b1oUT~P*avcg>9j8@tr?QvVI$s5H-BX;pzKY$SU0rX{%oj!L+CK2yv#` zbpW%MvsQrPRmGdcDu108gNRa7+JahSh+Fq1iYr?$;VeN1UHdnaR|jC4lKL~c)b@o# z$ah2yS{edSTD%Zt^o z;Dh|YAdKZ*2TroxQZf!pw&?cc;xo~29PqZze>i#J(J^kK;ETe%x4%iXvZN0u0dW3h zFW(5XY>!83glKcls+DAisSeY!)qw#WgqOTxBg~PY_n>A1#C}s5b@HWAVuYm z4J&45?j403x(6zcnN114Jh_1J*erzmD?eJcR+%h%$Dw~~aFY0DwwPCE|BGpqaQYbl zJ(msot}8NY&aX-I9$JKT(g3h@XCMD0LQRlh9Y0{I1NNaU<$EXeZ4w_rKzPKf>(q{u zq8`9c^Z(3Nq@&YTOstZ*DNFzYEg{pCheurJ=tLcN)wCAQ5#;3b+`avD>Tfrf z%KJObudmRDe7&gV&7F|z%XSxO!H_2^<&KcQ!=L9dWAJO2R-oe}?;r5)s0!L#@M1+x zR!j#3_iAyv*zaIew}8plBxls9*^e(uSCiO&-A-?6wjTMYfO(G3V%$0*Sc?R?mUpI} zReb5ie;A^h_z`U>#k^6Z-{-I7Fnh->{DfJufoG#Cm%m>ds5PsLu@(GrYgjy6TvSOg zZ=ZZ&5-bcr_^BpbD>~ib@{4Kn>p{-yw%?dZyTJe{=c%o_TX#=Z-`-+DUjlt##DncTd^lg=eQ1nPIY!NXinvt~F;h^97mb;mo4*XZb; z4bU8IJ7gV78@j9=)aBrU-tV0elfrCUT-|P$e!Q3Oe8OsTALtQvE%aik#lDtx@(w`& z7WWbED*OhM&8Lumw1=EHeVUBY-RBUD>2q)0KkNNb@ID|zQxJ0pes!pmz$%Z8{}V8+ zk5fK0L}h+jx8Gs~cvXF4F3AQ*<$KgcyhCkH1D3&$)`rA#{%Q0Ljdo%##cLw?VL$L_ z!Zv34pHh=%&N$=*f6A8eKdQ?^1A1k}lN`fHP|VhSlhA>i&X}u5KIn-A_{lc0?({=L zXArv)$movGsKTxG3EG4LcJvb+Fmnrtoy+pb$U&Aja^6$Mo+5p+#d#pP@7u0ywJ(_A z87^@*lp`7p>Th8bu5_y&@h`m@xL`Q0LJkbe~}ejhCe~y${1Ow_6daPuvFJJ0By)6#+GmO%385c>{CI<3D)u0PE7upbvE_<#b~e+~L}x0oF@)Bm1Uf!-1E*n?a8#k&FqETq6sScxomrO1amBWrmmsXve% zB3Dz9K`(hP$HmNg6In!Tu+i9?+_0PdU9|C@H{lDpEwxylH-411(^Gw47)HFy%(e%% zJVi@69iH!vujF1tgg#0|4)r5kqi~VMTNX;OAe+=n6Yj~b+nxd!NsLrNNT>Xhyc}>Pv1-DNo6QTk_TgAsksIJJ)_sql11e4=ze}7X$|Sl z069Sd0HR({zH5LZ^78s3I}mG3iJQzgXe3g6!MAYo6-TrQz^Ku5EreV`#}ws65qPvX z-^V#_LLITXH1`3YM@5ln7IAg4nSb9mVajV_st+yL&Ot3c0`VXx!zK3!o|q zEbRe+u3|i$zqED_;Pm;{rEwj>m=13Ko)AD-9*bN;>6|2h5yQ;ayOklI7T~sa54HP0 z?oeN+-Q<-cBS>D5gsqYEDfM2-&|XxNOXo%tksFP2C=ps%9J*qwfNaKIZfh}{GIju* zlbF6on`eXa)tWO%BLrFq#L+0e_FJd9g)@xL38?&_f-Lb~5vsN0b0r@eAhkK@gjyuI zlsO1P*_7;5!S^!|x>s&ouqBP;Dg?!M*G>xfNrCDHA$SKepm=s};eFVHlLj_jdLBr1 z3D&I#zEl4mZ39BY!M5j?LxPz>yARiC`=2Efrq@hEk|zkVk}91-wYPCGgfrecA=ro>mI`}lJAfMj@VZA=T-9@>Wo0xKyc2{laOD6F8SENXm)G3nteMDGh zCw1_GfERZv((O@kIr1n*{)RMC#R8+HM5Ch}M)216j}yUSQP1WYB?aLX5^?Is&~JBv z)~tF!jlY1PGns7bl_4yPsAdB1+jcAgugahAxq`Xvntvwrbw1<9bFTM1Y@yZ#SmaHi zvsRp7b%4ZmS6k5AF*pNqt#>i-=o#k-*k|5qb1t@O#*eqboyh zdKbOp%IzUxc16mIq@_j(2x|l|QID8KM62FC6|V;~Cz@&3R$K6%j4R_56Kj#nT-g7( zQ#s5c@QV)N$MfABij&iAb>J+*wR}nveoZvegA%*CcGFB$%DQ+6C{1Rnh8aO7bh*FD0$(-zW&U#&2eYRRrlbk`udZvZU+^vb4aMwNlV!Us z6Za!&vxn=ERfg5(7l6d%bbADjJ=Sz@-}s~loWFv$#vH(%an}|Xy;2>AS*9P2XSffe zW6w_i@#igkvW=p=sRFWMZ2XD!6Tw0=JHL6_&H$d=WqfF7k-GR{__rRAb-|kydqsXm z@FbxU`Vi1p^m`_8-PKct{vl~JMi{3f&Pv{`rI1wfUNpWb5{hc0f%`LO==jSIap9@t z1U#v4Y?!EK`kd@N4Q}Xz7sn;y z{CR5IeSOJb$_Oo3qS>2SyZuB}mgYY=EDHB#@FhWKf{65_I5_+D!=tX8_5+V2$*9ZN zRaV;|TLQKcCJ=CfAg&WwXoKaPneYB%o8CAxVwJDH1vu&RS%;h=3qan+Yuwho+8FS+X*Vz}Md9r{`%Ltdcg7Cub%S4LoI5{3{Rey zBn%C-knHkkH8L2_YlYpc>W}@!dY{@F{%HMF3nv!0EY2XjMwhC1JUr*>X?!&M9H;IOftrW*G;5=;K&jE&BF)sZAoNNk z=6~wvKZSUUw#(m;T{eC1&5EKra@h8ql;quM2)ij>v;ot3^U)Lv*v*kZ>5&09Tay|~ zg}`?i^E1!r^=mX9G^o1;y_@!TR=l$iuvGliXM~cMDU$I42l{|r4YNdUiFwCy9$bmQ@V0Erht3?bQ%~tlM3Ydh zad4h>)D|EcP`(v;UXLp$XQCo!oTQ=N&Hfbvhi!0)Y~a# z-4<=}7Yy}LI(Ii&MZmyB_bxEacIK0I26%lrR*nV#UwG>_q=+bg)Z)q}clj4k8!hSmSTYn9Z#dq5q;giZDul-i>=`g7K=B3s4iQWuBE&cyE7)XGRJ6T| zFyf&yGbMnfiGnlk^}8g7EFHinoV56Sv|P==Pn`N?l^0G+%}`wZytqCtY&Iv9?T#2Y zf0LyxS|JSnXyEa#&j_HkW<{|-F&!^is?tmX=`D< zf-U5F7Eb|x7$>vt9YKZ|WPnBcRB~LXI5f|QkOSBDTJ}>E@&UTb#dWh&(+lFfPqA z!qRGLGQQw2r7O9vSyrE<-2@7w~8fT^}PYwnjZf@k{)uB)x+739lc|-I9;QxeOl4sXJX3MvV$7Udi5~{&1hibGb*7 zK5UfSX0}hf4Esd;qGI#uE?pGEtyrq4s5U?jYpuALMTg=u0_XWC_}O9Ko5sODen{2t zcX&8*iD$79Bt!}nmxs*s}pznbI#7Ydb!73biu7__flb8oS zdBTzVuXRqjNCmy(n)1XGO6Rpx_IKjdl^6NnpFL-SN=qs(kTa#bz%{? zYRI@Nuqr0RYSVu1(Ohyv!pZyqf%u-H0X>x-Gdz}ZOBwNmnU?LFa!AU#FKck;l$t=Din0`4! zrfaQapjfJM)m5mN{lIli_NiReIk#CPty1s>x+X ziPlJf!S}h1wSGsXqTD6inMGH5p>g?qE5Fuu3`d5Goo~cL&gD(d?N#?aCjoCbCw_(1}xT~0yI9jJXkUXKB zsNa&-O~ufosoKhAz^eCqKR*qkF9~4X^f(i_BC7sA!gkHMWqU2z$kJs$0lXxUi-;ku z^?GLoZUEVJg)h^PMUYke=4AWkXyzCJ6GGQ9f|oy-MJZWn(9lc%>xmFx;CAQ#HjcA+ zvYsT_hXs(@#oh#gejO!j3LvmoxaLb$WN|*sXuY&+d*Qw>~AY|AOaPy=i;K z=~x`>=lMhnk;eOKdtwc_KI^cyFdNp!!f!wEW@;s?eC{|^{k(5u^t-3TZssbgAZAMY zM&vSzSQYXH8;s{`C{1F6fb(jry1e?G)#qZLk}3= z0H=>j(W>sJgu=hec07m=zK1>-$2hNHCsn!|)~kG2Pa{;RGPTL?ZBa|wvT4LcbDpVL+JvTH<$%R&jp2V95ixDXz>st7zF!PE$ufijis0nx;_bflVxB{TrmM zv;xE32P*jsp5q&5(R081tHyt~s1!FBs_BhHq;Y%3(Y#B!qZ+Fqth`aI_M9P3VVnL% zm8#u(w8PIQeq3ETR!w2Am>Zm!&(a(3LL+y(>ugimks}OZmV=Uvt@o2T)4~H>fsRdt zL~xcD*asti!G3y|X_U*?wq&pb8WLRMXiHA_y_`b%^cf4Puq>mU zp-U{DxIg;$y)6Gh?79Hgu%GPPviy1!7D|P!3^%+uS1XY*R z9o3ar*e~g6qj!u&MW$**|7PtnzAYq;#!5Op+f$cd@zeyBm=*ri6b3tyAv{Tj-?ju4 z>8d_wAcjp^C5Q3@5zfTT%;stY%;i%^VNXYHN2P@ud{Yk%;@sbTlmXHIUNy4&?>9r_ zYCgPpl9Yj6Ce?=LHoKwx#zm=81GoARyLBGz59Q&{+tS9O_+Q62xa_Qx)x@ekjK)&= zmk8$3uxHX(1rkv;a1Ugnvjw@RUad!U5KuU&)% zK}l%7%#z2OJzvU;RXjVaXkqkvV+FFQlMAlAQEG(+mE5k*VP3?eV0CJ!G3paD0}~O zZqBzB1O_C{?lh>DkYS=#+A#VB~?VVRtQ(wF8Llp!BM7k6~5kYzrq&GpDbdlaW zh=BA^q)8PJks_g20Y!QV2nZs*8G7%%2M8f&^55g!?EQV`jIsAPcV}JXDsyD5xn|~i z%kz6y@3&8#1ZUP6FhTc$uJ>VNLwrjm-s=-gOZ5~(lOzeRua2Sq(M%L`tB# zw`!)&diD$`^N{232i3dpmw#o;$IMUh<8adkW#nQh{ZTDKk@dfymb}z+zA;)&T@^sM zcH=c)9SECZJ_nEAar-biFyk?zwsdth|IQEbW(}W&u4<7w#aP%l5Zayipt&F2?-f_F zYKz>RLG7fHN_t1ke*Plla~OI}<;tfa#V*!!VQ0HOYkl#2IC{ZiXIbyyRW^NTWkynt zM|~oJm>i&0a|MlmV+Q!%18UQzE@MDW!9T6J?9cz?T&W*vZ;$3~dJTIB^M9kCf?Nm1 zbi?b~&s?L8noEY5=Qhw+Ni8(Qdja5Bdx>8>nwn?V^Adv!?9$o%?DYK?6+L`EjOX!9 z$w4Vla-oh~E)O0jZe6s^-0-{vqD8|#_eTTmLI@K-$2zN!aY3m_NlISOT@S(^xLKrN zwxb#FdTGqRP#F3)Y4Bpso!fm>FFfNffuGdbPtwe@Kl<=WOFGS~EmKTG*R}SM2rzjw z;et%i9U%m<%8_W|b&nM)bBQ4E4EZdU(Kv7Ee&G~vU(R}R`Lq{@8TEKr@j|U8MwV<} zSohGo2^1?Ob^#gtePKyz)@Q9Nf`q>2@F;@e^b%kzweoccET^bV&ZhXkOl_U(v)Ub| zUo0ksOG0*o@!0?xd#K1fIXl63G<-h{xGopmOvsRr5 z!z61*45~!8w5Dk(?rCTKc?Rfa9>nftdd;?(nYy#2QI*&GjPx6L-)iRXZ#nkgG1g#< z+JhbX;bWSWCuGw`bN)IUULFk~Q7e@C{+lgvPj~0rMCaOGODtQIC$m*3;!C^Y9Cx>F zj!8;W3jBw|2?S_jJk*otp1{SNa9IcNH1$#Ltk2>eU$y!nH+7HD+e5h#wIk|JH!Suj zajQ3DO|-R>yjPO-RZFMd59L0qxIF8Uy2^0mFyseWkug|4C)w%7F;s}i%K*>JSWRI$oFLT z%ckEg8eV2<%aG=_^OEGc8v5WRHZ`%YX56;13{Ou<PWIEdAwb4p{b~ zEkad+E6);2tf!7B4SYxj_7ge1EJj*F!(?|7oQcGVTg|Q+z79P$>CT@x@&k|5L}G_n z`dudfUR?rwul8EYqCG|nwA|(kUFqqF^{234_Y`dr9(4W4589ftjIA7HzxdxvbZ>>K zM_1QwPY-kt}^{yb8F6i?m=jrn1)ijB}6{dT4(a4Pv+ZoK$tFtiju0#?X+tTM6 z?%U3?73pn8vtY&h&j8>#;UV7%ot zySP6pfC)H`kh(Od?qde-5A?87H<7TPxYxwT;D(X(+s?fXwFWKZsfs?mV87yEq@APgKFNH77z${G{>>E>})4e3Gr@?$?D;gVSD&l(^x;ccbb z_{>%pIHbfHo7hF|ku+eEY)Ad9p9@RS&)fErjiSwpyOx%<)eS}~Ok0G?F_=D)xy#=` z8_dp!by!j=vpV^< z@RZY0Kh8+u0I&Rb!HQN-=b@;Wv&9mz?SeDv^bcpn$Ind84HJvRZwmc)9OE&|T~d-A zq7CVi0pps_n3}Bs@qNV{b7ktgk-uY%X%W0zcqitW6{E3S2M>&c<|AGh+Ayy$QJ4Ju zd;lu^R|rMsu9{TvjZ1{A`zcLy162`a|I*W1^l5G9meXvLPr$0=LC5J~2AB)DUmEfY zXlBMyNS+kywn^f>Q8?AKC!M^BP({^%t*HjD<$X=4I|(4&HRb0PTniMZg$sSEkwV(B zG1fcSd~dhMg-}3o9c?`K?B-7)eNzcBe{rB+?#!Er56P0swnm*imNuEvZ=u8IToKaS zwM(ozI6FYx49vA=TtDSlkB;PtiBj!6|8AHvUOkpN$OeXd(Z z&)oMWABsm$lq5aYKt9wc$%4v@4m`Uge3wy@>F<#JSw&@Q|<#2 zritNlc0_cKP;}gaNu*Tn2?@rtgIx3aOP_VmnjVxHeYQV9oS%nLOJ;WBD&?|QB+%`# zZ3MJJJbr?FORFMoaZle)%1BSPRPSBN{Z|iA1@DXI04I!$2R!V#y<{EPd3+@$UfPGS zz{1S8lm0V#xTr)@*1%Z*{f4Gr(>h{?ONN!o(9|_H_2n_21A5sit3IVP1kbCgB8_)d zOyJ3`ZbM*H`#hjr?TJGs-r(@2tijSO0yW#-6~XX!ytHwrW~#+l$_f~6phx5}&!7j< zL^ZR%TgWhT(WRWp8%4%g4fh5c`AfX}Jaq1hw>!%zpv8cm2Wkt3+j$0{8*1lvGr!kh z4Rt}JS)-f&lFZXLU^zUxI{(}oQg$nwn@ved*q2KB&2aZa9(MUnCLQ0xaG>aiDJQWt z8;J*}>qy-`=R|$d=Z8En2)bzvNi2_e?um2Xnt(0}3kScBKFD*+chCw8AL6ibs1n-u zZG{B+lulP?%C3$8`d)LGH9+N_*@53Sc#iJf1?r3eecy)z7po$$VM&n+1+%Ny_ZX|2mOCS%;@@!BZVGVR{X=7=%NC`^B`we&p=#BW)t@;ujeTaes zL^s?ABG!_Nl>IpzjtR|~H(H&A%D@jg>6vJyT&Af<7&CI?MQwJk z#R-MSMY>P*;KHsUOqb1Q*RaTd*=2zN@uJ*^&*L6{2$$W-970{SFY$z#NVL2uczJGH z9~f+4M?GLBB`3h_1s^`3MF$s)k^sK(zFmOB!Yrmy}F?@2d{t)gr z>%)~H#1D4EL@^QhD4z#}@VJJK?djXb7se@6s@l!-4# zh$0pjR4k6tAUoZH*v2jjJ{hS+`Vv9TQepSxv@X+kzQ;_D^pa%#0D)LDzj<3IW?Vh3 zFRQ4wp;&+}IL;PQ;u%Zx3!aer7GeBuq?Z5?gRNebqb7q^7LY6oK;SIEbRi1X;Tyly zICM0A))EF-nG&;P-1%838+ZT7&hZGfm|*AMfXdic->i85kYgiaG@rev#~8)@pCfU`Zu9Zr@9KxrE;Ien~Y^S6JFPA zh9R3)4)A;|q-72=PMA(vA;`eaNDC=i_+?E>p8M8)g{5)jBoj?30rutSti1Cujw^G% z!iKsevClHlF#eH4`@*nYCG)J5eMZj#$UniNDyR7Kzh#C9^v@eicR!s>Q&<*paIC4*k+|0-(YuFP) zQcv*WRa-W!O+4hC5_s6ZIARLSFI?kV!~CrzKYW}2$7|47k zO(-QiZ+N)rz-nnjIZT)aWvn(a+kg>sOAtR1ye^$+00MvPcMcnhty-J>m9e)<=u663 zscE+^vxx}P;(!ECTmahIkgAQcqF5TS+PWs8?>Q8Dl#OqWy%KKFc3)lYj*q7mSXI;A z9vfn(<-^M8QNJYw8Qcf3t?-^WZ@@)NX!uvPsma1W#+6pe-{*`de3A%%hs6_NDhjt7 zE0&QTJaKDhe7DMz2E-gqUVPmM!wX)3hyJ+43k#@GRm@inQVDFattZ8|nlx3sDmim( zGZidY5c+V6c17*DmbHYL$rjgyoVzB~0{vdnC6_0;03>!zTWc&#E0ko!SSM>^(@+b*JVD&!AuV{5&GCW>&9*7Zh})n>$>e=>AQ zE&hIT1E5AnS{X!(a}JTmTlK`QY|o6rv}L7{d>O)JmxXELJ-I{y4z+Ov5Jhi2(1TUl zc$n3Ot+X*!dAjcvi>md?Vd>U{DMnrQ`nEC>~nNc2Y(9^-2Mvm z`stLu2Q(m6^TX1qv8fbrqPi-0|L$=DwA(cgL}Xb&LX#2Nx+7)Zo_@EZMb7}+ks)X> z{GxcE&u_CBPKrkFwHr&x7eH4Wf)C-_$m9tK0@DbjV~ip*z04YEp8m%k-nR zrVAO<+}Pc1;QixTc>cAGZ)Y#1~)22z|`w}=f0XQ*j@&GFVW(cv>!_8tM-t~qtXAmj{i1NuQWV~9dB z0V$58*X0$m*v3d4V6r9}<7@t+)N#F=d7|-^J?oXGmljSjzf-2^DzQO%vZ#Taz3aY? zc+}TKLSA()$247yFJ{k9e@Q)YUnM}0Y8H5N$w=~Gb}vkTTwB7m@#ODNL3ZRHbY5i3 zZB9|PFFlcjG$Jn3!-7o5o0Zl9S6g*Uk^#Rc_2n;mt!?JJsEv3xk4Mx|9%)F<&mS=V zYzv&S6>qVYDerOj;O6bz{BQz6mq&J_q;b5GNG&AYE%8^Q|i+uUY0zfESH-}*dF1by)+Y9koPGlqeU)n4Li`?AkR zP3WZ3ocw|}mv-o^Re0O`WU*1o*SlWuBYVU-^VORHiQM$`bbYG+B|78F6IjZdIJ97k zXsYvBn|Va?k)gNWMGS52$lXMs&?!GV*m=*y3R#g?;l^fh_=u&HPD_ToTH(R5GHu$T z?=E^_Jc;Nqk6@?~S372}2M!R;&IUv&PU@+}R*s>tDoWMCLvuh~e(gHpik(5gPphd( zhFUW5en;~QKyFV^z8=+l#-(}`$PHi5(dfp@BVKehBn|StUR8aSSh5{?0j1;dMjAL~ z|F9Uqtm%`(cNlBS*)Q9bJEeq%SD_Rdst@i~03<+I+qKSI+VPGue3y+vNN zdM8Gp-@B4=&3O_0P8>Pr_o~;vSdxuK9MUVGx%a-YZ}$Tffjf1On|ao&OEPxx4u~{@ z>MAc%oaYZc78$kZWXX@7-So2i*SkCW#Erd+3*hr`enLpW*2K1E5I>bi2!I|5J)j58 zosPMIhQoABTBk z-8R$z&!gz!n47@F#(K`w#O)W&JDF&C%ui>9Q*zLVs)?Kvb>I=e`S4M)Kl-MQt^RFM zCd{?PUV{DAz_mKkn|IYVKoXZfCZ3>mS&_!S;(A>^ z^VMwFwCv{iz`zSpr103zQ&s^cM74p1KDkeK>n!&`L8Q1aW?wCwYrOWAP5WhN&9!-G z_Ya6N8g5S?(sVDR_n|^UwbSwOdMWc&t`)3t3s8cQi!H}1JUlPLq>71{r`5$a^6-GP zSXs#HpU~#Owdp{S)cg^RcFr^1v!0E;np?1F(TGkv)CIkZ_xgu{02gy1_4#XQy?vLK|2~s^5UEWC%iW< zX#;*B|Mo@i*0wOP-YxmPf{GxwNu5Y<`q{C<(C_%30PqA-Ur(9N1<2Z{qb@ut%wji(lo(#30uMZ^eB&T>TnemUv4rR=%Yhqg-&q3= zeIklv8Q$@j^4OLY8{jifr(Ca~x@}91Bg{k9&-=%~2@UNsj&WIk$HQp(fPg0zf!Ufn z>-@S0{^8&4B~gD3T_yqn6@$@_EJCE*J&v`QgKL>FGq0%nS_-(b$-H>zacEJgv@<25 zF5&5B?&mUAqMJVBf7I806Z11&)P0p37$fn;HGBvQW!ggQ?SN8dizY8Qr@TLxve7Y} z0V#{hRf@JTESr0Vdi2y)Z3HCN#NX6`c{lHokqN|UE{kFUujcSnXSyM(0k1~uY zWhhb{1LBWEwJ^oxkHWPm)RO5!< zVo19Wabtxzb#d;}RT^uwy^(ZY3Z?Rh!ws9{4mfHsyQ1H z(JDGy(b|tx^tTXN%M#VPH&~5{<-&=TIhKztdrjND$UPQLVZ_oYq-YUgVw0Fs{T~n? zIk}x=TII7__|h~i-AzAnBSY6agezs(Wz&S8-)1||pY1`=nPqc}WYO`;>68TSMVi^Q zRbXa5P8_^ruk>!ZBQWo~dw6S2s}HhFk{Xm@-%^F}<;!vSqy8ZEP6G4vPM3lNDZQ;) z+*h&<{w<5?z0ze7Yd$A<-~B%UhwTj7z0db`W^EWxwyItd(=pI(TI~DF=!4i;tb$s} zThi4ot2vZ?Lc{LK;&4|c3*BbfqrPoXnxHzxULgUKVY96eSA$id%MXczO(3q2ce=yJ zkrN5+w(YRG8}%qqNX$t;Cf26)WV&8;>G9*WE-O3n9e>|P#9w?R-g>ZgzmN~Jh&y(l zf3((L=PEp-ivt}Ivf|BD#K}sn&Uo`&rB{0R`-o!Wa9C9Ic{)F>&b+>EAW zfB!NG7hw+Msow}AqOr)_5=x^lrsy1#=DWrq?2B27UJjufcr(qJToy4KzJp=i`mxe9 z(&1ir2fn~Q%DC0_AEsp=-R_vnCz6g_hGO!#Kl2K(99Ok0-1VkBDA<%l#t0y|oNu0a^_%%UlejL?7|`43*oOu26!)0%A4(HxcT- z8TW)Nh!Y-m6R#&E7AJTa$8xJbc52)EMMIX*7TOWjGJETxHO^y;t#q4t6>lEhNV(uR z!TC>^T|*m`0Nt%I`63wQbOYlLLHt&ssgG9JMkK(f&TSILJE@-piP9{QKZXJ0jH(bB z?HZ*4E$@PIRynHDJoXoLp4o$xAmmo(IL%xU-aV;_3D&ivpp(!R360*L8m@x3OA;zT zjB?X0CWY1aEvYsh-K=C>N$p@Gp5j8yH_Cr}erKz6&z4+d?k8>sgNDZEM#;tgve&(< zb)O;B?zj2UpId#+#4)Vt++DwIVsrFPxj#MJy& zT!Nb7wk5v>-XpU3s3}X{nJ+?;cXYb1qB&QA07X;u3Yecu1+M( zPm~;akz(=HR5?{m=32|&trj#G+7?glNIewmSGIvpYG5CZQY3t|inUL&=-|wpG%ErG zwz$wwmWI0rf|-`u8o}+h`Q*@)?GXE8Wzn@tEzM%6(&ht1Y{+KvqM%Ud~YQkju4TFrK%_#jJGR`ESDU>mibdSiyH4q7ZoL2D1w zj2jfQeR5Ydm(i`TneESn$d*r}sPM{7n11J8#j=DGt7k|#_KDbA?#S5gm*-8$0 z6vV2D?5Ez~*e^X0)A%??mOK-b%z7HfCaZ&L%riz7V9$+=5#R4qGU%5)Ck!zvUV>dT z6;YxH@%w9akm)x?(Kj>n3)5)9I$smUawCb>x3QeR@YQcmD4=hx$YC$he7T7~oXuRp zmZQ^&Ind5fp+5SXu=SO-qIl)Ni#%Y;k)kndF&w+o-{x5?l^G<9h$i@z5UzdWU58m- zgYfD6bM6ErhkMDnuL;Epd{)898ULFWYRz-B%CmJ@_hdZfd%3~`RmT4qI38Yg6POid zBb9F-#lZ{OQ^~Y-y^=d7O6UD_w_Y8VHU&a^>rYBNVm;5i_1f=$GQeO16s^Gud(#5) zq<{p|OpiXZ+7Sy=myMHyK(5^%z(IWdVRrqI^$#4Jufh}r7;tVh`hUNG;s~_bzySc0 z|2hW5$Kd$Cy=TJg`b+=%tN+vS|NgB0^X2{P-~adH{|{Hy`p@%mNe l814Vh^#9YDKE&YBKxnPL?nJ&?puN6t$_nc8<+5fW{|kT=cUJ%a diff --git a/Templates/BaseGame/game/core/images/warnMat.dds b/Templates/BaseGame/game/core/images/warnMat.dds deleted file mode 100644 index ea99dcbd74a8b2ae49c5cff5a69743498a66e937..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 699192 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 diff --git a/Templates/BaseGame/game/core/images/window.png b/Templates/BaseGame/game/core/images/window.png deleted file mode 100644 index d9e8006e473974be6c97716e9ab9abc2e0e373e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2559 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

y=B0vFoY*eFT;806|)ERK!%dbrTa%1TK9Bjd-9 zr^}Zwi-N<44;PRUD|p8mJa{mjI(14AQ>RXy1kGcDhbtX7ZX8XXJXzkw;#?xT(6?{j z3J3uh>Ba9w{MtcKu%x6!T&t}`aS|7W2Z3^ccTP&GivWbIUcH(oO`0Ui9XxnYavbA4 z%5?&-1*M?e%a<=BO5(h$uP-kz7Yjmkmb6|ZFE2pFMP2CIHEU?vv}sa=9LG41awk#B zq7Ia{QxaviS3x(c2?E@105;E zR9{~&)}l)PttOOhZ4I|2jx8a+gcuZitEhD4$`!Ms zqC#Rpix)38j~_p7vL`X?Id;V^)8uz~lf9ey`0?YYbl|`NbLrBhsl}e~gpM6MmSaf# z4vshyr^beQs(JmIo;`aOl}3*qEj}EA0K<$KpHnmYb-2Cy`a0>A>greGimhql#EIf{ zQjw&e`c!V3Oxq|YTv72CD&=tqUmt1-QPA>^J$LS0?e%#WP%j>b2t4qxk)&k#^5x0s z71t(8Q9LZ8M*WU3_*)q908x1nc$Lp*%%DMo2E{4rrM;IrQC4khIDr8hqD>W0WMK?v!wXo*Sox6w^%mnQ(TC_-zKFZS8^{EVS zw8ffyettoOj)7h%>FMkg2ntlMeRelK&RT}s7JUfZ@!Pi-cVw4ae$%~oO))8A$|GfAL#3^{}?&;db3pOiK3Vbm7-lsLCqW$rzmzSf~tuG+U5+V zVXEU)6!6+MGU2Q63p@-Ii4Dgv|CzlIPvV?FXa!eP9ecf5D)rhdDqD7VZzm^s6_5ed zvATFL*uvwpQIcZas^e4?@Y+@sZRN44Hk?X#VqekwO{wZa04bQlkd&h8*z3(wspp$j z5&tR*cDQ0W=(-9_a6EL`lmL_h1w*(07|LK40No;%f}xJHp|J7v=~MI2p+k`!3$Zta zudn2Hr!Bl(quZU34PWn{l{=8Jow`mDubt{-#iH18 z8mX&%Art`E>G4is6t7)JdqnF zTQ{Ikk}k)E6-v_O$=*DXcE(HIdgj!iH}mZ9Z6_!B?Z}atAEOE->2fHjP?9cB#4^d& z^)Dz%_7`Wmoo_5^VDG1sH4sUD!e1e9l7Sz8obiXr@Qttc&B~q5qToJHnKFgOefF7b zTeB1JoR=+IM&-N`?Y735a_lLxXE`S3g#FBjOTps0m=oerh)ZQ9_7odyQpbo#sU70F zm=oerUUq}0W9o{4lDL?YWiHUgoDh%7mP8bdjX7E8EM3eA@u+M`1U>0uPFD038*@TD zDq9lJ#heh2Qlg7FAs&@23Fu-@h({^W#hmQEuahaoedFu>r|5?ob5cVopo=+Kw*={8 zPKZY#E|m?@q9+8;7A#mm13vml>+7N9`t|GSHykF3+Fsfd5jlj}TcX9f=zv}*>dx>;V=&NpN9e@jtbDyKdCUjy1xJXsWE znAx*ux2K+D`2Jx+ck@Rk#fmp?-lW5a54WpDwOtRsGCpq%!8$1@@9io6?0Rb#Tc7lk zCr=XojYoS*RM+E^-Kx7^y?RCS=g$}25H%UW|2(2S#h+c@o)&Yv_kRJO_n_Zf_&8bs O0000(_@_GbJ<_dZw^Q+&I7EPrEnI(eqE51YbYz7T13zwEE$$n>MSVv_3!WR xqwIV#4BRgm4JXvHMKX&S7St`!IKaTf!=UB9TBWi;$P?&J22WQ%mvv4FO#lthVzU4M literal 0 HcmV?d00001 diff --git a/Templates/BaseGame/game/core/gui/images/thumbHighlightButton.png b/Templates/BaseGame/game/core/gui/images/thumbHighlightButton.png new file mode 100644 index 0000000000000000000000000000000000000000..9d83b75f31b965b79ff082e3a0f6e37e4c757c1b GIT binary patch literal 778 zcmV+l1NHogP)^%4Aj<$I1_}WqRRR$d z1~4y>8i*8ofd!i&&^88q;$hSbL@LC>f3!$o1Vs!3BNnyT#Q(FzWmcoc0=>O348mYE z7Di)XG#${gULYk9sZ%c;*}t7K1LT!85hAQlXK)Rq9_nInN)!ayOp3q3h5+?ZB@mfF0rU0$f5zPxzJM_-aIs(% zaacePd~O^y0Gb=Qf!I}_n|uR62^f})T}Q)U#D)ReA_iudz%LMg;eTdyg}>q%QN>TK zMd@&GqN(S^VIe239t#(mI2R5BxNsT3gC@>{!vG#!2JoSY^WiXn50?SFXyUv$4B(}@ z3n;D^SU}}Ft66XpQhe_P#$P)N-;>uu0ogpTEtG2ypD`}kb`^|A zTPQ=eg`y=V3C3g_aP84^23RtV84ZIG8wR5-l+hN-XbXi3Efk;Vaufm3qytH#c_6Z< zE(Ia9w3GDg3<4Lg-UZX@LvA#W$v3*3@#f9jjG!4Dq}d&UEfkp8X#0Q~5|tAdDOXK#LK`1pomC0NWAfc{C??-~a#s07*qo IM6N<$f>^aj6#xJL literal 0 HcmV?d00001 diff --git a/Templates/BaseGame/game/core/gui/images/window.png b/Templates/BaseGame/game/core/gui/images/window.png new file mode 100644 index 0000000000000000000000000000000000000000..d9e8006e473974be6c97716e9ab9abc2e0e373e3 GIT binary patch literal 2559 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 %deskResX) || (%resY >= %deskResY)) + { + warn("Warning: The requested windowed resolution is equal to or larger than the current desktop resolution. Attempting to find a better resolution"); + + %resCount = Canvas.getModeCount(); + for (%i = (%resCount - 1); %i >= 0; %i--) + { + %testRes = Canvas.getMode(%i); + %testResX = getWord(%testRes, $WORD::RES_X); + %testResY = getWord(%testRes, $WORD::RES_Y); + %testBPP = getWord(%testRes, $WORD::BITDEPTH); + + if (%testBPP != %bpp) + continue; + + if ((%testResX < %deskResX) && (%testResY < %deskResY)) + { + // This will work as our new resolution + %resX = %testResX; + %resY = %testResY; + + warn("Warning: Switching to \"" @ %resX SPC %resY SPC %bpp @ "\""); + + break; + } + } + } + } + + $pref::Video::Resolution = %resX SPC %resY; + $pref::Video::FullScreen = %fs; + $pref::Video::BitDepth = %bpp; + $pref::Video::RefreshRate = %rate; + $pref::Video::AA = %aa; + + if (%fs == 1 || %fs $= "true") + %fsLabel = "Yes"; + else + %fsLabel = "No"; + + echo("Accepted Mode: " NL + "--Resolution : " @ %resX SPC %resY NL + "--Full Screen : " @ %fsLabel NL + "--Bits Per Pixel : " @ %bpp NL + "--Refresh Rate : " @ %rate NL + "--AA TypeXLevel : " @ %aa NL + "--------------"); + + // Actually set the new video mode + Canvas.setVideoMode(%resX, %resY, %fs, %bpp, %rate, %aa); + + commandToServer('setClientAspectRatio', %resX, %resY); + + // AA piggybacks on the AA setting in $pref::Video::mode. + // We need to parse the setting between AA modes, and then it's level + // It's formatted as AATypexAALevel + // So, FXAAx4 or MLAAx2 + if ( isObject( FXAA_PostEffect ) ) + FXAA_PostEffect.isEnabled = ( %aa > 0 ) ? true : false; +} diff --git a/Templates/BaseGame/game/core/gui/scripts/cursor.cs b/Templates/BaseGame/game/core/gui/scripts/cursor.cs new file mode 100644 index 000000000..f71bc023a --- /dev/null +++ b/Templates/BaseGame/game/core/gui/scripts/cursor.cs @@ -0,0 +1,102 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//--------------------------------------------------------------------------------------------- +// Cursor toggle functions. +//--------------------------------------------------------------------------------------------- +$cursorControlled = true; +function showCursor() +{ + if ($cursorControlled) + lockMouse(false); + Canvas.cursorOn(); +} + +function hideCursor() +{ + if ($cursorControlled) + lockMouse(true); + Canvas.cursorOff(); +} + +//--------------------------------------------------------------------------------------------- +// In the CanvasCursor package we add some additional functionality to the built-in GuiCanvas +// class, of which the global Canvas object is an instance. In this case, the behavior we want +// is for the cursor to automatically display, except when the only guis visible want no +// cursor - usually the in game interface. +//--------------------------------------------------------------------------------------------- +package CanvasCursorPackage +{ + +//--------------------------------------------------------------------------------------------- +// checkCursor +// The checkCursor method iterates through all the root controls on the canvas checking each +// ones noCursor property. If the noCursor property exists as anything other than false or an +// empty string on every control, the cursor will be hidden. +//--------------------------------------------------------------------------------------------- +function GuiCanvas::checkCursor(%this) +{ + %count = %this.getCount(); + for(%i = 0; %i < %count; %i++) + { + %control = %this.getObject(%i); + if ((%control.noCursor $= "") || !%control.noCursor) + { + showCursor(); + return; + } + } + // If we get here, every control requested a hidden cursor, so we oblige. + hideCursor(); +} + +//--------------------------------------------------------------------------------------------- +// The following functions override the GuiCanvas defaults that involve changing the content +// of the Canvas. Basically, all we are doing is adding a call to checkCursor to each one. +//--------------------------------------------------------------------------------------------- +function GuiCanvas::setContent(%this, %ctrl) +{ + Parent::setContent(%this, %ctrl); + %this.checkCursor(); +} + +function GuiCanvas::pushDialog(%this, %ctrl, %layer, %center) +{ + Parent::pushDialog(%this, %ctrl, %layer, %center); + %this.checkCursor(); +} + +function GuiCanvas::popDialog(%this, %ctrl) +{ + Parent::popDialog(%this, %ctrl); + %this.checkCursor(); +} + +function GuiCanvas::popLayer(%this, %layer) +{ + Parent::popLayer(%this, %layer); + %this.checkCursor(); +} + +}; + +activatePackage(CanvasCursorPackage); diff --git a/Templates/BaseGame/game/core/gui/scripts/fonts/Arial 10 (ansi).uft b/Templates/BaseGame/game/core/gui/scripts/fonts/Arial 10 (ansi).uft new file mode 100644 index 0000000000000000000000000000000000000000..2b564950050cfca995e66f048e0523428ff493b0 GIT binary patch literal 412 zcmZQ(U|?W%EXqvG;R3Qi07P>@F%ytx24VyN@mQf;5Dk%qsR4%?)Qy83;)lEIri7m zFZoExihWaFY>GaAyHfb_#$7>4rhD3-7VX{JcRHkY<;8EhWjEc^(!MS|x7jKnT~tu; z`y-fhfi55e9MJ#4lvSq~c?$DU2jYrb$q5Y1ZVG9@ Ja2IA^0RUczP(}a% literal 0 HcmV?d00001 diff --git a/Templates/BaseGame/game/core/gui/scripts/fonts/Arial 12 (ansi).uft b/Templates/BaseGame/game/core/gui/scripts/fonts/Arial 12 (ansi).uft new file mode 100644 index 0000000000000000000000000000000000000000..67a177016766c6f06b5b601c3336b9fea2ac75ba GIT binary patch literal 62 jcmZQ(U|?W%EXqvG;Q_Kh07P>_F*8U23jU*ldXO*xH#ZTF literal 0 HcmV?d00001 diff --git a/Templates/BaseGame/game/core/gui/scripts/fonts/Arial 14 (ansi).uft b/Templates/BaseGame/game/core/gui/scripts/fonts/Arial 14 (ansi).uft new file mode 100644 index 0000000000000000000000000000000000000000..f4f19745fb7ea405e3c544ab4380b665efbfde9c GIT binary patch literal 4631 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 b6sM#M<#jvpb9awrZFUL$u!K`tU*`B9%GMUT literal 0 HcmV?d00001 diff --git a/Templates/BaseGame/game/core/gui/scripts/fonts/Arial 16 (ansi).uft b/Templates/BaseGame/game/core/gui/scripts/fonts/Arial 16 (ansi).uft new file mode 100644 index 0000000000000000000000000000000000000000..ec996019dfe8c0fdc39ecd2cb8f3a59021328064 GIT binary patch literal 13031 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 U#C$+paVt3?At42ntauri09vTq4gdfE literal 0 HcmV?d00001 diff --git a/Templates/BaseGame/game/core/gui/scripts/fonts/Arial Bold 14 (ansi).uft b/Templates/BaseGame/game/core/gui/scripts/fonts/Arial Bold 14 (ansi).uft new file mode 100644 index 0000000000000000000000000000000000000000..4dbbddede62addac380eca861535ac39d2f3819b GIT binary patch literal 2669 zcmc(gdpMM76u`eR7mNrosa-n?>zZ;YOU01exP>&9T87ny+|sOTB}BQ@Xb^?RrC6a@ zk;|6sPMeg5by+*2MLRCz5(+7?^ZLGdnrB!3-Sa%}oO9maIp=-P`+nayXb6JvCc!?Q zehQ|6e%=y17YNW|$UyV7CU1ORK*T2j9v*Q;cp9@}^J8#456l7qT6o10UHOF|K*0b4 zG)&j8_z)z-(}KBhO(}$8d0H?Rwh00h1ZfjDi02QnZ=N?^?`XLnLfx*9DIG2Xd)$cb1p&(XpUD!T@ zP{Gpx1g;#rCQU#n|E&1Cf-5uD%*{mT>buHaGq(_-t3MkhYvxw0nOlv}fA0!Djr*UW zaKB81f?EIs2+;8J{M(8TLHs@Q&kBA+pCVN77Jv<}+lEjO3ub`;4QfG9=gKeqgbGsd zWrLuX2<3MK)&)^;BnP3ugS&t=yzZDlE{G7!Me+Ou2YX9#{ATcKh?A|%oFE9yqTov5 zo963zA0T_OnTc~)_Cyzvrg#WynkHg!LUE=Fk|G#uu)6gn-_pZAG9CzQ8VUALv$UZ|egBK6=a zDO#3NXrKz$l54r+W^0f^(j#1m;6%dq_Si@xbs`gK$L3yQUb zj-$F67$>@_TwCmm0^yPPa`Wlr>ZL);HV!t;QR|l@8KT*_rZo}|44YLZe`uYZlc3u! zgy==}b&w5G(}cWJhC(3|Ysr)$I(s1GLx7CpU=LHes)*^PRw&&VQ8ryKLbcyjXVBLw z)%j#{vNE1ZuE`uVI;Uc>s9Lg7&-oatBNnnxNGc%d_AES^cy-mPlV0ji4 z&yMuqxU_RmLK^BGR>F3L7{)zRaae*0iIJh9Dcdd6tt44ihY`=zaj;f{OF!UmIPx_P@zT;YGCD zu#%bT@b;B|X|lP!*&S1A%na|N!xsgf5zZT-yb;!OiN%(P*&%a&AQ3MVb8!$?+n?C5 z{3dJQh3*4oOVTCdwg5uWH1NiayW=7ziIAv--bWF zx$%f{1}lucoHHMaj!H^D#gW;s^zPRa6RfFdI@X>0*Po5%iRtf&T--+E`VapAtP-Jh literal 0 HcmV?d00001 diff --git a/Templates/BaseGame/game/core/gui/scripts/fonts/Arial Bold 16 (ansi).uft b/Templates/BaseGame/game/core/gui/scripts/fonts/Arial Bold 16 (ansi).uft new file mode 100644 index 0000000000000000000000000000000000000000..fb096776f37c76773bef44144599604436e1c8bb GIT binary patch literal 1198 zcmZQ(U|`^KEXqvGQE$SaLNPOx52T=g4M=kVF(Z`b0E>e}K>$Rv12ISz zL_=hGfGiNeE-M6)1j}NYECH2e0@BE`EMRddB)ypSDj>$^|@K978JRyuG5B zFYPJ8_JCgk2t*{r*hE-FWH>Y|Bm@!y1R$W`fkR?rJZ0y`T zKp-X&QN^DVv->Z5-#qulv6*Eiv) z*N4?xwX5UJ&N`=0+#dScWNy`L*H5L>=D#|zMg8BD*|TeA@xG3o_BLnIpVDbhlh?^j z%5o3&E&6M?csb8&laraepQps^xjD6N4WrJb_vwM@kALp#TM~a#Ywy2@=VO;%Kl{k; z@vhTW<))`_ElB4ebe{K=1iZfwl|jHxTI6{v%tK(Pv4E+ z=TH86e%X32wVkuxFiC`bnsNL4%l9g(Ar{7*sI`_#Qy-9cW<$SJUn(^e< z=Y8{@?JJ*F|GMb&-{}nZR9{|KIQjCl*>ULu@6+XN*029oEdDuX|J*Iw{ExGYR7`6g@ft;7yps<;JgQ$Wwo=o=d4Dp<5KmV>mvv4FO@T-zDgfCfKx_xZ6}OTT5)%IV zvjNEm|NWI2OlI@<%P@03D-d4U$Ju$7=SWO|nY2JLlOgvc8~rJ1tVwPvg>o8a85wpk H3YP!?K^+@u literal 0 HcmV?d00001 diff --git a/Templates/BaseGame/game/core/gui/scripts/fonts/Arial Bold 18 (ansi).uft b/Templates/BaseGame/game/core/gui/scripts/fonts/Arial Bold 18 (ansi).uft new file mode 100644 index 0000000000000000000000000000000000000000..1f8fdedd3337dae3859867addedafffcd75bd980 GIT binary patch literal 3066 zcmchYdpwle8poG0VJ0I}Y>jdYT~tz&OJW;xnMrO#ZhIF>ndm|;C4^yj)KoNEDM#|b zPTO_Mt&mHhWI}2bN}?o}+(L-XyS(Gmd(PJW^E{u=TF-jdcm1CAtY^LNj4%LzXn6dP z+hIkcV~5?BB9G9Zmk=~O;@2VVyNMyg#Yhtpc;Xy_v(Ruz!&0b6Hks=I5Jfy(3ANA@ zkOlyGu1D#-_B&lJpbJNq#c2N?SqVe`9(gT>VzqD#z$OfZT4<2KGXS79*8{K!@mQ_M z-28R{h3A{!7kV^~v4BGDd}W}A&p$S_k_^ED7#YnITS=yX!W`#wh8|t%grV4+(OYm8 zP?!nS%-^s0+`OlN!t-IZXk>2zo!@s}i$*?yp;#?SPyb`&NQ@Sn6{_V3C<*b9LW3SY z18{Y&|L^w-QdE0GKw(C3c0OnHM$!ay;cDaxD2#;F!Z85FbN!FLg;D{9`=ZrDJvy$! zP;6v0E1rPqR;sQNo3Uc>2Ty^S9bpPD-w5p_cJr&;&l^7 zT7OUOij(Aq=MS&Ee}}{wRBd$CDnDBnLUm@=>oGY_PM(Ik%RjhJw56+sWyRF^$Z9!l z){n+V^dIq!DIcV<=$`nP=eXvdq|?$arFL~XcmN^#sfz71nXuQL)9s5Z>|Tg(b;S=Q z{Q~Zn(atqBS}Uj8w3G>haerGo@04{Fb)G;!Z18LM_sUN20jN`nvW%;6 zfe&z(R9I{DinhPCz#UnTH6Sst&Kck}g zD0#4fniz*;1>-dqB|7uAx<#L5I?wQJW+ojE1eI3~*@A*)H*uFk8{KXxU0;=Brtf{{ zR;sDGiHEP)ivqPULfljSJ|dmn*TZ(V>;tLmnd&qc_|-V&R>c&> zUzP3?UwOp;yihe^ow~K2l>c~pc*0FxTH2QbvmZ07D5K5=XAI2bapEAZ7jroY%&GJ8!iSF5Ik?YyT+^#wQSrnAqAgn+H;s|RCz z`rPE@Wr`{4{h)cTTFs57#NvPM_+y-|40ad09bcBY>7lP$53k)m@T=n%2$b!;6= zGwkPeA>oB}_=(40oRJ!9xYGaH?k-B8$KG967h_JMTh zSOPUvw{Z~HctF#%E@a1T+Qm{dG)X`QZlhAzu3jkSx)Vbo5c3c2@URuW$T=v)lfX z-rMC#w96rQHIg_d23mbz&eRQj-A|JV{$>W=N*N{oMq+roWPJ|SPnw!8Ezn)mo5pi3 zqrPKQe||Z0JC1!kYv`GY2ChdfUTS@mRo-x%1Z_#Ch@?WCxltRhm)%V%3C+C_YM1N0 z-357P_Xf-Rs5VYDookS>{XF{F798`ix$BGr? z^6vr|CYHw8My~7)$Qb@9LQ_OqAktV!JK1`#zE*+_#7&-VsZH7vfqR@e^35PhJ9n{t zm9&Lr{J5%x$-CR~)~jy!y9@6X)9AcNx!g@MD!r8aF!H2t%4HXQo4)L?quLHZ7gwyj gzEMiUZ??izbQ#$)evm%<0A^7=iU0rr literal 0 HcmV?d00001 diff --git a/Templates/BaseGame/game/core/gui/scripts/fonts/ArialItalic 14 (ansi).uft b/Templates/BaseGame/game/core/gui/scripts/fonts/ArialItalic 14 (ansi).uft new file mode 100644 index 0000000000000000000000000000000000000000..5bac0316eb5a91b60214d283e613e06abf22c7a6 GIT binary patch literal 777 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 + \ No newline at end of file diff --git a/Templates/BaseGame/game/core/lighting/scripts/advancedLighting_Init.cs b/Templates/BaseGame/game/core/lighting/scripts/advancedLighting_Init.cs new file mode 100644 index 000000000..c7d357bb8 --- /dev/null +++ b/Templates/BaseGame/game/core/lighting/scripts/advancedLighting_Init.cs @@ -0,0 +1,68 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +/////////////////////////////////////////////////////////////////////////////// +// Default Prefs + +/* +$pref::LightManager::sgAtlasMaxDynamicLights = "16"; +$pref::LightManager::sgDynamicShadowDetailSize = "0"; +$pref::LightManager::sgDynamicShadowQuality = "0"; +$pref::LightManager::sgLightingProfileAllowShadows = "1"; +$pref::LightManager::sgLightingProfileQuality = "0"; +$pref::LightManager::sgMaxBestLights = "10"; +$pref::LightManager::sgMultipleDynamicShadows = "1"; +$pref::LightManager::sgShowCacheStats = "0"; +$pref::LightManager::sgUseBloom = ""; +$pref::LightManager::sgUseDRLHighDynamicRange = "0"; +$pref::LightManager::sgUseDynamicRangeLighting = "0"; +$pref::LightManager::sgUseDynamicShadows = "1"; +$pref::LightManager::sgUseToneMapping = ""; +*/ + +//exec( "./shaders.cs" ); +//exec( "./deferredShading.cs" ); + +function onActivateAdvancedLM() +{ + // Enable the offscreen target so that AL will work + // with MSAA back buffers and for HDR rendering. + AL_FormatToken.enable(); + + // Activate Deferred Shading + AL_DeferredShading.enable(); +} + +function onDeactivateAdvancedLM() +{ + // Disable the offscreen render target. + AL_FormatToken.disable(); + + // Deactivate Deferred Shading + AL_DeferredShading.disable(); +} + +function setAdvancedLighting() +{ + setLightManager( "Advanced Lighting" ); +} + diff --git a/Templates/BaseGame/game/core/lighting/scripts/advancedLighting_Shaders.cs b/Templates/BaseGame/game/core/lighting/scripts/advancedLighting_Shaders.cs new file mode 100644 index 000000000..a73598d9b --- /dev/null +++ b/Templates/BaseGame/game/core/lighting/scripts/advancedLighting_Shaders.cs @@ -0,0 +1,276 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + + +// Vector Light State +new GFXStateBlockData( AL_VectorLightState ) +{ + blendDefined = true; + blendEnable = true; + blendSrc = GFXBlendOne; + blendDest = GFXBlendOne; + blendOp = GFXBlendOpAdd; + + zDefined = true; + zEnable = false; + zWriteEnable = false; + + samplersDefined = true; + samplerStates[0] = SamplerClampPoint; // G-buffer + mSamplerNames[0] = "deferredBuffer"; + samplerStates[1] = SamplerClampPoint; // Shadow Map (Do not change this to linear, as all cards can not filter equally.) + mSamplerNames[1] = "shadowMap"; + samplerStates[2] = SamplerClampPoint; // Shadow Map (Do not change this to linear, as all cards can not filter equally.) + mSamplerNames[2] = "dynamicShadowMap"; + samplerStates[3] = SamplerClampLinear; // SSAO Mask + mSamplerNames[3] = "ssaoMask"; + samplerStates[4] = SamplerWrapPoint; // Random Direction Map + + cullDefined = true; + cullMode = GFXCullNone; + + stencilDefined = true; + stencilEnable = true; + stencilFailOp = GFXStencilOpKeep; + stencilZFailOp = GFXStencilOpKeep; + stencilPassOp = GFXStencilOpKeep; + stencilFunc = GFXCmpLess; + stencilRef = 0; +}; + +// Vector Light Material +new ShaderData( AL_VectorLightShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/lighting/advanced/farFrustumQuadV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/lighting/advanced/vectorLightP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/lighting/advanced/gl/farFrustumQuadV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/lighting/advanced/gl/vectorLightP.glsl"; + + samplerNames[0] = "$deferredBuffer"; + samplerNames[1] = "$shadowMap"; + samplerNames[2] = "$dynamicShadowMap"; + samplerNames[3] = "$ssaoMask"; + samplerNames[4] = "$gTapRotationTex"; + samplerNames[5] = "$lightBuffer"; + samplerNames[6] = "$colorBuffer"; + samplerNames[7] = "$matInfoBuffer"; + + pixVersion = 3.0; +}; + +new CustomMaterial( AL_VectorLightMaterial ) +{ + shader = AL_VectorLightShader; + stateBlock = AL_VectorLightState; + + sampler["deferredBuffer"] = "#deferred"; + sampler["shadowMap"] = "$dynamiclight"; + sampler["dynamicShadowMap"] = "$dynamicShadowMap"; + sampler["ssaoMask"] = "#ssaoMask"; + sampler["lightBuffer"] = "#lightinfo"; + sampler["colorBuffer"] = "#color"; + sampler["matInfoBuffer"] = "#matinfo"; + + target = "lightinfo"; + + pixVersion = 3.0; +}; + +//------------------------------------------------------------------------------ + +// Convex-geometry light states +new GFXStateBlockData( AL_ConvexLightState ) +{ + blendDefined = true; + blendEnable = true; + blendSrc = GFXBlendOne; + blendDest = GFXBlendOne; + blendOp = GFXBlendOpAdd; + + zDefined = true; + zEnable = true; + zWriteEnable = false; + zFunc = GFXCmpGreaterEqual; + + samplersDefined = true; + samplerStates[0] = SamplerClampPoint; // G-buffer + mSamplerNames[0] = "deferredBuffer"; + samplerStates[1] = SamplerClampPoint; // Shadow Map (Do not use linear, these are perspective projections) + mSamplerNames[1] = "shadowMap"; + samplerStates[2] = SamplerClampPoint; // Shadow Map (Do not use linear, these are perspective projections) + mSamplerNames[2] = "dynamicShadowMap"; + samplerStates[3] = SamplerClampLinear; // Cookie Map + samplerStates[4] = SamplerWrapPoint; // Random Direction Map + + cullDefined = true; + cullMode = GFXCullCW; + + stencilDefined = true; + stencilEnable = true; + stencilFailOp = GFXStencilOpKeep; + stencilZFailOp = GFXStencilOpKeep; + stencilPassOp = GFXStencilOpKeep; + stencilFunc = GFXCmpLess; + stencilRef = 0; +}; + +// Point Light Material +new ShaderData( AL_PointLightShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/lighting/advanced/convexGeometryV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/lighting/advanced/pointLightP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/lighting/advanced/gl/convexGeometryV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/lighting/advanced/gl/pointLightP.glsl"; + + samplerNames[0] = "$deferredBuffer"; + samplerNames[1] = "$shadowMap"; + samplerNames[2] = "$dynamicShadowMap"; + samplerNames[3] = "$cookieMap"; + samplerNames[4] = "$gTapRotationTex"; + samplerNames[5] = "$lightBuffer"; + samplerNames[6] = "$colorBuffer"; + samplerNames[7] = "$matInfoBuffer"; + + pixVersion = 3.0; +}; + +new CustomMaterial( AL_PointLightMaterial ) +{ + shader = AL_PointLightShader; + stateBlock = AL_ConvexLightState; + + sampler["deferredBuffer"] = "#deferred"; + sampler["shadowMap"] = "$dynamiclight"; + sampler["dynamicShadowMap"] = "$dynamicShadowMap"; + sampler["cookieMap"] = "$dynamiclightmask"; + sampler["lightBuffer"] = "#lightinfo"; + sampler["colorBuffer"] = "#color"; + sampler["matInfoBuffer"] = "#matinfo"; + + target = "lightinfo"; + + pixVersion = 3.0; +}; + +// Spot Light Material +new ShaderData( AL_SpotLightShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/lighting/advanced/convexGeometryV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/lighting/advanced/spotLightP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/lighting/advanced/gl/convexGeometryV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/lighting/advanced/gl/spotLightP.glsl"; + + samplerNames[0] = "$deferredBuffer"; + samplerNames[1] = "$shadowMap"; + samplerNames[2] = "$dynamicShadowMap"; + samplerNames[3] = "$cookieMap"; + samplerNames[4] = "$gTapRotationTex"; + samplerNames[5] = "$lightBuffer"; + samplerNames[6] = "$colorBuffer"; + samplerNames[7] = "$matInfoBuffer"; + + pixVersion = 3.0; +}; + +new CustomMaterial( AL_SpotLightMaterial ) +{ + shader = AL_SpotLightShader; + stateBlock = AL_ConvexLightState; + + sampler["deferredBuffer"] = "#deferred"; + sampler["shadowMap"] = "$dynamiclight"; + sampler["dynamicShadowMap"] = "$dynamicShadowMap"; + sampler["cookieMap"] = "$dynamiclightmask"; + sampler["lightBuffer"] = "#lightinfo"; + sampler["colorBuffer"] = "#color"; + sampler["matInfoBuffer"] = "#matinfo"; + + target = "lightinfo"; + + pixVersion = 3.0; +}; + +/// This material is used for generating deferred +/// materials for objects that do not have materials. +new Material( AL_DefaultDeferredMaterial ) +{ + // We need something in the first pass else it + // won't create a proper material instance. + // + // We use color here because some objects may not + // have texture coords in their vertex format... + // for example like terrain. + // + diffuseColor[0] = "1 1 1 1"; +}; + +/// This material is used for generating shadow +/// materials for objects that do not have materials. +new Material( AL_DefaultShadowMaterial ) +{ + // We need something in the first pass else it + // won't create a proper material instance. + // + // We use color here because some objects may not + // have texture coords in their vertex format... + // for example like terrain. + // + diffuseColor[0] = "1 1 1 1"; + + // This is here mostly for terrain which uses + // this material to create its shadow material. + // + // At sunset/sunrise the sun is looking thru + // backsides of the terrain which often are not + // closed. By changing the material to be double + // sided we avoid holes in the shadowed geometry. + // + doubleSided = true; +}; + +// Particle System Point Light Material +new ShaderData( AL_ParticlePointLightShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/lighting/advanced/particlePointLightV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/lighting/advanced/particlePointLightP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/lighting/advanced/gl/convexGeometryV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/lighting/advanced/gl/pointLightP.glsl"; + + samplerNames[0] = "$deferredBuffer"; + + pixVersion = 3.0; +}; + +new CustomMaterial( AL_ParticlePointLightMaterial ) +{ + shader = AL_ParticlePointLightShader; + stateBlock = AL_ConvexLightState; + + sampler["deferredBuffer"] = "#deferred"; + target = "lightinfo"; + + pixVersion = 3.0; +}; diff --git a/Templates/BaseGame/game/core/lighting/scripts/basicLighting_Init.cs b/Templates/BaseGame/game/core/lighting/scripts/basicLighting_Init.cs new file mode 100644 index 000000000..99be20c5c --- /dev/null +++ b/Templates/BaseGame/game/core/lighting/scripts/basicLighting_Init.cs @@ -0,0 +1,92 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//exec( "./shadowFilter.cs" ); + +singleton GFXStateBlockData( BL_ProjectedShadowSBData ) +{ + blendDefined = true; + blendEnable = true; + blendSrc = GFXBlendDestColor; + blendDest = GFXBlendZero; + + zDefined = true; + zEnable = true; + zWriteEnable = false; + + samplersDefined = true; + samplerStates[0] = SamplerClampLinear; + vertexColorEnable = true; +}; + +singleton ShaderData( BL_ProjectedShadowShaderData ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/projectedShadowV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/projectedShadowP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/gl/projectedShadowV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/gl/projectedShadowP.glsl"; + + samplerNames[0] = "inputTex"; + + pixVersion = 2.0; +}; + +singleton CustomMaterial( BL_ProjectedShadowMaterial ) +{ + sampler["inputTex"] = "$miscbuff"; + + shader = BL_ProjectedShadowShaderData; + stateBlock = BL_ProjectedShadowSBData; + version = 2.0; + forwardLit = true; +}; + +function onActivateBasicLM() +{ + // If HDR is enabled... enable the special format token. + if ( $platform !$= "macos" && HDRPostFx.isEnabled ) + AL_FormatToken.enable(); + + // Create render pass for projected shadow. + new RenderPassManager( BL_ProjectedShadowRPM ); + + // Create the mesh bin and add it to the manager. + %meshBin = new RenderMeshMgr(); + BL_ProjectedShadowRPM.addManager( %meshBin ); + + // Add both to the root group so that it doesn't + // end up in the MissionCleanup instant group. + RootGroup.add( BL_ProjectedShadowRPM ); + RootGroup.add( %meshBin ); +} + +function onDeactivateBasicLM() +{ + // Delete the pass manager which also deletes the bin. + BL_ProjectedShadowRPM.delete(); +} + +function setBasicLighting() +{ + setLightManager( "Basic Lighting" ); +} diff --git a/Templates/BaseGame/game/core/lighting/scripts/basicLighting_shadowFilter.cs b/Templates/BaseGame/game/core/lighting/scripts/basicLighting_shadowFilter.cs new file mode 100644 index 000000000..5aea7b607 --- /dev/null +++ b/Templates/BaseGame/game/core/lighting/scripts/basicLighting_shadowFilter.cs @@ -0,0 +1,76 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + + +singleton ShaderData( BL_ShadowFilterShaderV ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/lighting/basic/shadowFilterV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/lighting/basic/shadowFilterP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/lighting/basic/gl/shadowFilterV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/lighting/basic/gl/shadowFilterP.glsl"; + + samplerNames[0] = "$diffuseMap"; + + defines = "BLUR_DIR=float2(1.0,0.0)"; + + pixVersion = 2.0; +}; + +singleton ShaderData( BL_ShadowFilterShaderH : BL_ShadowFilterShaderV ) +{ + defines = "BLUR_DIR=float2(0.0,1.0)"; +}; + + +singleton GFXStateBlockData( BL_ShadowFilterSB : PFX_DefaultStateBlock ) +{ + colorWriteDefined=true; + colorWriteRed=false; + colorWriteGreen=false; + colorWriteBlue=false; + blendDefined = true; + blendEnable = true; +}; + +// NOTE: This is ONLY used in Basic Lighting, and +// only directly by the ProjectedShadow. It is not +// meant to be manually enabled like other PostEffects. +singleton PostEffect( BL_ShadowFilterPostFx ) +{ + // Blur vertically + shader = BL_ShadowFilterShaderV; + stateBlock = PFX_DefaultStateBlock; + targetClear = "PFXTargetClear_OnDraw"; + targetClearColor = "0 0 0 0"; + texture[0] = "$inTex"; + target = "$outTex"; + + // Blur horizontal + new PostEffect() + { + shader = BL_ShadowFilterShaderH; + stateBlock = PFX_DefaultStateBlock; + texture[0] = "$inTex"; + target = "$outTex"; + }; +}; diff --git a/Templates/BaseGame/game/core/lighting/scripts/deferredShading.cs b/Templates/BaseGame/game/core/lighting/scripts/deferredShading.cs new file mode 100644 index 000000000..5dbacd2e3 --- /dev/null +++ b/Templates/BaseGame/game/core/lighting/scripts/deferredShading.cs @@ -0,0 +1,71 @@ +singleton ShaderData( ClearGBufferShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/lighting/advanced/deferredClearGBufferV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/lighting/advanced/deferredClearGBufferP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/lighting/advanced/gl/deferredClearGBufferP.glsl"; + + pixVersion = 2.0; +}; + +singleton ShaderData( DeferredColorShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFx/postFxV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/lighting/advanced/deferredColorShaderP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/lighting/advanced/gl/deferredColorShaderP.glsl"; + + pixVersion = 2.0; +}; + +// Primary Deferred Shader +new GFXStateBlockData( AL_DeferredShadingState : PFX_DefaultStateBlock ) +{ + cullMode = GFXCullNone; + + blendDefined = true; + blendEnable = true; + blendSrc = GFXBlendSrcAlpha; + blendDest = GFXBlendInvSrcAlpha; + + samplersDefined = true; + samplerStates[0] = SamplerWrapLinear; + samplerStates[1] = SamplerWrapLinear; + samplerStates[2] = SamplerWrapLinear; + samplerStates[3] = SamplerWrapLinear; + samplerStates[4] = SamplerWrapLinear; +}; + +new ShaderData( AL_DeferredShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/postFxV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/lighting/advanced/deferredShadingP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/lighting/advanced/gl/deferredShadingP.glsl"; + + samplerNames[0] = "colorBufferTex"; + samplerNames[1] = "lightDeferredTex"; + samplerNames[2] = "matInfoTex"; + samplerNames[3] = "deferredTex"; + + pixVersion = 2.0; +}; + +singleton PostEffect( AL_DeferredShading ) +{ + renderTime = "PFXAfterBin"; + renderBin = "SkyBin"; + shader = AL_DeferredShader; + stateBlock = AL_DeferredShadingState; + texture[0] = "#color"; + texture[1] = "#lightinfo"; + texture[2] = "#matinfo"; + texture[3] = "#deferred"; + + target = "$backBuffer"; + renderPriority = 10000; + allowReflectPass = true; +}; \ No newline at end of file diff --git a/Templates/BaseGame/game/core/lighting/scripts/lighting.cs b/Templates/BaseGame/game/core/lighting/scripts/lighting.cs new file mode 100644 index 000000000..b7d4034ff --- /dev/null +++ b/Templates/BaseGame/game/core/lighting/scripts/lighting.cs @@ -0,0 +1,74 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +function initLightingSystems(%manager) +{ + echo( "\nInitializing Lighting Systems" ); + + // First exec the scripts for the different light managers + // in the lighting folder. + /*%pattern = "./lighting/*//*init.cs"; + %file = findFirstFile( %pattern ); + if ( %file $= "" ) + { + // Try for DSOs next. + %pattern = "./lighting/*//*init.cs.dso"; + %file = findFirstFile( %pattern ); + } + + while( %file !$= "" ) + { + exec( %file ); + %file = findNextFile( %pattern ); + }*/ + + // Try the perfered one first. + %success = setLightManager(%manager); + + // Did we completely fail to initialize a light manager? + if (!%success) + { + // If we completely failed to initialize a light + // manager then the 3d scene cannot be rendered. + quitWithErrorMessage( "Failed to set a light manager!" ); + } +} + +//--------------------------------------------------------------------------------------------- + +function onLightManagerActivate( %lmName ) +{ + // Call activation callbacks. + %activateNewFn = "onActivate" @ getWord( %lmName, 0 ) @ "LM"; + if( isFunction( %activateNewFn ) ) + eval( %activateNewFn @ "();" ); +} + +//--------------------------------------------------------------------------------------------- + +function onLightManagerDeactivate( %lmName ) +{ + // Call deactivation callback. + %deactivateOldFn = "onDeactivate" @ getWord( %lmName, 0 ) @ "LM"; + if( isFunction( %deactivateOldFn ) ) + eval( %deactivateOldFn @ "();" ); +} diff --git a/Templates/BaseGame/game/core/lighting/scripts/shadowMaps_Init.cs b/Templates/BaseGame/game/core/lighting/scripts/shadowMaps_Init.cs new file mode 100644 index 000000000..f4875bf08 --- /dev/null +++ b/Templates/BaseGame/game/core/lighting/scripts/shadowMaps_Init.cs @@ -0,0 +1,32 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + + +new ShaderData(BlurDepthShader) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/lighting/shadowMap/boxFilterV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/lighting/shadowMap/boxFilterP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/lighting/shadowMap/gl/boxFilterV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/lighting/shadowMap/gl/boxFilterP.glsl"; + pixVersion = 2.0; +}; diff --git a/Templates/BaseGame/game/core/postFX/Core_PostFX.cs b/Templates/BaseGame/game/core/postFX/Core_PostFX.cs new file mode 100644 index 000000000..d36d912ab --- /dev/null +++ b/Templates/BaseGame/game/core/postFX/Core_PostFX.cs @@ -0,0 +1,33 @@ + +function Core_PostFX::onCreate(%this) +{ + // + exec("./scripts/postFx.cs"); + /*exec("./scripts/postFxManager.gui.cs"); + exec("./scripts/postFxManager.gui.settings.cs"); + exec("./scripts/postFxManager.persistance.cs"); + + exec("./scripts/default.postfxpreset.cs"); + + exec("./scripts/caustics.cs"); + exec("./scripts/chromaticLens.cs"); + exec("./scripts/dof.cs"); + exec("./scripts/edgeAA.cs"); + exec("./scripts/flash.cs"); + exec("./scripts/fog.cs"); + exec("./scripts/fxaa.cs"); + exec("./scripts/GammaPostFX.cs"); + exec("./scripts/glow.cs"); + exec("./scripts/hdr.cs"); + exec("./scripts/lightRay.cs"); + exec("./scripts/MLAA.cs"); + exec("./scripts/MotionBlurFx.cs"); + exec("./scripts/ovrBarrelDistortion.cs"); + exec("./scripts/ssao.cs"); + exec("./scripts/turbulence.cs"); + exec("./scripts/vignette.cs");*/ +} + +function Core_PostFX::onDestroy(%this) +{ +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/postFX/Core_PostFX.module b/Templates/BaseGame/game/core/postFX/Core_PostFX.module new file mode 100644 index 000000000..627a32d94 --- /dev/null +++ b/Templates/BaseGame/game/core/postFX/Core_PostFX.module @@ -0,0 +1,10 @@ + + \ No newline at end of file diff --git a/Templates/BaseGame/game/core/postFX/guis/postFxManager.gui b/Templates/BaseGame/game/core/postFX/guis/postFxManager.gui new file mode 100644 index 000000000..6a704eb65 --- /dev/null +++ b/Templates/BaseGame/game/core/postFX/guis/postFxManager.gui @@ -0,0 +1,2755 @@ +//--- OBJECT WRITE BEGIN --- +%guiContent = new GuiControl(PostFXManager) { + position = "0 0"; + extent = "1024 768"; + minExtent = "8 8"; + horizSizing = "width"; + vertSizing = "height"; + profile = "GuiModelessDialogProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "1"; + + new DbgFileView() { + position = "0 0"; + extent = "8 2"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiDefaultProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiWindowCtrl(ppOptionsWindow) { + text = "PostFX Manager"; + resizeWidth = "0"; + resizeHeight = "0"; + canMove = "1"; + canClose = "1"; + canMinimize = "0"; + canMaximize = "0"; + canCollapse = "0"; + closeCommand = "Canvas.popDialog(PostFXManager);"; + edgeSnap = "0"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "306 216"; + extent = "411 336"; + minExtent = "8 8"; + horizSizing = "center"; + vertSizing = "center"; + profile = "GuiWindowProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + + new GuiBitmapBorderCtrl() { + position = "11 77"; + extent = "390 216"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTabBorderProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTabBookCtrl(ppOptionsTabBook) { + tabPosition = "Top"; + tabMargin = "7"; + minTabWidth = "32"; + tabHeight = "20"; + allowReorder = "0"; + defaultPage = "-1"; + selectedPage = "1"; + frontTabPadding = "0"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "11 58"; + extent = "394 233"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTabBookProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + + new GuiTabPageCtrl(ppOptionsSSAOTab) { + fitBook = "0"; + text = "SSAO"; + maxLength = "1024"; + docking = "Client"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "1"; + anchorLeft = "1"; + anchorRight = "1"; + position = "0 20"; + extent = "394 213"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTabPageProfile"; + visible = "0"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Options for the Screen Space Ambient Occlusion postFX"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + + new GuiBitmapBorderCtrl() { + position = "12 30"; + extent = "365 170"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTabBorderProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "1"; + }; + new GuiTabBookCtrl(ppOptionsSSAOOptions) { + tabPosition = "Top"; + tabMargin = "7"; + minTabWidth = "64"; + tabHeight = "20"; + allowReorder = "0"; + defaultPage = "-1"; + selectedPage = "2"; + frontTabPadding = "0"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "12 11"; + extent = "362 185"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTabBookProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + + new GuiTabPageCtrl(ppOptionsSSAOGeneralTab) { + fitBook = "0"; + text = "General"; + maxLength = "1024"; + docking = "Client"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "1"; + anchorLeft = "1"; + anchorRight = "1"; + position = "0 20"; + extent = "362 165"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTabPageProfile"; + visible = "0"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Contains general overall settings for the SSAO postFX"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + + new GuiTextCtrl(ppOptionsSSAOOverallStrengthLabel) { + text = "Overall Strength"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "31 57"; + extent = "77 18"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Controls the overall strength of the Ambient Occlusion effect."; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsSSAOBlurDepthLabel) { + text = "Blur (Softness)"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "38 85"; + extent = "73 18"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Controls the amount of softness in the SSAO, overall."; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsSSAOBlurNormalLabel) { + text = "Blur (Normal Maps)"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "19 112"; + extent = "92 18"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Controls the amount of softness in the SSAO, in the normal maps."; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiPopUpMenuCtrl(ppOptionsSSAOQuality) { + maxPopupHeight = "200"; + sbUsesNAColor = "0"; + reverseTextList = "0"; + bitmapBounds = "16 16"; + text = "Low"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "120 28"; + extent = "211 20"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiPopUpMenuProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsSSAOQualityLabel) { + text = "Quality"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "76 29"; + extent = "32 18"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiSliderCtrl(ppOptionsSSAOOverallStrength) { + range = "0 50"; + ticks = "1000"; + snap = "0"; + value = "2"; + position = "120 56"; + extent = "211 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiSliderCtrl(ppOptionsSSAOBlurDepth) { + range = "0 0.3"; + ticks = "1000"; + snap = "0"; + value = "0.001"; + position = "120 86"; + extent = "211 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiSliderCtrl(ppOptionsSSAOBlurNormal) { + range = "0 1"; + ticks = "1000"; + snap = "0"; + value = "0.95"; + position = "119 113"; + extent = "212 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + }; + new GuiTabPageCtrl(ppOptionsSSAONearTab) { + fitBook = "0"; + text = "Near"; + maxLength = "1024"; + docking = "Client"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "1"; + anchorLeft = "1"; + anchorRight = "1"; + position = "0 20"; + extent = "362 165"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTabPageProfile"; + visible = "0"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Contains settings for the near range ambient occlusion aspect of the SSAO postFX"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + + new GuiSliderCtrl(ppOptionsSSAONearRadius) { + range = "0.001 5"; + ticks = "1000"; + snap = "0"; + value = "0.1"; + position = "122 17"; + extent = "221 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiSliderCtrl(ppOptionsSSAONearDepthMin) { + range = "0 5"; + ticks = "1000"; + snap = "0"; + value = "0.1"; + position = "122 62"; + extent = "221 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiSliderCtrl(ppOptionsSSAONearStrength) { + range = "0 20"; + ticks = "1000"; + snap = "0"; + value = "6"; + position = "122 39"; + extent = "221 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsSSAONearRadiusLabel) { + text = "Radius"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "80 16"; + extent = "34 18"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Controls the near/small radius SSAO reach."; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsSSAONearStrengthLabel) { + text = "Strength"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "73 38"; + extent = "41 18"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Controls the near/small radius SSAO strength."; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsSSAONearDepthMinLabel) { + text = "Depth Min"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "66 61"; + extent = "48 18"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Controls the near/small radius SSAO minimum depth value."; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsSSAONearDepthMaxLabel) { + text = "Depth Max"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "62 85"; + extent = "52 18"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Controls the near/small radius SSAO maximum depth value."; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiSliderCtrl(ppOptionsSSAONearDepthMax) { + range = "0 50"; + ticks = "1000"; + snap = "0"; + value = "1"; + position = "122 86"; + extent = "221 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiSliderCtrl(ppOptionsSSAONearToleranceNormal) { + range = "0 2"; + ticks = "1000"; + snap = "0"; + value = "0"; + position = "122 133"; + extent = "103 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiSliderCtrl(ppOptionsSSAONearTolerancePower) { + range = "0 2"; + ticks = "1000"; + snap = "0"; + value = "1"; + position = "246 133"; + extent = "97 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsSSAONearToleranceLabel2) { + text = "Tolerance / Power"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "24 132"; + extent = "92 18"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsSSAONearToleranceLabel1) { + text = "Normal Maps : "; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "19 113"; + extent = "71 18"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + }; + new GuiTabPageCtrl(ppOptionsSSAOFarTab) { + fitBook = "0"; + text = "Far"; + maxLength = "1024"; + docking = "Client"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "1"; + anchorLeft = "1"; + anchorRight = "1"; + position = "0 20"; + extent = "362 165"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTabPageProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Contains settings for the far range ambient occlusion aspect of the SSAO postFX"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + + new GuiTextCtrl(ppOptionsSSAOFarRadiusLabel) { + text = "Radius"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "80 16"; + extent = "34 18"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Controls the far/large radius SSAO reach."; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiSliderCtrl(ppOptionsSSAOFarRadius) { + range = "0.001 5"; + ticks = "1000"; + snap = "0"; + value = "1"; + position = "122 17"; + extent = "221 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsSSAOFarStrengthLabel) { + text = "Strength"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "73 38"; + extent = "41 18"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Controls the far/large radius SSAO strength."; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiSliderCtrl(ppOptionsSSAOFarStrength) { + range = "0 20"; + ticks = "1000"; + snap = "0"; + value = "10"; + position = "122 39"; + extent = "221 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsSSAOFarDepthMinLabel) { + text = "Depth Min"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "66 61"; + extent = "48 18"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Controls the far/large radius SSAO minimum depth."; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiSliderCtrl(ppOptionsSSAOFarDepthMin) { + range = "0 5"; + ticks = "1000"; + snap = "0"; + value = "0.2"; + position = "122 62"; + extent = "221 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsSSAOFarDepthMaxLabel) { + text = "Depth Max"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "62 85"; + extent = "52 18"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Controls the far/large radius SSAO maximum."; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiSliderCtrl(ppOptionsSSAOFarDepthMax) { + range = "0 5"; + ticks = "1000"; + snap = "0"; + value = "2"; + position = "122 86"; + extent = "221 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsSSAOFarToleranceLabel1) { + text = "Normal Maps :"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "6 113"; + extent = "72 18"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl() { + text = "Tolerance / Power"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "24 132"; + extent = "90 18"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiSliderCtrl(ppOptionsSSAOFarToleranceNormal) { + range = "0 2"; + ticks = "1000"; + snap = "0"; + value = "0"; + position = "122 133"; + extent = "100 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiSliderCtrl(ppOptionsSSAOFarTolerancePower) { + range = "0 2"; + ticks = "1000"; + snap = "0"; + value = "2"; + position = "239 133"; + extent = "104 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + }; + }; + new GuiCheckBoxCtrl(ppOptionsEnableSSAO) { + useInactiveState = "0"; + text = "Enable"; + groupNum = "-1"; + buttonType = "ToggleButton"; + useMouseEvents = "0"; + position = "329 7"; + extent = "53 20"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiCheckBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Enable/Disable the SSAO postFX"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + }; + new GuiTabPageCtrl(ppOptionsHDRTab) { + fitBook = "0"; + text = "HDR"; + maxLength = "1024"; + docking = "Client"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "1"; + anchorLeft = "1"; + anchorRight = "1"; + position = "0 20"; + extent = "394 213"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTabPageProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Options for the High Definition Range Lighting postFX"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + + new GuiBitmapBorderCtrl() { + position = "12 30"; + extent = "363 172"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTabBorderProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "1"; + }; + new GuiTabBookCtrl(ppOptionsHDROptions) { + tabPosition = "Top"; + tabMargin = "7"; + minTabWidth = "64"; + tabHeight = "20"; + allowReorder = "0"; + defaultPage = "-1"; + selectedPage = "0"; + frontTabPadding = "0"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "12 11"; + extent = "365 195"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTabBookProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + + new GuiTabPageCtrl(ppOptionsHDRBrightnessTab) { + fitBook = "0"; + text = "Brightness"; + maxLength = "1024"; + docking = "Client"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "1"; + anchorLeft = "1"; + anchorRight = "1"; + position = "0 20"; + extent = "365 175"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTabPageProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Contains settings related to the brightness of the HDR postFX"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + + new GuiSliderCtrl(ppOptionsHDRMinLuminance) { + range = "0 1"; + ticks = "1000"; + snap = "0"; + value = "0"; + position = "132 77"; + extent = "206 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Value : 0"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiSliderCtrl(ppOptionsHDRKeyValue) { + range = "0 1"; + ticks = "1000"; + snap = "0"; + value = "0.0459184"; + position = "132 50"; + extent = "206 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Value : 0.0459184"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsHDRKeyValueLabel) { + text = "Key Value"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "69 50"; + extent = "52 16"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "The tone mapping middle grey or exposure value used to adjust the overall \"balance\" of the image."; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsHDRMinLuminanceLabel) { + text = "Minimum Luminance"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "25 77"; + extent = "96 16"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "The minimum luminance value to allow when tone mapping the scene. This is particularly useful if your scene is very dark or has a black ambient color in places."; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsHDRWhiteCutoffLabel) { + text = "White Cutoff"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "56 104"; + extent = "65 16"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "The cutoff level for the white levels in the brightness."; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiSliderCtrl(ppOptionsHDRWhiteCutoff) { + range = "0 1"; + ticks = "1000"; + snap = "0"; + value = "0.52551"; + position = "132 104"; + extent = "206 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Value : 0.52551"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiSliderCtrl(ppOptionsHDRBrightnessAdaptRate) { + range = "0.1 10"; + ticks = "1000"; + snap = "0"; + value = "2"; + position = "132 132"; + extent = "205 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsHDRBrightnessAdaptRateLabel) { + text = "Brightness Adapt Rate"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "12 132"; + extent = "109 16"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "The speed at which the view adjusts to the new lighting in the environment."; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsHDRKeyValueLabel1) { + text = "Tone Mapping Contrast"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "10 24"; + extent = "111 16"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Tone mapping contrast is the amount of scene to blend, with the tone mapped HDR scene. Lower values are recommended but higher values give a strong contrasted darker shadowed look."; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiSliderCtrl(ppOptionsHDRToneMappingAmount) { + range = "0 1"; + ticks = "1000"; + snap = "0"; + value = "0.265306"; + position = "132 24"; + extent = "206 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "value : 0.265306"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + }; + new GuiTabPageCtrl(ppOptionsHDRBloomTab) { + fitBook = "0"; + text = "Bloom"; + maxLength = "1024"; + docking = "Client"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "1"; + anchorLeft = "1"; + anchorRight = "1"; + position = "0 20"; + extent = "365 175"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTabPageProfile"; + visible = "0"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Contains settings related to the blooming aspect of the HDR postFX"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + + new GuiSliderCtrl(ppOptionsHDRBloomBlurMultiplier) { + range = "0 5"; + ticks = "1000"; + snap = "0"; + value = "0.502645"; + position = "132 70"; + extent = "199 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Value : 0.502645"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiSliderCtrl(ppOptionsHDRBloomBlurMean) { + range = "0 1"; + ticks = "1000"; + snap = "0"; + value = "0.510526"; + position = "132 97"; + extent = "200 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Value : 0.510526"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiSliderCtrl(ppOptionsHDRBloomBlurStdDev) { + range = "0 3"; + ticks = "1000"; + snap = "0"; + value = "1.4127"; + position = "132 123"; + extent = "199 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Value : 1.4127"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsHDRBlurMultiplierLabel) { + text = "Blur Multiplier"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "59 70"; + extent = "63 16"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "The amount of blur to apply to the bloomed areas in the HDR."; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsHDRBlurMeanLabel) { + text = "Blur \"mean\" value"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "38 97"; + extent = "84 16"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsHDRBlurStandardDevianceLabel) { + text = "Blur \"Std Dev\" value"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "23 123"; + extent = "99 16"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsHDRBloomBrightPassThresholdLabel) { + text = "Bright pass threshold"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "19 43"; + extent = "103 16"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "The bright pass threshold controls how bright the brightest areas of the scene are in the HDR."; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiSliderCtrl(ppOptionsHDRBloomBlurBrightPassThreshold) { + range = "0 5"; + ticks = "1000"; + snap = "0"; + value = "1.60526"; + position = "132 43"; + extent = "200 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Value : 1.60526"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiCheckBoxCtrl(ppOptionsHDRBloom) { + useInactiveState = "0"; + text = " Enable Bloom"; + groupNum = "-1"; + buttonType = "ToggleButton"; + useMouseEvents = "0"; + position = "250 9"; + extent = "85 24"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiCheckBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Enables or disables the bloom (glowing effect) of the HDR PostFX."; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + }; + new GuiTabPageCtrl(ppOptionsHDRBloomEffectsTab) { + fitBook = "0"; + text = "Effects"; + maxLength = "1024"; + docking = "Client"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "1"; + anchorLeft = "1"; + anchorRight = "1"; + position = "0 20"; + extent = "365 175"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTabPageProfile"; + visible = "0"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Contains settings related to the effects the HDR postFX can offer"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + + new GuiCheckBoxCtrl(ppOptionsHDREffectsBlueShift) { + useInactiveState = "0"; + text = " Enable Color Shift"; + groupNum = "-1"; + buttonType = "ToggleButton"; + useMouseEvents = "0"; + position = "11 4"; + extent = "117 24"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiCheckBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Enables a scene tinting/Blue shift based on the color selected below."; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiColorPickerCtrl(ppOptionsHDREffectsBlueShiftColorBlend) { + baseColor = "1 0 0.0235294 1"; + pickColor = "0 0 0 1"; + selectorGap = "1"; + displayMode = "BlendColor"; + actionOnMove = "1"; + showReticle = "1"; + position = "10 29"; + extent = "344 110"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiDefaultProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Select a color"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiColorPickerCtrl(ppOptionsHDREffectsBlueShiftColorBaseColor) { + baseColor = "1 0 0.0235294 1"; + pickColor = "0 0 0 1"; + selectorGap = "1"; + displayMode = "HorizColor"; + actionOnMove = "1"; + showReticle = "1"; + position = "10 142"; + extent = "343 21"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiDefaultProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Select a color"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + }; + }; + new GuiCheckBoxCtrl(ppOptionsHDRToneMapping) { + useInactiveState = "0"; + text = " Enable Tone Mapping"; + groupNum = "-1"; + buttonType = "ToggleButton"; + useMouseEvents = "0"; + position = "18 8"; + extent = "120 24"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiCheckBoxProfile"; + visible = "0"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Enables or disabled tone mapping on the HDR. The tone mapping balanced the brightness levels during the HDR process. Recommended"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiCheckBoxCtrl(ppOptionsEnableHDR) { + useInactiveState = "0"; + text = "Enable"; + groupNum = "-1"; + buttonType = "ToggleButton"; + useMouseEvents = "0"; + position = "329 7"; + extent = "53 20"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiCheckBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Enable/Disable the HDR postFX (takes some time to initialise, be patient)"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiCheckBoxCtrl(ppOptionsEnableHDRDebug) { + useInactiveState = "0"; + text = "Debug"; + groupNum = "-1"; + buttonType = "ToggleButton"; + useMouseEvents = "0"; + position = "262 7"; + extent = "53 20"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiCheckBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + }; + new GuiTabPageCtrl(ppOptionsLightRaysTab) { + fitBook = "0"; + text = "Light Rays"; + maxLength = "1024"; + docking = "Client"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "1"; + anchorLeft = "1"; + anchorRight = "1"; + position = "0 20"; + extent = "394 213"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTabPageProfile"; + visible = "0"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Options for the Light Rays postFX"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + + new GuiSliderCtrl(ppOptionsLightRaysBrightScalar) { + range = "0 5"; + ticks = "1000"; + snap = "0"; + value = "0.75"; + position = "96 46"; + extent = "264 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsLightRaysBrightnessScalarLabel) { + text = "Brightness"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "26 48"; + extent = "87 15"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Controls how bright the rays and the object casting them are in the scene."; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + + new GuiSliderCtrl(ppOptionsLightRaysSampleScalar) { + range = "20 512"; + ticks = "512"; + snap = "0"; + value = "40"; + position = "96 75"; + extent = "264 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + + new GuiTextCtrl(ppOptionsLightRaysSampleScalarLabel) { + text = "Samples"; + maxLength = "512"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "26 76"; + extent = "87 15"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Controls the number of samples for the shader."; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + + new GuiSliderCtrl(ppOptionsLightRaysDensityScalar) { + range = "0.01 1"; + ticks = "1000"; + snap = "0"; + value = "0.94"; + position = "96 105"; + extent = "264 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + + new GuiTextCtrl(ppOptionsLightRaysDensityScalarLabel) { + text = "Density"; + maxLength = "1000"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "26 106"; + extent = "87 15"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Controls the density of the rays."; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + + new GuiSliderCtrl(ppOptionsLightRaysWeightScalar) { + range = "0.1 10"; + ticks = "1000"; + snap = "0"; + value = "5.65"; + position = "96 135"; + extent = "264 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + + new GuiTextCtrl(ppOptionsLightRaysWeightScalarLabel) { + text = "Weight"; + maxLength = "1000"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "26 136"; + extent = "87 15"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Controls the weight of the rays."; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + + + new GuiSliderCtrl(ppOptionsLightRaysDecayScalar) { + range = "0.01 1"; + ticks = "1000"; + snap = "0"; + value = "1.0"; + position = "96 165"; + extent = "264 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + + new GuiTextCtrl(ppOptionsLightRaysDecayScalarLabel) { + text = "Decay"; + maxLength = "1000"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "26 166"; + extent = "87 15"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Controls the decay of the rays."; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiCheckBoxCtrl(ppOptionsEnableLightRays) { + useInactiveState = "0"; + text = "Enable"; + groupNum = "-1"; + buttonType = "ToggleButton"; + useMouseEvents = "0"; + position = "329 7"; + extent = "53 20"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiCheckBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Enable/Disable the light rays postFX"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + }; + new GuiTabPageCtrl(ppOptionsDOFTab) { + fitBook = "0"; + text = "DOF"; + maxLength = "1024"; + docking = "Client"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "1"; + anchorLeft = "1"; + anchorRight = "1"; + position = "0 20"; + extent = "394 213"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTabPageProfile"; + visible = "0"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Options for the Depth Of Field postFX"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + + new GuiBitmapBorderCtrl() { + position = "14 28"; + extent = "362 170"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTabBorderProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "1"; + }; + new GuiTabBookCtrl() { + tabPosition = "Top"; + tabMargin = "7"; + minTabWidth = "64"; + tabHeight = "20"; + allowReorder = "0"; + defaultPage = "-1"; + selectedPage = "1"; + frontTabPadding = "0"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "14 9"; + extent = "360 189"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTabBookProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + + new GuiTabPageCtrl(ppOptionsDOFGeneralTab) { + fitBook = "0"; + text = "General"; + maxLength = "1024"; + docking = "Client"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "1"; + anchorLeft = "1"; + anchorRight = "1"; + position = "0 20"; + extent = "360 169"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTabPageProfile"; + visible = "0"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Contains general settings related to the DOF system"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + + //new GuiCheckBoxCtrl(ppOptionsDOFEnableDOF) { + //useInactiveState = "0"; + //text = "Enable DOF"; + //groupNum = "-1"; + //buttonType = "ToggleButton"; + //useMouseEvents = "0"; + //position = "31 43"; + //extent = "140 30"; + //minExtent = "8 2"; + //horizSizing = "right"; + //vertSizing = "bottom"; + //profile = "GuiCheckBoxProfile"; + //visible = "1"; + //active = "1"; + //tooltipProfile = "GuiToolTipProfile"; + //hovertime = "1000"; + //isContainer = "0"; + //canSave = "1"; + //canSaveDynamicFields = "0"; + //}; + new GuiCheckBoxCtrl(ppOptionsDOFEnableAutoFocus) { + useInactiveState = "0"; + text = "Enable Auto Focus"; + groupNum = "-1"; + buttonType = "ToggleButton"; + useMouseEvents = "0"; + position = "31 8"; + extent = "140 30"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiCheckBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + }; + new GuiTabPageCtrl(ppOptionsDOFAutoFocusTab) { + fitBook = "0"; + text = "Auto Focus"; + maxLength = "1024"; + docking = "Client"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "1"; + anchorLeft = "1"; + anchorRight = "1"; + position = "0 20"; + extent = "360 169"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTabPageProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Contains settings related to the fine control of the auto focus system"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + + new GuiTextCtrl(ppOptionsDOFNearBlurMaxLabel) { + text = "Near Blur Max"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "36 8"; + extent = "67 16"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "The max allowed value of near blur"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiSliderCtrl(ppOptionsDOFFarBlurMinSlider) { + range = "0 1"; + ticks = "1000"; + snap = "0"; + value = "0"; + position = "120 8"; + extent = "224 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsDOFFarBlurMaxLabel) { + text = "Far Blur Max"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "43 34"; + extent = "60 16"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "The max allowed value of far blur"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiSliderCtrl(ppOptionsDOFFarBlurMaxSlider) { + range = "0 1"; + ticks = "1000"; + snap = "0"; + value = "0"; + position = "120 34"; + extent = "224 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsDOFFocusRangeMinLabel) { + text = "Focus Range (Min)"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "13 61"; + extent = "90 16"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "The distance range around the focal distance that remains in focus (in meters, minimum distance in focus) focal distance it is\r\ndependant on the visible distance set in your level"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiSliderCtrl(ppOptionsDOFFocusRangeMinSlider) { + range = "0.01 1e+003"; + ticks = "1000"; + snap = "0"; + value = "0.01"; + position = "120 61"; + extent = "224 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsDOFFocusRangeMaxLabel) { + text = "Focus Range (Max)"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "9 88"; + extent = "95 16"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "The distance range around the focal distance that remains in focus (in meters, maximum distance in focus) focal distance it is\r\ndependant on the visible distance set in your level"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiSliderCtrl(ppOptionsDOFFocusRangeMaxSlider) { + range = "0.01 1e+003"; + ticks = "1000"; + snap = "0"; + value = "0.01"; + position = "119 87"; + extent = "224 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsDOFBurCurveNearLabel) { + text = "Blur Curve Near"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "27 114"; + extent = "77 16"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "A small number causes bluriness to increase gradually\r\nat distances closer than the focal distance. A large number causes bluriness to \r\nincrease quickly"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiSliderCtrl(ppOptionsDOFBlurCurveNearSlider) { + range = "0 50"; + ticks = "1000"; + snap = "0"; + value = "0"; + position = "119 114"; + extent = "225 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsDOFBlurCurveFarLabel) { + text = "Blur Curve Far"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "33 139"; + extent = "70 16"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "A small number causes bluriness to increase gradually\r\nat distances closer than the focal distance. A large number causes bluriness to \r\nincrease quickly"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiSliderCtrl(ppOptionsDOFBlurCurveFarSlider) { + range = "0 50"; + ticks = "1000"; + snap = "0"; + value = "0"; + position = "119 141"; + extent = "224 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + }; + }; + new GuiCheckBoxCtrl(ppOptionsEnableDOF) { + useInactiveState = "0"; + text = "Enable"; + groupNum = "-1"; + buttonType = "ToggleButton"; + useMouseEvents = "0"; + position = "329 7"; + extent = "53 20"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiCheckBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Enable/Disable the Depth of field postFX"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + }; + new GuiTabPageCtrl(ppOptionsVignetteTab) { + fitBook = "0"; + text = "Vignette"; + maxLength = "1024"; + docking = "Client"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "1"; + anchorLeft = "1"; + anchorRight = "1"; + position = "0 40"; + extent = "394 193"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTabPageProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Options for the Vignette postFX"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + Enabled = "1"; + + new GuiCheckBoxCtrl(ppOptionsEnableVignette) { + text = "Enable"; + groupNum = "-1"; + buttonType = "ToggleButton"; + useMouseEvents = "0"; + position = "329 7"; + extent = "53 20"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiCheckBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Enable/Disable the vignette postFX"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiSliderCtrl(ppOptionsVignetteVMax) { + range = "0.001 5"; + ticks = "1000"; + snap = "0"; + value = "0.6"; + position = "96 46"; + extent = "221 17"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiSliderBoxProfile"; + visible = "1"; + active = "1"; + variable = "$VignettePostEffect::VMax"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsVignetteVMaxLabel) { + text = "Radius"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "26 48"; + extent = "41 18"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Controls the maximum exposure of vignetting."; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + }; + new GuiTabPageCtrl() { + fitBook = "0"; + text = "Color Correction"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "8 27"; + extent = "376 200"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTabPageProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "1"; + internalName = "ColorCorrectionTab"; + canSave = "1"; + canSaveDynamicFields = "0"; + + new GuiTextCtrl() { + text = "Color Correction Ramp"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "6 7"; + extent = "118 13"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextEditCtrl() { + historySize = "0"; + tabComplete = "0"; + sinkAllKeyEvents = "0"; + password = "0"; + passwordMask = "*"; + text = "core/postFX/images/null_color_ramp.png"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "6 29"; + extent = "365 18"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextEditProfile"; + visible = "1"; + active = "1"; + altCommand = "ppColorCorrection_selectFileHandler( $thisControl.getText() );"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "1"; + internalName = "ColorCorrectionFileName"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiButtonCtrl() { + text = "Select..."; + groupNum = "-1"; + buttonType = "PushButton"; + useMouseEvents = "0"; + position = "252 54"; + extent = "56 22"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiButtonProfile"; + visible = "1"; + active = "1"; + command = "ppColorCorrection_selectFile();"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + internalName = "ColorCorrectionButton"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiButtonCtrl() { + text = "Reset"; + groupNum = "-1"; + buttonType = "PushButton"; + useMouseEvents = "0"; + position = "315 54"; + extent = "56 22"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiButtonProfile"; + visible = "1"; + active = "1"; + command = "ppColorCorrection_selectFileHandler( \"\" );"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "0"; + internalName = "ColorCorrectionReset"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + }; + }; + new GuiButtonCtrl(ppOptionsApply) { + text = "Apply"; + groupNum = "-1"; + buttonType = "PushButton"; + useMouseEvents = "0"; + position = "309 302"; + extent = "93 23"; + minExtent = "8 8"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiButtonProfile"; + visible = "1"; + active = "1"; + command = "PostFXManager.settingsApplyAll(); Canvas.popDialog(PostFXManager);"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Apply the settings and close this dialog"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiButtonCtrl(ppOptionsSavePreset) { + text = "Save Preset..."; + groupNum = "-1"; + buttonType = "PushButton"; + useMouseEvents = "0"; + position = "111 302"; + extent = "93 23"; + minExtent = "8 8"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiButtonProfile"; + visible = "1"; + active = "1"; + command = "PostFXManager.savePresetFile();"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Save the preset to a file to disk for later use (use postfx::applyPreset)"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiButtonCtrl(ppOptionsLoadPreset) { + text = "Load Preset..."; + groupNum = "-1"; + buttonType = "PushButton"; + useMouseEvents = "0"; + position = "12 302"; + extent = "93 23"; + minExtent = "8 8"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiButtonProfile"; + visible = "1"; + active = "1"; + command = "PostFXManager.loadPresetFile();"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Load a post FX preset file from disk"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiCheckBoxCtrl(ppOptionsEnable) { + useInactiveState = "0"; + text = "Enable PostFX System"; + groupNum = "-1"; + buttonType = "ToggleButton"; + useMouseEvents = "0"; + position = "13 24"; + extent = "127 30"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiCheckBoxProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Enable or Disable the postFX system"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiPopUpMenuCtrl(ppOptionsQuality) { + maxPopupHeight = "200"; + sbUsesNAColor = "0"; + reverseTextList = "0"; + bitmapBounds = "16 16"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "278 30"; + extent = "122 21"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiPopUpMenuProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Used to adjust the quality/performance settings of the PostFX system. Some PostFX may not adhere to the settings in this dialog."; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiTextCtrl(ppOptionsQualityLabel) { + text = "Quality"; + maxLength = "1024"; + margin = "0 0 0 0"; + padding = "0 0 0 0"; + anchorTop = "1"; + anchorBottom = "0"; + anchorLeft = "1"; + anchorRight = "0"; + position = "238 32"; + extent = "39 12"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiTextProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Used to adjust the quality/performance settings of the PostFX system. Some PostFX may not adhere to the settings in this dialog."; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + new GuiButtonCtrl(ppOptionsOk1) { + text = "Revert"; + groupNum = "-1"; + buttonType = "PushButton"; + useMouseEvents = "0"; + position = "210 302"; + extent = "93 23"; + minExtent = "8 8"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiButtonProfile"; + visible = "1"; + active = "1"; + command = "postProcessOptionsDlg.applySettings(); Canvas.popDialog(postProcessOptionsDlg);"; + tooltipProfile = "GuiToolTipProfile"; + tooltip = "Revert any changes made since opening the dialog"; + hovertime = "1000"; + isContainer = "0"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; + }; +}; +//--- OBJECT WRITE END --- diff --git a/Templates/BaseGame/game/core/postFX/images/AreaMap33.dds b/Templates/BaseGame/game/core/postFX/images/AreaMap33.dds new file mode 100644 index 0000000000000000000000000000000000000000..e01982a94528594a375ae6e61c44780a8e1c0b68 GIT binary patch literal 109028 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 RBF+E+002ovPDHLkV1nj@91s8i literal 0 HcmV?d00001 diff --git a/Templates/BaseGame/game/core/postFX/images/caustics_2.png b/Templates/BaseGame/game/core/postFX/images/caustics_2.png new file mode 100644 index 0000000000000000000000000000000000000000..99097fa0ed112c28958363f2951478a0955218ec GIT binary patch literal 33963 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 literal 0 HcmV?d00001 diff --git a/Templates/BaseGame/game/core/postFX/images/inactive-overlay.png b/Templates/BaseGame/game/core/postFX/images/inactive-overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..feab83209cc442c5ad8dc73c2b86e0a8115c4743 GIT binary patch literal 131 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE;=WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!foRZkbkkcwMLfBw9D?8~Obq{gPz9LVg>D`Q%4bP0l+XkKL$W0) literal 0 HcmV?d00001 diff --git a/Templates/BaseGame/game/core/postFX/images/materials.cs b/Templates/BaseGame/game/core/postFX/images/materials.cs new file mode 100644 index 000000000..a13c751b3 --- /dev/null +++ b/Templates/BaseGame/game/core/postFX/images/materials.cs @@ -0,0 +1,32 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +singleton Material( Empty ) +{ +}; + +singleton Material(WarningMaterial) { + detailMap[0] = "missingTexture"; + diffuseColor[0] = "25 16 0"; + emissive[0] = false; + translucent = false; +}; diff --git a/Templates/BaseGame/game/core/postFX/images/missingTexture.png b/Templates/BaseGame/game/core/postFX/images/missingTexture.png new file mode 100644 index 0000000000000000000000000000000000000000..80a7874da967ad523e1a3308f3f14c66d4eed503 GIT binary patch literal 10645 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 IM6N<$f@#CI-2eap literal 0 HcmV?d00001 diff --git a/Templates/BaseGame/game/core/postFX/images/null_color_ramp.png b/Templates/BaseGame/game/core/postFX/images/null_color_ramp.png new file mode 100644 index 0000000000000000000000000000000000000000..5f5a52186eb93cb7ace739e645e5e8f8e6b8050d GIT binary patch literal 2843 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 literal 0 HcmV?d00001 diff --git a/Templates/BaseGame/game/core/postFX/images/warnMat.dds b/Templates/BaseGame/game/core/postFX/images/warnMat.dds new file mode 100644 index 0000000000000000000000000000000000000000..ea99dcbd74a8b2ae49c5cff5a69743498a66e937 GIT binary patch literal 699192 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 literal 0 HcmV?d00001 diff --git a/Templates/BaseGame/game/core/postFX/scripts/GammaPostFX.cs b/Templates/BaseGame/game/core/postFX/scripts/GammaPostFX.cs new file mode 100644 index 000000000..293d44714 --- /dev/null +++ b/Templates/BaseGame/game/core/postFX/scripts/GammaPostFX.cs @@ -0,0 +1,73 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +singleton ShaderData( GammaShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/postFxV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/gammaP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/gl/gammaP.glsl"; + + samplerNames[0] = "$backBuffer"; + samplerNames[1] = "$colorCorrectionTex"; + + pixVersion = 2.0; +}; + +singleton GFXStateBlockData( GammaStateBlock : PFX_DefaultStateBlock ) +{ + samplersDefined = true; + samplerStates[0] = SamplerClampLinear; + samplerStates[1] = SamplerClampLinear; +}; + +singleton PostEffect( GammaPostFX ) +{ + isEnabled = true; + allowReflectPass = true; + + renderTime = "PFXBeforeBin"; + renderBin = "EditorBin"; + renderPriority = 9998; + + shader = GammaShader; + stateBlock = GammaStateBlock; + + texture[0] = "$backBuffer"; + texture[1] = $HDRPostFX::colorCorrectionRamp; + textureSRGB[1] = true; +}; + +function GammaPostFX::preProcess( %this ) +{ + if ( %this.texture[1] !$= $HDRPostFX::colorCorrectionRamp ) + %this.setTexture( 1, $HDRPostFX::colorCorrectionRamp ); +} + +function GammaPostFX::setShaderConsts( %this ) +{ + %clampedGamma = mClamp( $pref::Video::Gamma, 2.0, 2.5); + %this.setShaderConst( "$OneOverGamma", 1 / %clampedGamma ); + %this.setShaderConst( "$Brightness", $pref::Video::Brightness ); + %this.setShaderConst( "$Contrast", $pref::Video::Contrast ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/postFX/scripts/MLAA.cs b/Templates/BaseGame/game/core/postFX/scripts/MLAA.cs new file mode 100644 index 000000000..491c98e4e --- /dev/null +++ b/Templates/BaseGame/game/core/postFX/scripts/MLAA.cs @@ -0,0 +1,186 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// An implementation of "Practical Morphological Anti-Aliasing" from +// GPU Pro 2 by Jorge Jimenez, Belen Masia, Jose I. Echevarria, +// Fernando Navarro, and Diego Gutierrez. +// +// http://www.iryoku.com/mlaa/ + +// NOTE: This is currently disabled in favor of FXAA. See +// core\scripts\client\canvas.cs if you want to re-enable it. + +singleton GFXStateBlockData( MLAA_EdgeDetectStateBlock : PFX_DefaultStateBlock ) +{ + // Mark the edge pixels in stencil. + stencilDefined = true; + stencilEnable = true; + stencilPassOp = GFXStencilOpReplace; + stencilFunc = GFXCmpAlways; + stencilRef = 1; + + samplersDefined = true; + samplerStates[0] = SamplerClampLinear; +}; + +singleton ShaderData( MLAA_EdgeDetectionShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/mlaa/offsetV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/mlaa/edgeDetectionP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/mlaa/gl/offsetV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/mlaa/gl/edgeDetectionP.glsl"; + + samplerNames[0] = "$colorMapG"; + samplerNames[1] = "$deferredMap"; + + pixVersion = 3.0; +}; + +singleton GFXStateBlockData( MLAA_BlendWeightCalculationStateBlock : PFX_DefaultStateBlock ) +{ + // Here we want to process only marked pixels. + stencilDefined = true; + stencilEnable = true; + stencilPassOp = GFXStencilOpKeep; + stencilFunc = GFXCmpEqual; + stencilRef = 1; + + samplersDefined = true; + samplerStates[0] = SamplerClampPoint; + samplerStates[1] = SamplerClampLinear; + samplerStates[2] = SamplerClampPoint; +}; + +singleton ShaderData( MLAA_BlendWeightCalculationShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/mlaa/passthruV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/mlaa/blendWeightCalculationP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/mlaa/gl/passthruV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/mlaa/gl/blendWeightCalculationP.glsl"; + + samplerNames[0] = "$edgesMap"; + samplerNames[1] = "$edgesMapL"; + samplerNames[2] = "$areaMap"; + + pixVersion = 3.0; +}; + +singleton GFXStateBlockData( MLAA_NeighborhoodBlendingStateBlock : PFX_DefaultStateBlock ) +{ + // Here we want to process only marked pixels too. + stencilDefined = true; + stencilEnable = true; + stencilPassOp = GFXStencilOpKeep; + stencilFunc = GFXCmpEqual; + stencilRef = 1; + + samplersDefined = true; + samplerStates[0] = SamplerClampPoint; + samplerStates[1] = SamplerClampLinear; + samplerStates[2] = SamplerClampPoint; +}; + +singleton ShaderData( MLAA_NeighborhoodBlendingShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/mlaa/offsetV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/mlaa/neighborhoodBlendingP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/mlaa/gl/offsetV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/mlaa/gl/neighborhoodBlendingP.glsl"; + + samplerNames[0] = "$blendMap"; + samplerNames[1] = "$colorMapL"; + samplerNames[2] = "$colorMap"; + + pixVersion = 3.0; +}; + + +singleton PostEffect( MLAAFx ) +{ + isEnabled = false; + + allowReflectPass = false; + renderTime = "PFXAfterDiffuse"; + + texture[0] = "$backBuffer"; //colorMapG + texture[1] = "#deferred"; // Used for depth detection + + target = "$outTex"; + targetClear = PFXTargetClear_OnDraw; + targetClearColor = "0 0 0 0"; + + stateBlock = MLAA_EdgeDetectStateBlock; + shader = MLAA_EdgeDetectionShader; + + // The luma calculation weights which can be user adjustable + // per-scene if nessasary. The default value of... + // + // 0.2126 0.7152 0.0722 + // + // ... is the HDTV ITU-R Recommendation BT. 709. + lumaCoefficients = "0.2126 0.7152 0.0722"; + + // The tweakable color threshold used to select + // the range of edge pixels to blend. + threshold = 0.1; + + // The depth delta threshold used to select + // the range of edge pixels to blend. + depthThreshold = 0.01; + + new PostEffect() + { + internalName = "blendingWeightsCalculation"; + + target = "$outTex"; + targetClear = PFXTargetClear_OnDraw; + + shader = MLAA_BlendWeightCalculationShader; + stateBlock = MLAA_BlendWeightCalculationStateBlock; + + texture[0] = "$inTex"; // Edges mask + texture[1] = "$inTex"; // Edges mask + texture[2] = "core/postFX/images/AreaMap33.dds"; + }; + + new PostEffect() + { + internalName = "neighborhoodBlending"; + + shader = MLAA_NeighborhoodBlendingShader; + stateBlock = MLAA_NeighborhoodBlendingStateBlock; + + texture[0] = "$inTex"; // Blend weights + texture[1] = "$backBuffer"; + texture[2] = "$backBuffer"; + }; +}; + +function MLAAFx::setShaderConsts(%this) +{ + %this.setShaderConst("$lumaCoefficients", %this.lumaCoefficients); + %this.setShaderConst("$threshold", %this.threshold); + %this.setShaderConst("$depthThreshold", %this.depthThreshold); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/postFX/scripts/MotionBlurFx.cs b/Templates/BaseGame/game/core/postFX/scripts/MotionBlurFx.cs new file mode 100644 index 000000000..6919cc5a7 --- /dev/null +++ b/Templates/BaseGame/game/core/postFX/scripts/MotionBlurFx.cs @@ -0,0 +1,53 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +singleton ShaderData( PFX_MotionBlurShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/postFxV.hlsl"; //we use the bare-bones postFxV.hlsl + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/motionBlurP.hlsl"; //new pixel shader + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/gl/motionBlurP.glsl"; + + samplerNames[0] = "$backBuffer"; + samplerNames[1] = "$deferredTex"; + + pixVersion = 3.0; +}; + +singleton PostEffect(MotionBlurFX) +{ + isEnabled = false; + + renderTime = "PFXAfterDiffuse"; + + shader = PFX_MotionBlurShader; + stateBlock = PFX_DefaultStateBlock; + texture[0] = "$backbuffer"; + texture[1] = "#deferred"; + target = "$backBuffer"; +}; + +function MotionBlurFX::setShaderConsts(%this) +{ + %this.setShaderConst( "$velocityMultiplier", 3000 ); +} diff --git a/Templates/BaseGame/game/core/postFX/scripts/caustics.cs b/Templates/BaseGame/game/core/postFX/scripts/caustics.cs new file mode 100644 index 000000000..7dcea20a5 --- /dev/null +++ b/Templates/BaseGame/game/core/postFX/scripts/caustics.cs @@ -0,0 +1,64 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +singleton GFXStateBlockData( PFX_CausticsStateBlock : PFX_DefaultStateBlock ) +{ + blendDefined = true; + blendEnable = true; + blendSrc = GFXBlendOne; + blendDest = GFXBlendOne; + + samplersDefined = true; + samplerStates[0] = SamplerClampLinear; + samplerStates[1] = SamplerWrapLinear; + samplerStates[2] = SamplerWrapLinear; +}; + +singleton ShaderData( PFX_CausticsShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/postFxV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/caustics/causticsP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/caustics/gl/causticsP.glsl"; + + samplerNames[0] = "$deferredTex"; + samplerNames[1] = "$causticsTex0"; + samplerNames[2] = "$causticsTex1"; + + pixVersion = 3.0; +}; + +singleton PostEffect( CausticsPFX ) +{ + isEnabled = false; + renderTime = "PFXAfterDiffuse"; + renderBin = "ObjTranslucentBin"; + //renderPriority = 0.1; + + shader = PFX_CausticsShader; + stateBlock = PFX_CausticsStateBlock; + texture[0] = "#deferred"; + texture[1] = "core/postFX/images/caustics_1"; + texture[2] = "core/postFX/images/caustics_2"; + target = "$backBuffer"; +}; diff --git a/Templates/BaseGame/game/core/postFX/scripts/chromaticLens.cs b/Templates/BaseGame/game/core/postFX/scripts/chromaticLens.cs new file mode 100644 index 000000000..06b8d3988 --- /dev/null +++ b/Templates/BaseGame/game/core/postFX/scripts/chromaticLens.cs @@ -0,0 +1,77 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +/// +$CAPostFx::enabled = false; + +/// The lens distortion coefficient. +$CAPostFx::distCoeffecient = -0.05; + +/// The cubic distortion value. +$CAPostFx::cubeDistortionFactor = -0.1; + +/// The amount and direction of the maxium shift for +/// the red, green, and blue channels. +$CAPostFx::colorDistortionFactor = "0.005 -0.005 0.01"; + + +singleton GFXStateBlockData( PFX_DefaultChromaticLensStateBlock ) +{ + zDefined = true; + zEnable = false; + zWriteEnable = false; + samplersDefined = true; + samplerStates[0] = SamplerClampPoint; +}; + +singleton ShaderData( PFX_ChromaticLensShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/postFxV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/chromaticLens.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/gl/chromaticLens.glsl"; + + samplerNames[0] = "$backBuffer"; + + pixVersion = 3.0; +}; + +singleton PostEffect( ChromaticLensPostFX ) +{ + renderTime = "PFXAfterDiffuse"; + renderPriority = 0.2; + isEnabled = false; + allowReflectPass = false; + + shader = PFX_ChromaticLensShader; + stateBlock = PFX_DefaultChromaticLensStateBlock; + texture[0] = "$backBuffer"; + target = "$backBuffer"; +}; + +function ChromaticLensPostFX::setShaderConsts( %this ) +{ + %this.setShaderConst( "$distCoeff", $CAPostFx::distCoeffecient ); + %this.setShaderConst( "$cubeDistort", $CAPostFx::cubeDistortionFactor ); + %this.setShaderConst( "$colorDistort", $CAPostFx::colorDistortionFactor ); +} diff --git a/Templates/BaseGame/game/core/postFX/scripts/default.postfxpreset.cs b/Templates/BaseGame/game/core/postFX/scripts/default.postfxpreset.cs new file mode 100644 index 000000000..6054d52ee --- /dev/null +++ b/Templates/BaseGame/game/core/postFX/scripts/default.postfxpreset.cs @@ -0,0 +1,72 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- +$PostFXManager::Settings::EnableVignette = "1"; +$PostFXManager::Settings::EnableDOF = "1"; +$PostFXManager::Settings::EnabledSSAO = "1"; +$PostFXManager::Settings::EnableHDR = "1"; +$PostFXManager::Settings::EnableLightRays = "1"; +$PostFXManager::Settings::EnablePostFX = "1"; +$PostFXManager::Settings::Vignette::VMax = "0.6"; +$PostFXManager::Settings::DOF::BlurCurveFar = ""; +$PostFXManager::Settings::DOF::BlurCurveNear = ""; +$PostFXManager::Settings::DOF::BlurMax = ""; +$PostFXManager::Settings::DOF::BlurMin = ""; +$PostFXManager::Settings::DOF::EnableAutoFocus = ""; +$PostFXManager::Settings::DOF::EnableDOF = ""; +$PostFXManager::Settings::DOF::FocusRangeMax = ""; +$PostFXManager::Settings::DOF::FocusRangeMin = ""; +$PostFXManager::Settings::HDR::adaptRate = "2"; +$PostFXManager::Settings::HDR::blueShiftColor = "1.05 0.97 1.27"; +$PostFXManager::Settings::HDR::brightPassThreshold = "1"; +$PostFXManager::Settings::HDR::enableBloom = "1"; +$PostFXManager::Settings::HDR::enableBlueShift = "0"; +$PostFXManager::Settings::HDR::enableToneMapping = "0.5"; +$PostFXManager::Settings::HDR::gaussMean = "0"; +$PostFXManager::Settings::HDR::gaussMultiplier = "0.3"; +$PostFXManager::Settings::HDR::gaussStdDev = "0.8"; +$PostFXManager::Settings::HDR::keyValue = "0.18"; +$PostFXManager::Settings::HDR::minLuminace = "0.001"; +$PostFXManager::Settings::HDR::whiteCutoff = "1"; +$PostFXManager::Settings::LightRays::brightScalar = "0.75"; +$PostFXManager::Settings::LightRays::decay = "1.0"; +$PostFXManager::Settings::LightRays::density = "0.94"; +$PostFXManager::Settings::LightRays::numSamples = "40"; +$PostFXManager::Settings::LightRays::weight = "5.65"; +$PostFXManager::Settings::SSAO::blurDepthTol = "0.001"; +$PostFXManager::Settings::SSAO::blurNormalTol = "0.95"; +$PostFXManager::Settings::SSAO::lDepthMax = "2"; +$PostFXManager::Settings::SSAO::lDepthMin = "0.2"; +$PostFXManager::Settings::SSAO::lDepthPow = "0.2"; +$PostFXManager::Settings::SSAO::lNormalPow = "2"; +$PostFXManager::Settings::SSAO::lNormalTol = "-0.5"; +$PostFXManager::Settings::SSAO::lRadius = "1"; +$PostFXManager::Settings::SSAO::lStrength = "10"; +$PostFXManager::Settings::SSAO::overallStrength = "2"; +$PostFXManager::Settings::SSAO::quality = "0"; +$PostFXManager::Settings::SSAO::sDepthMax = "1"; +$PostFXManager::Settings::SSAO::sDepthMin = "0.1"; +$PostFXManager::Settings::SSAO::sDepthPow = "1"; +$PostFXManager::Settings::SSAO::sNormalPow = "1"; +$PostFXManager::Settings::SSAO::sNormalTol = "0"; +$PostFXManager::Settings::SSAO::sRadius = "0.1"; +$PostFXManager::Settings::SSAO::sStrength = "6"; +$PostFXManager::Settings::ColorCorrectionRamp = "core/postFX/images/null_color_ramp.png"; diff --git a/Templates/BaseGame/game/core/postFX/scripts/dof.cs b/Templates/BaseGame/game/core/postFX/scripts/dof.cs new file mode 100644 index 000000000..736c288b2 --- /dev/null +++ b/Templates/BaseGame/game/core/postFX/scripts/dof.cs @@ -0,0 +1,599 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +/* + +================================================================================ + The DOFPostEffect API +================================================================================ + +DOFPostEffect::setFocalDist( %dist ) + +@summary +This method is for manually controlling the focus distance. It will have no +effect if auto focus is currently enabled. Makes use of the parameters set by +setFocusParams. + +@param dist +float distance in meters + +-------------------------------------------------------------------------------- + +DOFPostEffect::setAutoFocus( %enabled ) + +@summary +This method sets auto focus enabled or disabled. Makes use of the parameters set +by setFocusParams. When auto focus is enabled it determines the focal depth +by performing a raycast at the screen-center. + +@param enabled +bool + +-------------------------------------------------------------------------------- + +DOFPostEffect::setFocusParams( %nearBlurMax, %farBlurMax, %minRange, %maxRange, %nearSlope, %farSlope ) + +Set the parameters that control how the near and far equations are calculated +from the focal distance. If you are not using auto focus you will need to call +setFocusParams PRIOR to calling setFocalDist. + +@param nearBlurMax +float between 0.0 and 1.0 +The max allowed value of near blur. + +@param farBlurMax +float between 0.0 and 1.0 +The max allowed value of far blur. + +@param minRange/maxRange +float in meters +The distance range around the focal distance that remains in focus is a lerp +between the min/maxRange using the normalized focal distance as the parameter. +The point is to allow the focal range to expand as you focus farther away since this is +visually appealing. + +Note: since min/maxRange are lerped by the "normalized" focal distance it is +dependant on the visible distance set in your level. + +@param nearSlope +float less than zero +The slope of the near equation. A small number causes bluriness to increase gradually +at distances closer than the focal distance. A large number causes bluriness to +increase quickly. + +@param farSlope +float greater than zero +The slope of the far equation. A small number causes bluriness to increase gradually +at distances farther than the focal distance. A large number causes bluriness to +increase quickly. + +Note: To rephrase, the min/maxRange parameters control how much area around the +focal distance is completely in focus where the near/farSlope parameters control +how quickly or slowly bluriness increases at distances outside of that range. + +================================================================================ + Examples +================================================================================ + +Example1: Turn on DOF while zoomed in with a weapon. + +NOTE: These are not real callbacks! Hook these up to your code where appropriate! + +function onSniperZoom() +{ + // Parameterize how you want DOF to look. + DOFPostEffect.setFocusParams( 0.3, 0.3, 50, 500, -5, 5 ); + + // Turn on auto focus + DOFPostEffect.setAutoFocus( true ); + + // Turn on the PostEffect + DOFPostEffect.enable(); +} + +function onSniperUnzoom() +{ + // Turn off the PostEffect + DOFPostEffect.disable(); +} + +Example2: Manually control DOF with the mouse wheel. + +// Somewhere on startup... + +// Parameterize how you want DOF to look. +DOFPostEffect.setFocusParams( 0.3, 0.3, 50, 500, -5, 5 ); + +// Turn off auto focus +DOFPostEffect.setAutoFocus( false ); + +// Turn on the PostEffect +DOFPostEffect.enable(); + + +NOTE: These are not real callbacks! Hook these up to your code where appropriate! + +function onMouseWheelUp() +{ + // Since setFocalDist is really just a wrapper to assign to the focalDist + // dynamic field we can shortcut and increment it directly. + DOFPostEffect.focalDist += 8; +} + +function onMouseWheelDown() +{ + DOFPostEffect.focalDist -= 8; +} +*/ + +/// This method is for manually controlling the focal distance. It will have no +/// effect if auto focus is currently enabled. Makes use of the parameters set by +/// setFocusParams. +function DOFPostEffect::setFocalDist( %this, %dist ) +{ + %this.focalDist = %dist; +} + +/// This method sets auto focus enabled or disabled. Makes use of the parameters set +/// by setFocusParams. When auto focus is enabled it determine the focal depth +/// by performing a raycast at the screen-center. +function DOFPostEffect::setAutoFocus( %this, %enabled ) +{ + %this.autoFocusEnabled = %enabled; +} + +/// Set the parameters that control how the near and far equations are calculated +/// from the focal distance. If you are not using auto focus you will need to call +/// setFocusParams PRIOR to calling setFocalDist. +function DOFPostEffect::setFocusParams( %this, %nearBlurMax, %farBlurMax, %minRange, %maxRange, %nearSlope, %farSlope ) +{ + %this.nearBlurMax = %nearBlurMax; + %this.farBlurMax = %farBlurMax; + %this.minRange = %minRange; + %this.maxRange = %maxRange; + %this.nearSlope = %nearSlope; + %this.farSlope = %farSlope; +} + +/* + +More information... + +This DOF technique is based on this paper: +http://http.developer.nvidia.com/GPUGems3/gpugems3_ch28.html + +================================================================================ +1. Overview of how we represent "Depth of Field" +================================================================================ + +DOF is expressed as an amount of bluriness per pixel according to its depth. +We represented this by a piecewise linear curve depicted below. + +Note: we also refer to "bluriness" as CoC ( circle of confusion ) which is the term +used in the basis paper and in photography. + + +X-axis (depth) +x = 0.0----------------------------------------------x = 1.0 + +Y-axis (bluriness) +y = 1.0 + | + | ____(x1,y1) (x4,y4)____ + | (ns,nb)\ <--Line1 line2---> /(fe,fb) + | \ / + | \(x2,y2) (x3,y3)/ + | (ne,0)------(fs,0) +y = 0.0 + + +I have labeled the "corners" of this graph with (Xn,Yn) to illustrate that +this is in fact a collection of line segments where the x/y of each point +corresponds to the key below. + +key: +ns - (n)ear blur (s)tart distance +nb - (n)ear (b)lur amount (max value) +ne - (n)ear blur (e)nd distance +fs - (f)ar blur (s)tart distance +fe - (f)ar blur (e)nd distance +fb - (f)ar (b)lur amount (max value) + +Of greatest importance in this graph is Line1 and Line2. Where... +L1 { (x1,y1), (x2,y2) } +L2 { (x3,y3), (x4,y4) } + +Line one represents the amount of "near" blur given a pixels depth and line two +represents the amount of "far" blur at that depth. + +Both these equations are evaluated for each pixel and then the larger of the two +is kept. Also the output blur (for each equation) is clamped between 0 and its +maximum allowable value. + +Therefore, to specify a DOF "qualify" you need to specify the near-blur-line, +far-blur-line, and maximum near and far blur value. + +================================================================================ +2. Abstracting a "focal depth" +================================================================================ + +Although the shader(s) work in terms of a near and far equation it is more +useful to express DOF as an adjustable focal depth and derive the other parameters +"under the hood". + +Given a maximum near/far blur amount and a near/far slope we can calculate the +near/far equations for any focal depth. We extend this to also support a range +of depth around the focal depth that is also in focus and for that range to +shrink or grow as the focal depth moves closer or farther. + +Keep in mind this is only one implementation and depending on the effect you +desire you may which to express the relationship between focal depth and +the shader paramaters different. + +*/ + +//----------------------------------------------------------------------------- +// GFXStateBlockData / ShaderData +//----------------------------------------------------------------------------- + +singleton GFXStateBlockData( PFX_DefaultDOFStateBlock ) +{ + zDefined = true; + zEnable = false; + zWriteEnable = false; + + samplersDefined = true; + samplerStates[0] = SamplerClampPoint; + samplerStates[1] = SamplerClampPoint; +}; + +singleton GFXStateBlockData( PFX_DOFCalcCoCStateBlock ) +{ + zDefined = true; + zEnable = false; + zWriteEnable = false; + + samplersDefined = true; + samplerStates[0] = SamplerClampLinear; + samplerStates[1] = SamplerClampLinear; +}; + +singleton GFXStateBlockData( PFX_DOFDownSampleStateBlock ) +{ + zDefined = true; + zEnable = false; + zWriteEnable = false; + + samplersDefined = true; + samplerStates[0] = SamplerClampLinear; + samplerStates[1] = SamplerClampPoint; +}; + +singleton GFXStateBlockData( PFX_DOFBlurStateBlock ) +{ + zDefined = true; + zEnable = false; + zWriteEnable = false; + + samplersDefined = true; + samplerStates[0] = SamplerClampLinear; +}; + +singleton GFXStateBlockData( PFX_DOFFinalStateBlock ) +{ + zDefined = true; + zEnable = false; + zWriteEnable = false; + + samplersDefined = true; + samplerStates[0] = SamplerClampLinear; + samplerStates[1] = SamplerClampLinear; + samplerStates[2] = SamplerClampLinear; + samplerStates[3] = SamplerClampPoint; + + blendDefined = true; + blendEnable = true; + blendDest = GFXBlendInvSrcAlpha; + blendSrc = GFXBlendOne; +}; + +singleton ShaderData( PFX_DOFDownSampleShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/dof/DOF_DownSample_V.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/dof/DOF_DownSample_P.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/dof/gl/DOF_DownSample_V.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/dof/gl/DOF_DownSample_P.glsl"; + + samplerNames[0] = "$colorSampler"; + samplerNames[1] = "$depthSampler"; + + pixVersion = 3.0; +}; + +singleton ShaderData( PFX_DOFBlurYShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/dof/DOF_Gausian_V.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/dof/DOF_Gausian_P.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/dof/gl/DOF_Gausian_V.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/dof/gl/DOF_Gausian_P.glsl"; + + samplerNames[0] = "$diffuseMap"; + + pixVersion = 2.0; + defines = "BLUR_DIR=float2(0.0,1.0)"; +}; + +singleton ShaderData( PFX_DOFBlurXShader : PFX_DOFBlurYShader ) +{ + defines = "BLUR_DIR=float2(1.0,0.0)"; +}; + +singleton ShaderData( PFX_DOFCalcCoCShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/dof/DOF_CalcCoC_V.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/dof/DOF_CalcCoC_P.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/dof/gl/DOF_CalcCoC_V.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/dof/gl/DOF_CalcCoC_P.glsl"; + + samplerNames[0] = "$shrunkSampler"; + samplerNames[1] = "$blurredSampler"; + + pixVersion = 3.0; +}; + +singleton ShaderData( PFX_DOFSmallBlurShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/dof/DOF_SmallBlur_V.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/dof/DOF_SmallBlur_P.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/dof/gl/DOF_SmallBlur_V.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/dof/gl/DOF_SmallBlur_P.glsl"; + + samplerNames[0] = "$colorSampler"; + + pixVersion = 3.0; +}; + +singleton ShaderData( PFX_DOFFinalShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/dof/DOF_Final_V.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/dof/DOF_Final_P.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/dof/gl/DOF_Final_V.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/dof/gl/DOF_Final_P.glsl"; + + samplerNames[0] = "$colorSampler"; + samplerNames[1] = "$smallBlurSampler"; + samplerNames[2] = "$largeBlurSampler"; + samplerNames[3] = "$depthSampler"; + + pixVersion = 3.0; +}; + +//----------------------------------------------------------------------------- +// PostEffects +//----------------------------------------------------------------------------- + +function DOFPostEffect::onAdd( %this ) +{ + // The weighted distribution of CoC value to the three blur textures + // in the order small, medium, large. Most likely you will not need to + // change this value. + %this.setLerpDist( 0.2, 0.3, 0.5 ); + + // Fill out some default values but DOF really should not be turned on + // without actually specifying your own parameters! + %this.autoFocusEnabled = false; + %this.focalDist = 0.0; + %this.nearBlurMax = 0.5; + %this.farBlurMax = 0.5; + %this.minRange = 50; + %this.maxRange = 500; + %this.nearSlope = -5.0; + %this.farSlope = 5.0; +} + +function DOFPostEffect::setLerpDist( %this, %d0, %d1, %d2 ) +{ + %this.lerpScale = -1.0 / %d0 SPC -1.0 / %d1 SPC -1.0 / %d2 SPC 1.0 / %d2; + %this.lerpBias = 1.0 SPC ( 1.0 - %d2 ) / %d1 SPC 1.0 / %d2 SPC ( %d2 - 1.0 ) / %d2; +} + +singleton PostEffect( DOFPostEffect ) +{ + renderTime = "PFXAfterBin"; + renderBin = "GlowBin"; + renderPriority = 0.1; + + shader = PFX_DOFDownSampleShader; + stateBlock = PFX_DOFDownSampleStateBlock; + texture[0] = "$backBuffer"; + texture[1] = "#deferred"; + target = "#shrunk"; + targetScale = "0.25 0.25"; + + isEnabled = false; +}; + +singleton PostEffect( DOFBlurY ) +{ + shader = PFX_DOFBlurYShader; + stateBlock = PFX_DOFBlurStateBlock; + texture[0] = "#shrunk"; + target = "$outTex"; +}; + +DOFPostEffect.add( DOFBlurY ); + +singleton PostEffect( DOFBlurX ) +{ + shader = PFX_DOFBlurXShader; + stateBlock = PFX_DOFBlurStateBlock; + texture[0] = "$inTex"; + target = "#largeBlur"; +}; + +DOFPostEffect.add( DOFBlurX ); + +singleton PostEffect( DOFCalcCoC ) +{ + shader = PFX_DOFCalcCoCShader; + stateBlock = PFX_DOFCalcCoCStateBlock; + texture[0] = "#shrunk"; + texture[1] = "#largeBlur"; + target = "$outTex"; +}; + +DOFPostEffect.add( DOFCalcCoc ); + +singleton PostEffect( DOFSmallBlur ) +{ + shader = PFX_DOFSmallBlurShader; + stateBlock = PFX_DefaultDOFStateBlock; + texture[0] = "$inTex"; + target = "$outTex"; +}; + +DOFPostEffect.add( DOFSmallBlur ); + +singleton PostEffect( DOFFinalPFX ) +{ + shader = PFX_DOFFinalShader; + stateBlock = PFX_DOFFinalStateBlock; + texture[0] = "$backBuffer"; + texture[1] = "$inTex"; + texture[2] = "#largeBlur"; + texture[3] = "#deferred"; + target = "$backBuffer"; +}; + +DOFPostEffect.add( DOFFinalPFX ); + + +//----------------------------------------------------------------------------- +// Scripts +//----------------------------------------------------------------------------- + +function DOFPostEffect::setShaderConsts( %this ) +{ + if ( %this.autoFocusEnabled ) + %this.autoFocus(); + + %fd = %this.focalDist / $Param::FarDist; + + %range = mLerp( %this.minRange, %this.maxRange, %fd ) / $Param::FarDist * 0.5; + + // We work in "depth" space rather than real-world units for the + // rest of this method... + + // Given the focal distance and the range around it we want in focus + // we can determine the near-end-distance and far-start-distance + + %ned = getMax( %fd - %range, 0.0 ); + %fsd = getMin( %fd + %range, 1.0 ); + + // near slope + %nsl = %this.nearSlope; + + // Given slope of near blur equation and the near end dist and amount (x2,y2) + // solve for the y-intercept + // y = mx + b + // so... + // y - mx = b + + %b = 0.0 - %nsl * %ned; + + %eqNear = %nsl SPC %b SPC 0.0; + + // Do the same for the far blur equation... + + %fsl = %this.farSlope; + + %b = 0.0 - %fsl * %fsd; + + %eqFar = %fsl SPC %b SPC 1.0; + + %this.setShaderConst( "$dofEqWorld", %eqNear ); + DOFFinalPFX.setShaderConst( "$dofEqFar", %eqFar ); + + %this.setShaderConst( "$maxWorldCoC", %this.nearBlurMax ); + DOFFinalPFX.setShaderConst( "$maxFarCoC", %this.farBlurMax ); + + DOFFinalPFX.setShaderConst( "$dofLerpScale", %this.lerpScale ); + DOFFinalPFX.setShaderConst( "$dofLerpBias", %this.lerpBias ); +} + +function DOFPostEffect::autoFocus( %this ) +{ + if ( !isObject( ServerConnection ) || + !isObject( ServerConnection.getCameraObject() ) ) + { + return; + } + + %mask = $TypeMasks::StaticObjectType | $TypeMasks::TerrainObjectType; + %control = ServerConnection.getCameraObject(); + + %fvec = %control.getForwardVector(); + %start = %control.getPosition(); + + %end = VectorAdd( %start, VectorScale( %fvec, $Param::FarDist ) ); + + // Use the client container for this ray cast. + %result = containerRayCast( %start, %end, %mask, %control, true ); + + %hitPos = getWords( %result, 1, 3 ); + + if ( %hitPos $= "" ) + %focDist = $Param::FarDist; + else + %focDist = VectorDist( %hitPos, %start ); + + // For debuging + //$DOF::debug_dist = %focDist; + //$DOF::debug_depth = %focDist / $Param::FarDist; + //echo( "F: " @ %focDist SPC "D: " @ %delta ); + + %this.focalDist = %focDist; +} + + +// For debugging +/* +function reloadDOF() +{ + exec( "./dof.cs" ); + DOFPostEffect.reload(); + DOFPostEffect.disable(); + DOFPostEffect.enable(); +} + +function dofMetricsCallback() +{ + return " | DOF |" @ + " Dist: " @ $DOF::debug_dist @ + " Depth: " @ $DOF::debug_depth; +} +*/ \ No newline at end of file diff --git a/Templates/BaseGame/game/core/postFX/scripts/edgeAA.cs b/Templates/BaseGame/game/core/postFX/scripts/edgeAA.cs new file mode 100644 index 000000000..c3b4263fa --- /dev/null +++ b/Templates/BaseGame/game/core/postFX/scripts/edgeAA.cs @@ -0,0 +1,113 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + + +singleton GFXStateBlockData( PFX_DefaultEdgeAAStateBlock ) +{ + zDefined = true; + zEnable = false; + zWriteEnable = false; + + samplersDefined = true; + samplerStates[0] = SamplerClampPoint; + //samplerStates[1] = SamplerWrapPoint; +}; + +singleton ShaderData( PFX_EdgeAADetectShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/postFxV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/edgeaa/edgeDetectP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/edgeaa/gl/edgeDetectP.glsl"; + + samplerNames[0] = "$deferredBuffer"; + + pixVersion = 3.0; +}; + +singleton ShaderData( PFX_EdgeAAShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/edgeaa/edgeAAV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/edgeaa/edgeAAP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/edgeaa/gl/edgeAAV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/edgeaa/gl/edgeAAP.glsl"; + + samplerNames[0] = "$edgeBuffer"; + samplerNames[1] = "$backBuffer"; + + pixVersion = 3.0; +}; + +singleton ShaderData( PFX_EdgeAADebugShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/postFxV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/edgeaa/dbgEdgeDisplayP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/edgeaa/gl/dbgEdgeDisplayP.glsl"; + + samplerNames[0] = "$edgeBuffer"; + + pixVersion = 3.0; +}; + +singleton PostEffect( EdgeDetectPostEffect ) +{ + renderTime = "PFXBeforeBin"; + renderBin = "ObjTranslucentBin"; + //renderPriority = 0.1; + targetScale = "0.5 0.5"; + + shader = PFX_EdgeAADetectShader; + stateBlock = PFX_DefaultEdgeAAStateBlock; + texture[0] = "#deferred"; + target = "#edge"; + + isEnabled = true; +}; + +singleton PostEffect( EdgeAAPostEffect ) +{ + renderTime = "PFXAfterDiffuse"; + //renderBin = "ObjTranslucentBin"; + //renderPriority = 0.1; + + shader = PFX_EdgeAAShader; + stateBlock = PFX_DefaultEdgeAAStateBlock; + texture[0] = "#edge"; + texture[1] = "$backBuffer"; + target = "$backBuffer"; +}; + +singleton PostEffect( Debug_EdgeAAPostEffect ) +{ + renderTime = "PFXAfterDiffuse"; + //renderBin = "ObjTranslucentBin"; + //renderPriority = 0.1; + + shader = PFX_EdgeAADebugShader; + stateBlock = PFX_DefaultEdgeAAStateBlock; + texture[0] = "#edge"; + target = "$backBuffer"; +}; \ No newline at end of file diff --git a/Templates/BaseGame/game/core/postFX/scripts/flash.cs b/Templates/BaseGame/game/core/postFX/scripts/flash.cs new file mode 100644 index 000000000..1c97c6411 --- /dev/null +++ b/Templates/BaseGame/game/core/postFX/scripts/flash.cs @@ -0,0 +1,63 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +singleton ShaderData( PFX_FlashShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/postFxV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/flashP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/gl/flashP.glsl"; + + samplerNames[0] = "$backBuffer"; + + defines = "WHITE_COLOR=float4(1.0,1.0,1.0,0.0);MUL_COLOR=float4(1.0,0.25,0.25,0.0)"; + + pixVersion = 2.0; +}; + +singleton PostEffect( FlashFx ) +{ + isEnabled = false; + allowReflectPass = false; + + renderTime = "PFXAfterDiffuse"; + + shader = PFX_FlashShader; + texture[0] = "$backBuffer"; + renderPriority = 10; + stateBlock = PFX_DefaultStateBlock; +}; + +function FlashFx::setShaderConsts( %this ) +{ + if ( isObject( ServerConnection ) ) + { + %this.setShaderConst( "$damageFlash", ServerConnection.getDamageFlash() ); + %this.setShaderConst( "$whiteOut", ServerConnection.getWhiteOut() ); + } + else + { + %this.setShaderConst( "$damageFlash", 0 ); + %this.setShaderConst( "$whiteOut", 0 ); + } +} diff --git a/Templates/BaseGame/game/core/postFX/scripts/fog.cs b/Templates/BaseGame/game/core/postFX/scripts/fog.cs new file mode 100644 index 000000000..4b9bfc663 --- /dev/null +++ b/Templates/BaseGame/game/core/postFX/scripts/fog.cs @@ -0,0 +1,135 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +// Fog +//------------------------------------------------------------------------------ + +singleton ShaderData( FogPassShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/postFxV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/fogP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/gl/fogP.glsl"; + + samplerNames[0] = "$deferredTex"; + + pixVersion = 2.0; +}; + + +singleton GFXStateBlockData( FogPassStateBlock : PFX_DefaultStateBlock ) +{ + blendDefined = true; + blendEnable = true; + blendSrc = GFXBlendSrcAlpha; + blendDest = GFXBlendInvSrcAlpha; +}; + + +singleton PostEffect( FogPostFx ) +{ + // We forward render the reflection pass + // so it does its own fogging. + allowReflectPass = false; + + renderTime = "PFXBeforeBin"; + renderBin = "ObjTranslucentBin"; + + shader = FogPassShader; + stateBlock = FogPassStateBlock; + texture[0] = "#deferred"; + + renderPriority = 5; + + targetFormat = getBestHDRFormat(); + isEnabled = true; +}; + + +//------------------------------------------------------------------------------ +// UnderwaterFog +//------------------------------------------------------------------------------ + +singleton ShaderData( UnderwaterFogPassShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/postFxV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/underwaterFogP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/gl/underwaterFogP.glsl"; + + samplerNames[0] = "$deferredTex"; + samplerNames[1] = "$backbuffer"; + samplerNames[2] = "$waterDepthGradMap"; + + pixVersion = 2.0; +}; + + +singleton GFXStateBlockData( UnderwaterFogPassStateBlock : PFX_DefaultStateBlock ) +{ + samplersDefined = true; + samplerStates[0] = SamplerClampPoint; + samplerStates[1] = SamplerClampPoint; + samplerStates[2] = SamplerClampLinear; +}; + + +singleton PostEffect( UnderwaterFogPostFx ) +{ + oneFrameOnly = true; + onThisFrame = false; + + // Let the fog effect render during the + // reflection pass. + allowReflectPass = true; + + renderTime = "PFXBeforeBin"; + renderBin = "ObjTranslucentBin"; + + shader = UnderwaterFogPassShader; + stateBlock = UnderwaterFogPassStateBlock; + texture[0] = "#deferred"; + texture[1] = "$backBuffer"; + texture[2] = "#waterDepthGradMap"; + + // Needs to happen after the FogPostFx + renderPriority = 4; + + isEnabled = true; +}; + +function UnderwaterFogPostFx::onEnabled( %this ) +{ + TurbulenceFx.enable(); + CausticsPFX.enable(); + return true; +} + +function UnderwaterFogPostFx::onDisabled( %this ) +{ + TurbulenceFx.disable(); + CausticsPFX.disable(); + return false; +} diff --git a/Templates/BaseGame/game/core/postFX/scripts/fxaa.cs b/Templates/BaseGame/game/core/postFX/scripts/fxaa.cs new file mode 100644 index 000000000..4b81c6e19 --- /dev/null +++ b/Templates/BaseGame/game/core/postFX/scripts/fxaa.cs @@ -0,0 +1,64 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// An implementation of "NVIDIA FXAA 3.11" by TIMOTHY LOTTES +// +// http://timothylottes.blogspot.com/ +// +// The shader is tuned for the defaul quality and good performance. +// See shaders\common\postFx\fxaa\fxaaP.hlsl to tweak the internal +// quality and performance settings. + +singleton GFXStateBlockData( FXAA_StateBlock : PFX_DefaultStateBlock ) +{ + samplersDefined = true; + samplerStates[0] = SamplerClampLinear; +}; + +singleton ShaderData( FXAA_ShaderData ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/fxaa/fxaaV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/fxaa/fxaaP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/fxaa/gl/fxaaV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/fxaa/gl/fxaaP.glsl"; + + samplerNames[0] = "$colorTex"; + + pixVersion = 3.0; +}; + +singleton PostEffect( FXAA_PostEffect ) +{ + isEnabled = false; + + allowReflectPass = false; + renderTime = "PFXAfterDiffuse"; + + texture[0] = "$backBuffer"; + + target = "$backBuffer"; + + stateBlock = FXAA_StateBlock; + shader = FXAA_ShaderData; +}; + diff --git a/Templates/BaseGame/game/core/postFX/scripts/glow.cs b/Templates/BaseGame/game/core/postFX/scripts/glow.cs new file mode 100644 index 000000000..0f062f6f7 --- /dev/null +++ b/Templates/BaseGame/game/core/postFX/scripts/glow.cs @@ -0,0 +1,184 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + + +singleton ShaderData( PFX_GlowBlurVertShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/glowBlurV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/glowBlurP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/glowBlurV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/gl/glowBlurP.glsl"; + + defines = "BLUR_DIR=float2(0.0,1.0)"; + + samplerNames[0] = "$diffuseMap"; + + pixVersion = 2.0; +}; + + +singleton ShaderData( PFX_GlowBlurHorzShader : PFX_GlowBlurVertShader ) +{ + defines = "BLUR_DIR=float2(1.0,0.0)"; +}; + + +singleton GFXStateBlockData( PFX_GlowCombineStateBlock : PFX_DefaultStateBlock ) +{ + // Use alpha test to save some fillrate + // on the non-glowing areas of the scene. + alphaDefined = true; + alphaTestEnable = true; + alphaTestRef = 1; + alphaTestFunc = GFXCmpGreaterEqual; + + // Do a one to one blend. + blendDefined = true; + blendEnable = true; + blendSrc = GFXBlendOne; + blendDest = GFXBlendOne; +}; + + +singleton PostEffect( GlowPostFx ) +{ + // Do not allow the glow effect to work in reflection + // passes by default so we don't do the extra drawing. + allowReflectPass = false; + + renderTime = "PFXAfterBin"; + renderBin = "GlowBin"; + renderPriority = 1; + + // First we down sample the glow buffer. + shader = PFX_PassthruShader; + stateBlock = PFX_DefaultStateBlock; + texture[0] = "#glowbuffer"; + target = "$outTex"; + targetScale = "0.5 0.5"; + + isEnabled = true; + + // Blur vertically + new PostEffect() + { + shader = PFX_GlowBlurVertShader; + stateBlock = PFX_DefaultStateBlock; + texture[0] = "$inTex"; + target = "$outTex"; + }; + + // Blur horizontally + new PostEffect() + { + shader = PFX_GlowBlurHorzShader; + stateBlock = PFX_DefaultStateBlock; + texture[0] = "$inTex"; + target = "$outTex"; + }; + + // Upsample and combine with the back buffer. + new PostEffect() + { + shader = PFX_PassthruShader; + stateBlock = PFX_GlowCombineStateBlock; + texture[0] = "$inTex"; + target = "$backBuffer"; + }; +}; + +singleton ShaderData( PFX_VolFogGlowBlurVertShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/glowBlurV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/VolFogGlowP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/glowBlurV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/gl/VolFogGlowP.glsl"; + + defines = "BLUR_DIR=float2(0.0,1.0)"; + samplerNames[0] = "$diffuseMap"; + pixVersion = 2.0; +}; +singleton ShaderData( PFX_VolFogGlowBlurHorzShader : PFX_VolFogGlowBlurVertShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/glowBlurV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/VolFogGlowP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/glowBlurV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/gl/VolFogGlowP.glsl"; + + defines = "BLUR_DIR=float2(1.0,0.0)"; +}; + +$VolFogGlowPostFx::glowStrength = 0.3; + +singleton PostEffect( VolFogGlowPostFx ) +{ + // Do not allow the glow effect to work in reflection + // passes by default so we don't do the extra drawing. + allowReflectPass = false; + renderTime = "PFXAfterBin"; + renderBin = "FogBin"; + renderPriority = 1; + // First we down sample the glow buffer. + shader = PFX_PassthruShader; + stateBlock = PFX_DefaultStateBlock; + texture[0] = "$backbuffer"; + target = "$outTex"; + targetScale = "0.5 0.5"; + isEnabled = true; + // Blur vertically + new PostEffect() + { + shader = PFX_VolFogGlowBlurVertShader; + stateBlock = PFX_DefaultStateBlock; + internalName = "vert"; + texture[0] = "$inTex"; + target = "$outTex"; + }; + // Blur horizontally + new PostEffect() + { + shader = PFX_VolFogGlowBlurHorzShader; + stateBlock = PFX_DefaultStateBlock; + internalName = "hor"; + texture[0] = "$inTex"; + target = "$outTex"; + }; + // Upsample and combine with the back buffer. + new PostEffect() + { + shader = PFX_PassthruShader; + stateBlock = PFX_GlowCombineStateBlock; + texture[0] = "$inTex"; + target = "$backBuffer"; + }; +}; + +function VolFogGlowPostFx::setShaderConsts( %this ) +{ + %vp=%this-->vert; + %vp.setShaderConst( "$strength", $VolFogGlowPostFx::glowStrength ); + %vp=%this-->hor; + %vp.setShaderConst( "$strength", $VolFogGlowPostFx::glowStrength ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/postFX/scripts/hdr.cs b/Templates/BaseGame/game/core/postFX/scripts/hdr.cs new file mode 100644 index 000000000..3b2de8b7b --- /dev/null +++ b/Templates/BaseGame/game/core/postFX/scripts/hdr.cs @@ -0,0 +1,529 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + + +/// Blends between the scene and the tone mapped scene. +$HDRPostFX::enableToneMapping = 0.5; + +/// The tone mapping middle grey or exposure value used +/// to adjust the overall "balance" of the image. +/// +/// 0.18 is fairly common value. +/// +$HDRPostFX::keyValue = 0.18; + +/// The minimum luninace value to allow when tone mapping +/// the scene. Is particularly useful if your scene very +/// dark or has a black ambient color in places. +$HDRPostFX::minLuminace = 0.001; + +/// The lowest luminance value which is mapped to white. This +/// is usually set to the highest visible luminance in your +/// scene. By setting this to smaller values you get a contrast +/// enhancement. +$HDRPostFX::whiteCutoff = 1.0; + +/// The rate of adaptation from the previous and new +/// average scene luminance. +$HDRPostFX::adaptRate = 2.0; + +/// Blends between the scene and the blue shifted version +/// of the scene for a cinematic desaturated night effect. +$HDRPostFX::enableBlueShift = 0.0; + +/// The blue shift color value. +$HDRPostFX::blueShiftColor = "1.05 0.97 1.27"; + + +/// Blends between the scene and the bloomed scene. +$HDRPostFX::enableBloom = 1.0; + +/// The threshold luminace value for pixels which are +/// considered "bright" and need to be bloomed. +$HDRPostFX::brightPassThreshold = 1.0; + +/// These are used in the gaussian blur of the +/// bright pass for the bloom effect. +$HDRPostFX::gaussMultiplier = 0.3; +$HDRPostFX::gaussMean = 0.0; +$HDRPostFX::gaussStdDev = 0.8; + +/// The 1x255 color correction ramp texture used +/// by both the HDR shader and the GammaPostFx shader +/// for doing full screen color correction. +$HDRPostFX::colorCorrectionRamp = "core/postFX/images/null_color_ramp.png"; + + +singleton ShaderData( HDR_BrightPassShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/postFxV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/hdr/brightPassFilterP.hlsl"; + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/hdr/gl/brightPassFilterP.glsl"; + + samplerNames[0] = "$inputTex"; + samplerNames[1] = "$luminanceTex"; + + pixVersion = 3.0; +}; + +singleton ShaderData( HDR_DownScale4x4Shader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/hdr/downScale4x4V.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/hdr/downScale4x4P.hlsl"; + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/hdr/gl/downScale4x4V.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/hdr/gl/downScale4x4P.glsl"; + + samplerNames[0] = "$inputTex"; + + pixVersion = 2.0; +}; + +singleton ShaderData( HDR_BloomGaussBlurHShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/postFxV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/hdr/bloomGaussBlurHP.hlsl"; + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/hdr/gl/bloomGaussBlurHP.glsl"; + + samplerNames[0] = "$inputTex"; + + pixVersion = 3.0; +}; + +singleton ShaderData( HDR_BloomGaussBlurVShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/postFxV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/hdr/bloomGaussBlurVP.hlsl"; + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/hdr/gl/bloomGaussBlurVP.glsl"; + + samplerNames[0] = "$inputTex"; + + pixVersion = 3.0; +}; + +singleton ShaderData( HDR_SampleLumShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/postFxV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/hdr/sampleLumInitialP.hlsl"; + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/hdr/gl/sampleLumInitialP.glsl"; + + samplerNames[0] = "$inputTex"; + + pixVersion = 3.0; +}; + +singleton ShaderData( HDR_DownSampleLumShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/postFxV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/hdr/sampleLumIterativeP.hlsl"; + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/hdr/gl/sampleLumIterativeP.glsl"; + + samplerNames[0] = "$inputTex"; + + pixVersion = 3.0; +}; + +singleton ShaderData( HDR_CalcAdaptedLumShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/postFxV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/hdr/calculateAdaptedLumP.hlsl"; + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/hdr/gl/calculateAdaptedLumP.glsl"; + + samplerNames[0] = "$currLum"; + samplerNames[1] = "$lastAdaptedLum"; + + pixVersion = 3.0; +}; + +singleton ShaderData( HDR_CombineShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/postFxV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/hdr/finalPassCombineP.hlsl"; + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/hdr/gl/finalPassCombineP.glsl"; + + samplerNames[0] = "$sceneTex"; + samplerNames[1] = "$luminanceTex"; + samplerNames[2] = "$bloomTex"; + samplerNames[3] = "$colorCorrectionTex"; + samplerNames[4] = "deferredTex"; + + pixVersion = 3.0; +}; + + +singleton GFXStateBlockData( HDR_SampleStateBlock : PFX_DefaultStateBlock ) +{ + samplersDefined = true; + samplerStates[0] = SamplerClampPoint; + samplerStates[1] = SamplerClampPoint; +}; + +singleton GFXStateBlockData( HDR_DownSampleStateBlock : PFX_DefaultStateBlock ) +{ + samplersDefined = true; + samplerStates[0] = SamplerClampLinear; + samplerStates[1] = SamplerClampLinear; +}; + +singleton GFXStateBlockData( HDR_CombineStateBlock : PFX_DefaultStateBlock ) +{ + samplersDefined = true; + samplerStates[0] = SamplerClampPoint; + samplerStates[1] = SamplerClampLinear; + samplerStates[2] = SamplerClampLinear; + samplerStates[3] = SamplerClampLinear; +}; + +singleton GFXStateBlockData( HDRStateBlock ) +{ + samplersDefined = true; + samplerStates[0] = SamplerClampLinear; + samplerStates[1] = SamplerClampLinear; + samplerStates[2] = SamplerClampLinear; + samplerStates[3] = SamplerClampLinear; + + blendDefined = true; + blendDest = GFXBlendOne; + blendSrc = GFXBlendZero; + + zDefined = true; + zEnable = false; + zWriteEnable = false; + + cullDefined = true; + cullMode = GFXCullNone; +}; + + +function HDRPostFX::setShaderConsts( %this ) +{ + %this.setShaderConst( "$brightPassThreshold", $HDRPostFX::brightPassThreshold ); + %this.setShaderConst( "$g_fMiddleGray", $HDRPostFX::keyValue ); + + %bloomH = %this-->bloomH; + %bloomH.setShaderConst( "$gaussMultiplier", $HDRPostFX::gaussMultiplier ); + %bloomH.setShaderConst( "$gaussMean", $HDRPostFX::gaussMean ); + %bloomH.setShaderConst( "$gaussStdDev", $HDRPostFX::gaussStdDev ); + + %bloomV = %this-->bloomV; + %bloomV.setShaderConst( "$gaussMultiplier", $HDRPostFX::gaussMultiplier ); + %bloomV.setShaderConst( "$gaussMean", $HDRPostFX::gaussMean ); + %bloomV.setShaderConst( "$gaussStdDev", $HDRPostFX::gaussStdDev ); + + %minLuminace = $HDRPostFX::minLuminace; + if ( %minLuminace <= 0.0 ) + { + // The min should never be pure zero else the + // log() in the shader will generate INFs. + %minLuminace = 0.00001; + } + %this-->adaptLum.setShaderConst( "$g_fMinLuminace", %minLuminace ); + + %this-->finalLum.setShaderConst( "$adaptRate", $HDRPostFX::adaptRate ); + + %combinePass = %this-->combinePass; + %combinePass.setShaderConst( "$g_fEnableToneMapping", $HDRPostFX::enableToneMapping ); + %combinePass.setShaderConst( "$g_fMiddleGray", $HDRPostFX::keyValue ); + %combinePass.setShaderConst( "$g_fBloomScale", $HDRPostFX::enableBloom ); + %combinePass.setShaderConst( "$g_fEnableBlueShift", $HDRPostFX::enableBlueShift ); + %combinePass.setShaderConst( "$g_fBlueShiftColor", $HDRPostFX::blueShiftColor ); + + %clampedGamma = mClamp( $pref::Video::Gamma, 2.0, 2.5); + %combinePass.setShaderConst( "$g_fOneOverGamma", 1 / %clampedGamma ); + %combinePass.setShaderConst( "$Brightness", $pref::Video::Brightness ); + %combinePass.setShaderConst( "$Contrast", $pref::Video::Contrast ); + + %whiteCutoff = ( $HDRPostFX::whiteCutoff * $HDRPostFX::whiteCutoff ) * + ( $HDRPostFX::whiteCutoff * $HDRPostFX::whiteCutoff ); + %combinePass.setShaderConst( "$g_fWhiteCutoff", %whiteCutoff ); +} + +function HDRPostFX::preProcess( %this ) +{ + %combinePass = %this-->combinePass; + + if ( %combinePass.texture[3] !$= $HDRPostFX::colorCorrectionRamp ) + %combinePass.setTexture( 3, $HDRPostFX::colorCorrectionRamp ); +} + +function HDRPostFX::onEnabled( %this ) +{ + // See what HDR format would be best. + %format = getBestHDRFormat(); + if ( %format $= "" || %format $= "GFXFormatR8G8B8A8" ) + { + // We didn't get a valid HDR format... so fail. + return false; + } + + // HDR does it's own gamma calculation so + // disable this postFx. + GammaPostFX.disable(); + + // Set the right global shader define for HDR. + if ( %format $= "GFXFormatR10G10B10A2" ) + addGlobalShaderMacro( "TORQUE_HDR_RGB10" ); + else if ( %format $= "GFXFormatR16G16B16A16" ) + addGlobalShaderMacro( "TORQUE_HDR_RGB16" ); + + echo( "HDR FORMAT: " @ %format ); + + // Change the format of the offscreen surface + // to an HDR compatible format. + AL_FormatToken.format = %format; + setReflectFormat( %format ); + + // Reset the light manager which will ensure the new + // hdr encoding takes effect in all the shaders and + // that the offscreen surface is enabled. + resetLightManager(); + + return true; +} + +function HDRPostFX::onDisabled( %this ) +{ + // Enable a special GammaCorrection PostFX when this is disabled. + GammaPostFX.enable(); + + // Restore the non-HDR offscreen surface format. + %format = getBestHDRFormat(); + AL_FormatToken.format = %format; + setReflectFormat( %format ); + + removeGlobalShaderMacro( "TORQUE_HDR_RGB10" ); + removeGlobalShaderMacro( "TORQUE_HDR_RGB16" ); + + // Reset the light manager which will ensure the new + // hdr encoding takes effect in all the shaders. + resetLightManager(); +} + +singleton PostEffect( HDRPostFX ) +{ + isEnabled = false; + allowReflectPass = false; + + // Resolve the HDR before we render any editor stuff + // and before we resolve the scene to the backbuffer. + renderTime = "PFXBeforeBin"; + renderBin = "EditorBin"; + renderPriority = 9999; + + // The bright pass generates a bloomed version of + // the scene for pixels which are brighter than a + // fixed threshold value. + // + // This is then used in the final HDR combine pass + // at the end of this post effect chain. + // + + shader = HDR_BrightPassShader; + stateBlock = HDR_DownSampleStateBlock; + texture[0] = "$backBuffer"; + texture[1] = "#adaptedLum"; + target = "$outTex"; + targetFormat = "GFXFormatR16G16B16A16F"; + targetScale = "0.5 0.5"; + + new PostEffect() + { + allowReflectPass = false; + shader = HDR_DownScale4x4Shader; + stateBlock = HDR_DownSampleStateBlock; + texture[0] = "$inTex"; + target = "$outTex"; + targetFormat = "GFXFormatR16G16B16A16F"; + targetScale = "0.25 0.25"; + }; + + new PostEffect() + { + allowReflectPass = false; + internalName = "bloomH"; + + shader = HDR_BloomGaussBlurHShader; + stateBlock = HDR_DownSampleStateBlock; + texture[0] = "$inTex"; + target = "$outTex"; + targetFormat = "GFXFormatR16G16B16A16F"; + }; + + new PostEffect() + { + allowReflectPass = false; + internalName = "bloomV"; + + shader = HDR_BloomGaussBlurVShader; + stateBlock = HDR_DownSampleStateBlock; + texture[0] = "$inTex"; + target = "#bloomFinal"; + targetFormat = "GFXFormatR16G16B16A16F"; + }; + + // BrightPass End + + // Now calculate the adapted luminance. + new PostEffect() + { + allowReflectPass = false; + internalName = "adaptLum"; + + shader = HDR_SampleLumShader; + stateBlock = HDR_DownSampleStateBlock; + texture[0] = "$backBuffer"; + target = "$outTex"; + targetScale = "0.0625 0.0625"; // 1/16th + targetFormat = "GFXFormatR16F"; + + new PostEffect() + { + allowReflectPass = false; + shader = HDR_DownSampleLumShader; + stateBlock = HDR_DownSampleStateBlock; + texture[0] = "$inTex"; + target = "$outTex"; + targetScale = "0.25 0.25"; // 1/4 + targetFormat = "GFXFormatR16F"; + }; + + new PostEffect() + { + allowReflectPass = false; + shader = HDR_DownSampleLumShader; + stateBlock = HDR_DownSampleStateBlock; + texture[0] = "$inTex"; + target = "$outTex"; + targetScale = "0.25 0.25"; // 1/4 + targetFormat = "GFXFormatR16F"; + }; + + new PostEffect() + { + allowReflectPass = false; + shader = HDR_DownSampleLumShader; + stateBlock = HDR_DownSampleStateBlock; + texture[0] = "$inTex"; + target = "$outTex"; + targetScale = "0.25 0.25"; // At this point the target should be 1x1. + targetFormat = "GFXFormatR16F"; + }; + + // Note that we're reading the adapted luminance + // from the previous frame when generating this new + // one... PostEffect takes care to manage that. + new PostEffect() + { + allowReflectPass = false; + internalName = "finalLum"; + shader = HDR_CalcAdaptedLumShader; + stateBlock = HDR_DownSampleStateBlock; + texture[0] = "$inTex"; + texture[1] = "#adaptedLum"; + target = "#adaptedLum"; + targetFormat = "GFXFormatR16F"; + targetClear = "PFXTargetClear_OnCreate"; + targetClearColor = "1 1 1 1"; + }; + }; + + // Output the combined bloom and toned mapped + // version of the scene. + new PostEffect() + { + allowReflectPass = false; + internalName = "combinePass"; + + shader = HDR_CombineShader; + stateBlock = HDR_CombineStateBlock; + texture[0] = "$backBuffer"; + texture[1] = "#adaptedLum"; + texture[2] = "#bloomFinal"; + texture[3] = $HDRPostFX::colorCorrectionRamp; + target = "$backBuffer"; + }; +}; + +singleton ShaderData( LuminanceVisShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/postFxV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/hdr/luminanceVisP.hlsl"; + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/hdr/gl/luminanceVisP.glsl"; + + samplerNames[0] = "$inputTex"; + + pixVersion = 3.0; +}; + +singleton GFXStateBlockData( LuminanceVisStateBlock : PFX_DefaultStateBlock ) +{ + samplersDefined = true; + samplerStates[0] = SamplerClampLinear; +}; + +function LuminanceVisPostFX::setShaderConsts( %this ) +{ + %this.setShaderConst( "$brightPassThreshold", $HDRPostFX::brightPassThreshold ); +} + +singleton PostEffect( LuminanceVisPostFX ) +{ + isEnabled = false; + allowReflectPass = false; + + // Render before we do any editor rendering. + renderTime = "PFXBeforeBin"; + renderBin = "EditorBin"; + renderPriority = 9999; + + shader = LuminanceVisShader; + stateBlock = LuminanceVisStateBlock; + texture[0] = "$backBuffer"; + target = "$backBuffer"; + //targetScale = "0.0625 0.0625"; // 1/16th + //targetFormat = "GFXFormatR16F"; +}; + +function LuminanceVisPostFX::onEnabled( %this ) +{ + if ( !HDRPostFX.isEnabled() ) + { + HDRPostFX.enable(); + } + + HDRPostFX.skip = true; + + return true; +} + +function LuminanceVisPostFX::onDisabled( %this ) +{ + HDRPostFX.skip = false; +} + diff --git a/Templates/BaseGame/game/core/postFX/scripts/lightRay.cs b/Templates/BaseGame/game/core/postFX/scripts/lightRay.cs new file mode 100644 index 000000000..523b9bdea --- /dev/null +++ b/Templates/BaseGame/game/core/postFX/scripts/lightRay.cs @@ -0,0 +1,110 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + + +$LightRayPostFX::brightScalar = 0.75; +$LightRayPostFX::numSamples = 40; +$LightRayPostFX::density = 0.94; +$LightRayPostFX::weight = 5.65; +$LightRayPostFX::decay = 1.0; +$LightRayPostFX::exposure = 0.0005; +$LightRayPostFX::resolutionScale = 1.0; + + +singleton ShaderData( LightRayOccludeShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/postFxV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/lightRay/lightRayOccludeP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/lightRay/gl/lightRayOccludeP.glsl"; + + samplerNames[0] = "$backBuffer"; + samplerNames[1] = "$deferredTex"; + + pixVersion = 3.0; +}; + +singleton ShaderData( LightRayShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/postFxV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/lightRay/lightRayP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/lightRay/gl/lightRayP.glsl"; + + samplerNames[0] = "$frameSampler"; + samplerNames[1] = "$backBuffer"; + + pixVersion = 3.0; +}; + +singleton GFXStateBlockData( LightRayStateBlock : PFX_DefaultStateBlock ) +{ + samplersDefined = true; + samplerStates[0] = SamplerClampLinear; + samplerStates[1] = SamplerClampLinear; +}; + +singleton PostEffect( LightRayPostFX ) +{ + isEnabled = false; + allowReflectPass = false; + + renderTime = "PFXBeforeBin"; + renderBin = "EditorBin"; + renderPriority = 10; + + shader = LightRayOccludeShader; + stateBlock = LightRayStateBlock; + texture[0] = "$backBuffer"; + texture[1] = "#deferred"; + target = "$outTex"; + targetFormat = "GFXFormatR16G16B16A16F"; + + new PostEffect() + { + shader = LightRayShader; + stateBlock = LightRayStateBlock; + internalName = "final"; + texture[0] = "$inTex"; + texture[1] = "$backBuffer"; + target = "$backBuffer"; + }; +}; + +function LightRayPostFX::preProcess( %this ) +{ + %this.targetScale = $LightRayPostFX::resolutionScale SPC $LightRayPostFX::resolutionScale; +} + +function LightRayPostFX::setShaderConsts( %this ) +{ + %this.setShaderConst( "$brightScalar", $LightRayPostFX::brightScalar ); + + %pfx = %this-->final; + %pfx.setShaderConst( "$numSamples", $LightRayPostFX::numSamples ); + %pfx.setShaderConst( "$density", $LightRayPostFX::density ); + %pfx.setShaderConst( "$weight", $LightRayPostFX::weight ); + %pfx.setShaderConst( "$decay", $LightRayPostFX::decay ); + %pfx.setShaderConst( "$exposure", $LightRayPostFX::exposure ); +} diff --git a/Templates/BaseGame/game/core/postFX/scripts/ovrBarrelDistortion.cs b/Templates/BaseGame/game/core/postFX/scripts/ovrBarrelDistortion.cs new file mode 100644 index 000000000..1ea280863 --- /dev/null +++ b/Templates/BaseGame/game/core/postFX/scripts/ovrBarrelDistortion.cs @@ -0,0 +1,167 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// Only load these shaders if an Oculus VR device is present +if(!isFunction(isOculusVRDeviceActive)) + return; + +//----------------------------------------------------------------------------- +// Shader data +//----------------------------------------------------------------------------- + +singleton ShaderData( OVRMonoToStereoShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/postFxV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/oculusvr/monoToStereoP.hlsl"; + + //OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.hlsl"; + //OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/oculusvr/gl/monoToStereoP.glsl"; + + samplerNames[0] = "$backBuffer"; + + pixVersion = 2.0; +}; + +singleton ShaderData( OVRBarrelDistortionShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/postFxV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/oculusvr/barrelDistortionP.hlsl"; + + //OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.glsl"; + //OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/oculusvr/gl/barrelDistortionP.glsl"; + + samplerNames[0] = "$backBuffer"; + + pixVersion = 2.0; +}; + +singleton ShaderData( OVRBarrelDistortionChromaShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/postFxV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/oculusvr/barrelDistortionChromaP.hlsl"; + + pixVersion = 2.0; +}; + +//----------------------------------------------------------------------------- +// GFX state blocks +//----------------------------------------------------------------------------- + +singleton GFXStateBlockData( OVRBarrelDistortionStateBlock : PFX_DefaultStateBlock ) +{ + samplersDefined = true; + samplerStates[0] = SamplerClampLinear; +}; + +//----------------------------------------------------------------------------- +// Barrel Distortion PostFx +// +// To be used with the Oculus Rift. +// Expects a stereo pair to exist on the back buffer and then applies the +// appropriate barrel distortion. +//----------------------------------------------------------------------------- +singleton BarrelDistortionPostEffect( OVRBarrelDistortionPostFX ) +{ + isEnabled = false; + allowReflectPass = false; + + renderTime = "PFXAfterDiffuse"; + renderPriority = 100; + + // The barrel distortion + shader = OVRBarrelDistortionShader; + stateBlock = OVRBarrelDistortionStateBlock; + + texture[0] = "$backBuffer"; + + scaleOutput = 1.25; +}; + +//----------------------------------------------------------------------------- +// Barrel Distortion with Chromatic Aberration Correction PostFx +// +// To be used with the Oculus Rift. +// Expects a stereo pair to exist on the back buffer and then applies the +// appropriate barrel distortion. +// This version applies a chromatic aberration correction during the +// barrel distortion. +//----------------------------------------------------------------------------- +singleton BarrelDistortionPostEffect( OVRBarrelDistortionChromaPostFX ) +{ + isEnabled = false; + allowReflectPass = false; + + renderTime = "PFXAfterDiffuse"; + renderPriority = 100; + + // The barrel distortion + shader = OVRBarrelDistortionChromaShader; + stateBlock = OVRBarrelDistortionStateBlock; + + texture[0] = "$backBuffer"; + + scaleOutput = 1.25; +}; + +//----------------------------------------------------------------------------- +// Barrel Distortion Mono PostFx +// +// To be used with the Oculus Rift. +// Takes a non-stereo image and turns it into a stereo pair with barrel +// distortion applied. Only a vertical slice around the center of the back +// buffer is used to generate the pseudo stereo pair. +//----------------------------------------------------------------------------- +singleton PostEffect( OVRBarrelDistortionMonoPostFX ) +{ + isEnabled = false; + allowReflectPass = false; + + renderTime = "PFXAfterDiffuse"; + renderPriority = 100; + + // Converts the mono display to a stereo one + shader = OVRMonoToStereoShader; + stateBlock = OVRBarrelDistortionStateBlock; + + texture[0] = "$backBuffer"; + target = "$outTex"; + + // The actual barrel distortion + new BarrelDistortionPostEffect(OVRBarrelDistortionMonoStage2PostFX) + { + shader = OVRBarrelDistortionShader; + stateBlock = OVRBarrelDistortionStateBlock; + texture[0] = "$inTex"; + target = "$backBuffer"; + + scaleOutput = 1.25; + }; + +}; + +function OVRBarrelDistortionMonoPostFX::setShaderConsts( %this ) +{ + %HMDIndex = 0; + + %xOffsets = getOVRHMDEyeXOffsets(%HMDIndex); + %this.setShaderConst( "$LensXOffsets", %xOffsets ); +} diff --git a/Templates/BaseGame/game/core/postFX/scripts/postFx.cs b/Templates/BaseGame/game/core/postFX/scripts/postFx.cs new file mode 100644 index 000000000..fe931a994 --- /dev/null +++ b/Templates/BaseGame/game/core/postFX/scripts/postFx.cs @@ -0,0 +1,88 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +singleton ShaderData( PFX_PassthruShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/postFxV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/passthruP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/gl/passthruP.glsl"; + + samplerNames[0] = "$inputTex"; + + pixVersion = 2.0; +}; + +function postFXInit() +{ + exec("core/postFX/guis/postFxManager.gui"); + + //Load the core postFX files themselves + if (!$Server::Dedicated) + { + //init the postFX + %pattern = "./*.cs"; + %file = findFirstFile( %pattern ); + if ( %file $= "" ) + { + // Try for DSOs next. + %pattern = "core/postFX/*.cs.dso"; + %file = findFirstFile( %pattern ); + } + + while( %file !$= "" ) + { + exec( %file ); + %file = findNextFile( %pattern ); + } + } +} + +function PostEffect::inspectVars( %this ) +{ + %name = %this.getName(); + %globals = "$" @ %name @ "::*"; + inspectVars( %globals ); +} + +function PostEffect::viewDisassembly( %this ) +{ + %file = %this.dumpShaderDisassembly(); + + if ( %file $= "" ) + { + echo( "PostEffect::viewDisassembly - no shader disassembly found." ); + } + else + { + echo( "PostEffect::viewDisassembly - shader disassembly file dumped ( " @ %file @ " )." ); + openFile( %file ); + } +} + +// Return true if we really want the effect enabled. +// By default this is the case. +function PostEffect::onEnabled( %this ) +{ + return true; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/postFX/scripts/postFxManager.gui.cs b/Templates/BaseGame/game/core/postFX/scripts/postFxManager.gui.cs new file mode 100644 index 000000000..a6b0f0f01 --- /dev/null +++ b/Templates/BaseGame/game/core/postFX/scripts/postFxManager.gui.cs @@ -0,0 +1,446 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +$PostFXManager::vebose = true; +function postVerbose(%string) +{ + if($PostFXManager::vebose == true) + { + echo(%string); + } +} + +function PostFXManager::onDialogPush( %this ) +{ + //Apply the settings to the controls + postVerbose("% - PostFX Manager - Loading GUI."); + + %this.settingsRefreshAll(); +} + +// :: Controls for the overall postFX manager dialog +function ppOptionsEnable::onAction(%this) +{ + //Disable / Enable all PostFX + + if(ppOptionsEnable.getValue()) + { + %toEnable = true; + } + else + { + %toEnable = false; + } + + PostFXManager.settingsSetEnabled(%toEnable); + +} + +function PostFXManager::getEnableResultFromControl(%this, %control) +{ + %toEnable = -1; + %bTest = %control.getValue(); + if(%bTest == 1) + { + %toEnable = true; + } + else + { + %toEnable = false; + } + + return %toEnable; +} + +function ppOptionsEnableSSAO::onAction(%this) +{ + %toEnable = PostFXManager.getEnableResultFromControl(%this); + PostFXManager.settingsEffectSetEnabled("SSAO", %toEnable); +} + +function ppOptionsEnableHDR::onAction(%this) +{ + %toEnable = PostFXManager.getEnableResultFromControl(%this); + PostFXManager.settingsEffectSetEnabled("HDR", %toEnable); +} + +function ppOptionsEnableLightRays::onAction(%this) +{ + %toEnable = PostFXManager.getEnableResultFromControl(%this); + PostFXManager.settingsEffectSetEnabled("LightRays", %toEnable); +} + +function ppOptionsEnableDOF::onAction(%this) +{ + %toEnable = PostFXManager.getEnableResultFromControl(%this); + PostFXManager.settingsEffectSetEnabled("DOF", %toEnable); +} + +function ppOptionsEnableVignette::onAction(%this) +{ + %toEnable = PostFXManager.getEnableResultFromControl(%this); + PostFXManager.settingsEffectSetEnabled("Vignette", %toEnable); +} + +function ppOptionsSavePreset::onClick(%this) +{ + //Stores the current settings into a preset file for loading and use later on +} + +function ppOptionsLoadPreset::onClick(%this) +{ + //Loads and applies the settings from a postfxpreset file +} + + +//Other controls, Quality dropdown +function ppOptionsSSAOQuality::onSelect( %this, %id, %text ) +{ + if(%id > -1 && %id < 3) + { + $SSAOPostFx::quality = %id; + } +} + +//SSAO Slider controls +//General Tab +function ppOptionsSSAOOverallStrength::onMouseDragged(%this) +{ + $SSAOPostFx::overallStrength = %this.value; + %this.ToolTip = "Value : " @ %this.value; +} + +function ppOptionsSSAOBlurDepth::onMouseDragged(%this) +{ + $SSAOPostFx::blurDepthTol = %this.value; + %this.ToolTip = "Value : " @ %this.value; +} + +function ppOptionsSSAOBlurNormal::onMouseDragged(%this) +{ + $SSAOPostFx::blurNormalTol = %this.value; + %this.ToolTip = "Value : " @ %this.value; +} + +//Near Tab +function ppOptionsSSAONearRadius::onMouseDragged(%this) +{ + $SSAOPostFx::sRadius = %this.value; + %this.ToolTip = "Value : " @ %this.value; +} + +function ppOptionsSSAONearStrength::onMouseDragged(%this) +{ + $SSAOPostFx::sStrength = %this.value; + %this.ToolTip = "Value : " @ %this.value; +} + +function ppOptionsSSAONearDepthMin::onMouseDragged(%this) +{ + $SSAOPostFx::sDepthMin = %this.value; + %this.ToolTip = "Value : " @ %this.value; +} + +function ppOptionsSSAONearDepthMax::onMouseDragged(%this) +{ + $SSAOPostFx::sDepthMax = %this.value; + %this.ToolTip = "Value : " @ %this.value; +} + +function ppOptionsSSAONearToleranceNormal::onMouseDragged(%this) +{ + $SSAOPostFx::sNormalTol = %this.value; + %this.ToolTip = "Value : " @ %this.value; +} + +function ppOptionsSSAONearTolerancePower::onMouseDragged(%this) +{ + $SSAOPostFx::sNormalPow = %this.value; + %this.ToolTip = "Value : " @ %this.value; +} + +//Far Tab +function ppOptionsSSAOFarRadius::onMouseDragged(%this) +{ + $SSAOPostFx::lRadius = %this.value; + %this.ToolTip = "Value : " @ %this.value; +} +function ppOptionsSSAOFarStrength::onMouseDragged(%this) +{ + $SSAOPostFx::lStrength = %this.value; + %this.ToolTip = "Value : " @ %this.value; +} +function ppOptionsSSAOFarDepthMin::onMouseDragged(%this) +{ + $SSAOPostFx::lDepthMin = %this.value; + %this.ToolTip = "Value : " @ %this.value; +} +function ppOptionsSSAOFarDepthMax::onMouseDragged(%this) +{ + $SSAOPostFx::lDepthMax = %this.value; + %this.ToolTip = "Value : " @ %this.value; +} +function ppOptionsSSAOFarToleranceNormal::onMouseDragged(%this) +{ + $SSAOPostFx::lNormalTol = %this.value; + %this.ToolTip = "Value : " @ %this.value; +} +function ppOptionsSSAOFarTolerancePower::onMouseDragged(%this) +{ + $SSAOPostFx::lNormalPow = %this.value; + %this.ToolTip = "Value : " @ %this.value; +} + +//HDR Slider Controls +//Brighness tab + +function ppOptionsHDRToneMappingAmount::onMouseDragged(%this) +{ + + $HDRPostFX::enableToneMapping = %this.value; + %this.ToolTip = "value : " @ %this.value; +} + +function ppOptionsHDRKeyValue::onMouseDragged(%this) +{ + $HDRPostFX::keyValue = %this.value; + %this.ToolTip = "Value : " @ %this.value; +} + +function ppOptionsHDRMinLuminance::onMouseDragged(%this) +{ + $HDRPostFX::minLuminace = %this.value; + %this.ToolTip = "Value : " @ %this.value; +} + +function ppOptionsHDRWhiteCutoff::onMouseDragged(%this) +{ + $HDRPostFX::whiteCutoff = %this.value; + %this.ToolTip = "Value : " @ %this.value; +} + +function ppOptionsHDRBrightnessAdaptRate::onMouseDragged(%this) +{ + $HDRPostFX::adaptRate = %this.value; + %this.ToolTip = "Value : " @ %this.value; +} + +//Blur tab +function ppOptionsHDRBloomBlurBrightPassThreshold::onMouseDragged(%this) +{ + $HDRPostFX::brightPassThreshold = %this.value; + %this.ToolTip = "Value : " @ %this.value; +} + +function ppOptionsHDRBloomBlurMultiplier::onMouseDragged(%this) +{ + $HDRPostFX::gaussMultiplier = %this.value; + %this.ToolTip = "Value : " @ %this.value; +} + +function ppOptionsHDRBloomBlurMean::onMouseDragged(%this) +{ + $HDRPostFX::gaussMean = %this.value; + %this.ToolTip = "Value : " @ %this.value; +} + +function ppOptionsHDRBloomBlurStdDev::onMouseDragged(%this) +{ + $HDRPostFX::gaussStdDev = %this.value; + %this.ToolTip = "Value : " @ %this.value; +} + +function ppOptionsHDRBloom::onAction(%this) +{ + $HDRPostFX::enableBloom = %this.getValue(); +} + +function ppOptionsHDRToneMapping::onAction(%this) +{ + //$HDRPostFX::enableToneMapping = %this.getValue(); +} + +function ppOptionsHDREffectsBlueShift::onAction(%this) +{ + $HDRPostFX::enableBlueShift = %this.getValue(); +} + + +//Controls for color range in blue Shift dialog + +function ppOptionsHDREffectsBlueShiftColorBlend::onAction(%this) +{ + $HDRPostFX::blueShiftColor = %this.PickColor; + %this.ToolTip = "Color Values : " @ %this.PickColor; +} + +function ppOptionsHDREffectsBlueShiftColorBaseColor::onAction(%this) +{ + //This one feeds the one above + ppOptionsHDREffectsBlueShiftColorBlend.baseColor = %this.PickColor; + %this.ToolTip = "Color Values : " @ %this.PickColor; +} + + +//Light rays Brightness Slider Controls +function ppOptionsLightRaysBrightScalar::onMouseDragged(%this) +{ + $LightRayPostFX::brightScalar = %this.value; + %this.ToolTip = "Value : " @ %this.value; +} +//Light rays Number of Samples Slider Control +function ppOptionsLightRaysSampleScalar::onMouseDragged(%this) +{ + $LightRayPostFX::numSamples = %this.value; + %this.ToolTip = "Value : " @ %this.value; +} +//Light rays Density Slider Control +function ppOptionsLightRaysDensityScalar::onMouseDragged(%this) +{ + $LightRayPostFX::density = %this.value; + %this.ToolTip = "Value : " @ %this.value; +} +//Light rays Weight Slider Control +function ppOptionsLightRaysWeightScalar::onMouseDragged(%this) +{ + $LightRayPostFX::weight = %this.value; + %this.ToolTip = "Value : " @ %this.value; +} +//Light rays Decay Slider Control +function ppOptionsLightRaysDecayScalar::onMouseDragged(%this) +{ + $LightRayPostFX::decay = %this.value; + %this.ToolTip = "Value : " @ %this.value; +} + + +function ppOptionsUpdateDOFSettings() +{ + DOFPostEffect.setFocusParams( $DOFPostFx::BlurMin, $DOFPostFx::BlurMax, $DOFPostFx::FocusRangeMin, $DOFPostFx::FocusRangeMax, -($DOFPostFx::BlurCurveNear), $DOFPostFx::BlurCurveFar ); + + DOFPostEffect.setAutoFocus( $DOFPostFx::EnableAutoFocus ); + DOFPostEffect.setFocalDist(0); + + if($PostFXManager::PostFX::EnableDOF) + { + DOFPostEffect.enable(); + } + else + { + DOFPostEffect.disable(); + } +} + +//DOF General Tab +//DOF Toggles +function ppOptionsDOFEnableDOF::onAction(%this) +{ + $PostFXManager::PostFX::EnableDOF = %this.getValue(); + ppOptionsUpdateDOFSettings(); +} + + +function ppOptionsDOFEnableAutoFocus::onAction(%this) +{ + $DOFPostFx::EnableAutoFocus = %this.getValue(); + DOFPostEffect.setAutoFocus( %this.getValue() ); +} + +//DOF AutoFocus Slider controls +function ppOptionsDOFFarBlurMinSlider::onMouseDragged(%this) +{ + $DOFPostFx::BlurMin = %this.value; + ppOptionsUpdateDOFSettings(); +} + +function ppOptionsDOFFarBlurMaxSlider::onMouseDragged(%this) +{ + $DOFPostFx::BlurMax = %this.value; + ppOptionsUpdateDOFSettings(); +} + +function ppOptionsDOFFocusRangeMinSlider::onMouseDragged(%this) +{ + $DOFPostFx::FocusRangeMin = %this.value; + ppOptionsUpdateDOFSettings(); +} + +function ppOptionsDOFFocusRangeMaxSlider::onMouseDragged(%this) +{ + $DOFPostFx::FocusRangeMax = %this.value; + ppOptionsUpdateDOFSettings(); +} + +function ppOptionsDOFBlurCurveNearSlider::onMouseDragged(%this) +{ + $DOFPostFx::BlurCurveNear = %this.value; + ppOptionsUpdateDOFSettings(); +} + +function ppOptionsDOFBlurCurveFarSlider::onMouseDragged(%this) +{ + $DOFPostFx::BlurCurveFar = %this.value; + ppOptionsUpdateDOFSettings(); +} + +function ppOptionsEnableHDRDebug::onAction(%this) +{ + if ( %this.getValue() ) + LuminanceVisPostFX.enable(); + else + LuminanceVisPostFX.disable(); +} + +function ppOptionsUpdateVignetteSettings() +{ + if($PostFXManager::PostFX::EnableVignette) + { + VignettePostEffect.enable(); + } + else + { + VignettePostEffect.disable(); + } +} + +function ppOptionsVignetteEnableVignette::onAction(%this) +{ + $PostFXManager::PostFX::EnableVignette = %this.getValue(); + ppOptionsUpdateVignetteSettings(); +} + +function ppColorCorrection_selectFile() +{ + %filter = "Image Files (*.png, *.jpg, *.dds, *.bmp, *.gif, *.jng. *.tga)|*.png;*.jpg;*.dds;*.bmp;*.gif;*.jng;*.tga|All Files (*.*)|*.*|"; + getLoadFilename( %filter, "ppColorCorrection_selectFileHandler"); +} + +function ppColorCorrection_selectFileHandler( %filename ) +{ + if ( %filename $= "" || !isFile( %filename ) ) + %filename = "core/postFX/images/null_color_ramp.png"; + else + %filename = makeRelativePath( %filename, getMainDotCsDir() ); + + $HDRPostFX::colorCorrectionRamp = %filename; + PostFXManager-->ColorCorrectionFileName.Text = %filename; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/postFX/scripts/postFxManager.gui.settings.cs b/Templates/BaseGame/game/core/postFX/scripts/postFxManager.gui.settings.cs new file mode 100644 index 000000000..eefcd9b7e --- /dev/null +++ b/Templates/BaseGame/game/core/postFX/scripts/postFxManager.gui.settings.cs @@ -0,0 +1,439 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +$PostFXManager::defaultPreset = "./default.postfxpreset.cs"; + +function PostFXManager::settingsSetEnabled(%this, %bEnablePostFX) +{ + $PostFXManager::PostFX::Enabled = %bEnablePostFX; + + //if to enable the postFX, apply the ones that are enabled + if ( %bEnablePostFX ) + { + //SSAO, HDR, LightRays, DOF + + if ( $PostFXManager::PostFX::EnableSSAO ) + SSAOPostFx.enable(); + else + SSAOPostFx.disable(); + + if ( $PostFXManager::PostFX::EnableHDR ) + HDRPostFX.enable(); + else + HDRPostFX.disable(); + + if ( $PostFXManager::PostFX::EnableLightRays ) + LightRayPostFX.enable(); + else + LightRayPostFX.disable(); + + if ( $PostFXManager::PostFX::EnableDOF ) + DOFPostEffect.enable(); + else + DOFPostEffect.disable(); + + if ( $PostFXManager::PostFX::EnableVignette ) + VignettePostEffect.enable(); + else + VignettePostEffect.disable(); + + postVerbose("% - PostFX Manager - PostFX enabled"); + } + else + { + //Disable all postFX + + SSAOPostFx.disable(); + HDRPostFX.disable(); + LightRayPostFX.disable(); + DOFPostEffect.disable(); + VignettePostEffect.disable(); + + postVerbose("% - PostFX Manager - PostFX disabled"); + } + + VolFogGlowPostFx.disable(); +} + +function PostFXManager::settingsEffectSetEnabled(%this, %sName, %bEnable) +{ + %postEffect = 0; + + //Determine the postFX to enable, and apply the boolean + if(%sName $= "SSAO") + { + %postEffect = SSAOPostFx; + $PostFXManager::PostFX::EnableSSAO = %bEnable; + //$pref::PostFX::SSAO::Enabled = %bEnable; + } + else if(%sName $= "HDR") + { + %postEffect = HDRPostFX; + $PostFXManager::PostFX::EnableHDR = %bEnable; + //$pref::PostFX::HDR::Enabled = %bEnable; + } + else if(%sName $= "LightRays") + { + %postEffect = LightRayPostFX; + $PostFXManager::PostFX::EnableLightRays = %bEnable; + //$pref::PostFX::LightRays::Enabled = %bEnable; + } + else if(%sName $= "DOF") + { + %postEffect = DOFPostEffect; + $PostFXManager::PostFX::EnableDOF = %bEnable; + //$pref::PostFX::DOF::Enabled = %bEnable; + } + else if(%sName $= "Vignette") + { + %postEffect = VignettePostEffect; + $PostFXManager::PostFX::EnableVignette = %bEnable; + //$pref::PostFX::Vignette::Enabled = %bEnable; + } + + // Apply the change + if ( %bEnable == true ) + { + %postEffect.enable(); + postVerbose("% - PostFX Manager - " @ %sName @ " enabled"); + } + else + { + %postEffect.disable(); + postVerbose("% - PostFX Manager - " @ %sName @ " disabled"); + } +} + +function PostFXManager::settingsRefreshSSAO(%this) +{ + //Apply the enabled flag + ppOptionsEnableSSAO.setValue($PostFXManager::PostFX::EnableSSAO); + + //Add the items we need to display + ppOptionsSSAOQuality.clear(); + ppOptionsSSAOQuality.add("Low", 0); + ppOptionsSSAOQuality.add("Medium", 1); + ppOptionsSSAOQuality.add("High", 2); + + //Set the selected, after adding the items! + ppOptionsSSAOQuality.setSelected($SSAOPostFx::quality); + + //SSAO - Set the values of the sliders, General Tab + ppOptionsSSAOOverallStrength.setValue($SSAOPostFx::overallStrength); + ppOptionsSSAOBlurDepth.setValue($SSAOPostFx::blurDepthTol); + ppOptionsSSAOBlurNormal.setValue($SSAOPostFx::blurNormalTol); + + //SSAO - Set the values for the near tab + ppOptionsSSAONearDepthMax.setValue($SSAOPostFx::sDepthMax); + ppOptionsSSAONearDepthMin.setValue($SSAOPostFx::sDepthMin); + ppOptionsSSAONearRadius.setValue($SSAOPostFx::sRadius); + ppOptionsSSAONearStrength.setValue($SSAOPostFx::sStrength); + ppOptionsSSAONearToleranceNormal.setValue($SSAOPostFx::sNormalTol); + ppOptionsSSAONearTolerancePower.setValue($SSAOPostFx::sNormalPow); + + //SSAO - Set the values for the far tab + ppOptionsSSAOFarDepthMax.setValue($SSAOPostFx::lDepthMax); + ppOptionsSSAOFarDepthMin.setValue($SSAOPostFx::lDepthMin); + ppOptionsSSAOFarRadius.setValue($SSAOPostFx::lRadius); + ppOptionsSSAOFarStrength.setValue($SSAOPostFx::lStrength); + ppOptionsSSAOFarToleranceNormal.setValue($SSAOPostFx::lNormalTol); + ppOptionsSSAOFarTolerancePower.setValue($SSAOPostFx::lNormalPow); +} + +function PostFXManager::settingsRefreshHDR(%this) +{ + //Apply the enabled flag + ppOptionsEnableHDR.setValue($PostFXManager::PostFX::EnableHDR); + + ppOptionsHDRBloom.setValue($HDRPostFX::enableBloom); + ppOptionsHDRBloomBlurBrightPassThreshold.setValue($HDRPostFX::brightPassThreshold); + ppOptionsHDRBloomBlurMean.setValue($HDRPostFX::gaussMean); + ppOptionsHDRBloomBlurMultiplier.setValue($HDRPostFX::gaussMultiplier); + ppOptionsHDRBloomBlurStdDev.setValue($HDRPostFX::gaussStdDev); + ppOptionsHDRBrightnessAdaptRate.setValue($HDRPostFX::adaptRate); + ppOptionsHDREffectsBlueShift.setValue($HDRPostFX::enableBlueShift); + ppOptionsHDREffectsBlueShiftColor.BaseColor = $HDRPostFX::blueShiftColor; + ppOptionsHDREffectsBlueShiftColor.PickColor = $HDRPostFX::blueShiftColor; + ppOptionsHDRKeyValue.setValue($HDRPostFX::keyValue); + ppOptionsHDRMinLuminance.setValue($HDRPostFX::minLuminace); + ppOptionsHDRToneMapping.setValue($HDRPostFX::enableToneMapping); + ppOptionsHDRToneMappingAmount.setValue($HDRPostFX::enableToneMapping); + ppOptionsHDRWhiteCutoff.setValue($HDRPostFX::whiteCutoff); + + %this-->ColorCorrectionFileName.Text = $HDRPostFX::colorCorrectionRamp; +} + +function PostFXManager::settingsRefreshLightrays(%this) +{ + //Apply the enabled flag + ppOptionsEnableLightRays.setValue($PostFXManager::PostFX::EnableLightRays); + + ppOptionsLightRaysBrightScalar.setValue($LightRayPostFX::brightScalar); + + ppOptionsLightRaysSampleScalar.setValue($LightRayPostFX::numSamples); + ppOptionsLightRaysDensityScalar.setValue($LightRayPostFX::density); + ppOptionsLightRaysWeightScalar.setValue($LightRayPostFX::weight); + ppOptionsLightRaysDecayScalar.setValue($LightRayPostFX::decay); +} + +function PostFXManager::settingsRefreshDOF(%this) +{ + //Apply the enabled flag + ppOptionsEnableDOF.setValue($PostFXManager::PostFX::EnableDOF); + + + //ppOptionsDOFEnableDOF.setValue($PostFXManager::PostFX::EnableDOF); + ppOptionsDOFEnableAutoFocus.setValue($DOFPostFx::EnableAutoFocus); + + ppOptionsDOFFarBlurMinSlider.setValue($DOFPostFx::BlurMin); + ppOptionsDOFFarBlurMaxSlider.setValue($DOFPostFx::BlurMax); + + ppOptionsDOFFocusRangeMinSlider.setValue($DOFPostFx::FocusRangeMin); + ppOptionsDOFFocusRangeMaxSlider.setValue($DOFPostFx::FocusRangeMax); + + ppOptionsDOFBlurCurveNearSlider.setValue($DOFPostFx::BlurCurveNear); + ppOptionsDOFBlurCurveFarSlider.setValue($DOFPostFx::BlurCurveFar); + +} + +function PostFXManager::settingsRefreshVignette(%this) +{ + //Apply the enabled flag + ppOptionsEnableVignette.setValue($PostFXManager::PostFX::EnableVignette); + +} + +function PostFXManager::settingsRefreshAll(%this) +{ + $PostFXManager::PostFX::Enabled = $pref::enablePostEffects; + $PostFXManager::PostFX::EnableSSAO = SSAOPostFx.isEnabled(); + $PostFXManager::PostFX::EnableHDR = HDRPostFX.isEnabled(); + $PostFXManager::PostFX::EnableLightRays = LightRayPostFX.isEnabled(); + $PostFXManager::PostFX::EnableDOF = DOFPostEffect.isEnabled(); + $PostFXManager::PostFX::EnableVignette = VignettePostEffect.isEnabled(); + + //For all the postFX here, apply the active settings in the system + //to the gui controls. + + %this.settingsRefreshSSAO(); + %this.settingsRefreshHDR(); + %this.settingsRefreshLightrays(); + %this.settingsRefreshDOF(); + %this.settingsRefreshVignette(); + + ppOptionsEnable.setValue($PostFXManager::PostFX::Enabled); + + postVerbose("% - PostFX Manager - GUI values updated."); +} + +function PostFXManager::settingsApplyFromPreset(%this) +{ + postVerbose("% - PostFX Manager - Applying from preset"); + + //SSAO Settings + $SSAOPostFx::blurDepthTol = $PostFXManager::Settings::SSAO::blurDepthTol; + $SSAOPostFx::blurNormalTol = $PostFXManager::Settings::SSAO::blurNormalTol; + $SSAOPostFx::lDepthMax = $PostFXManager::Settings::SSAO::lDepthMax; + $SSAOPostFx::lDepthMin = $PostFXManager::Settings::SSAO::lDepthMin; + $SSAOPostFx::lDepthPow = $PostFXManager::Settings::SSAO::lDepthPow; + $SSAOPostFx::lNormalPow = $PostFXManager::Settings::SSAO::lNormalPow; + $SSAOPostFx::lNormalTol = $PostFXManager::Settings::SSAO::lNormalTol; + $SSAOPostFx::lRadius = $PostFXManager::Settings::SSAO::lRadius; + $SSAOPostFx::lStrength = $PostFXManager::Settings::SSAO::lStrength; + $SSAOPostFx::overallStrength = $PostFXManager::Settings::SSAO::overallStrength; + $SSAOPostFx::quality = $PostFXManager::Settings::SSAO::quality; + $SSAOPostFx::sDepthMax = $PostFXManager::Settings::SSAO::sDepthMax; + $SSAOPostFx::sDepthMin = $PostFXManager::Settings::SSAO::sDepthMin; + $SSAOPostFx::sDepthPow = $PostFXManager::Settings::SSAO::sDepthPow; + $SSAOPostFx::sNormalPow = $PostFXManager::Settings::SSAO::sNormalPow; + $SSAOPostFx::sNormalTol = $PostFXManager::Settings::SSAO::sNormalTol; + $SSAOPostFx::sRadius = $PostFXManager::Settings::SSAO::sRadius; + $SSAOPostFx::sStrength = $PostFXManager::Settings::SSAO::sStrength; + + //HDR settings + $HDRPostFX::adaptRate = $PostFXManager::Settings::HDR::adaptRate; + $HDRPostFX::blueShiftColor = $PostFXManager::Settings::HDR::blueShiftColor; + $HDRPostFX::brightPassThreshold = $PostFXManager::Settings::HDR::brightPassThreshold; + $HDRPostFX::enableBloom = $PostFXManager::Settings::HDR::enableBloom; + $HDRPostFX::enableBlueShift = $PostFXManager::Settings::HDR::enableBlueShift; + $HDRPostFX::enableToneMapping = $PostFXManager::Settings::HDR::enableToneMapping; + $HDRPostFX::gaussMean = $PostFXManager::Settings::HDR::gaussMean; + $HDRPostFX::gaussMultiplier = $PostFXManager::Settings::HDR::gaussMultiplier; + $HDRPostFX::gaussStdDev = $PostFXManager::Settings::HDR::gaussStdDev; + $HDRPostFX::keyValue = $PostFXManager::Settings::HDR::keyValue; + $HDRPostFX::minLuminace = $PostFXManager::Settings::HDR::minLuminace; + $HDRPostFX::whiteCutoff = $PostFXManager::Settings::HDR::whiteCutoff; + $HDRPostFX::colorCorrectionRamp = $PostFXManager::Settings::ColorCorrectionRamp; + + //Light rays settings + $LightRayPostFX::brightScalar = $PostFXManager::Settings::LightRays::brightScalar; + + $LightRayPostFX::numSamples = $PostFXManager::Settings::LightRays::numSamples; + $LightRayPostFX::density = $PostFXManager::Settings::LightRays::density; + $LightRayPostFX::weight = $PostFXManager::Settings::LightRays::weight; + $LightRayPostFX::decay = $PostFXManager::Settings::LightRays::decay; + + //DOF settings + $DOFPostFx::EnableAutoFocus = $PostFXManager::Settings::DOF::EnableAutoFocus; + $DOFPostFx::BlurMin = $PostFXManager::Settings::DOF::BlurMin; + $DOFPostFx::BlurMax = $PostFXManager::Settings::DOF::BlurMax; + $DOFPostFx::FocusRangeMin = $PostFXManager::Settings::DOF::FocusRangeMin; + $DOFPostFx::FocusRangeMax = $PostFXManager::Settings::DOF::FocusRangeMax; + $DOFPostFx::BlurCurveNear = $PostFXManager::Settings::DOF::BlurCurveNear; + $DOFPostFx::BlurCurveFar = $PostFXManager::Settings::DOF::BlurCurveFar; + + //Vignette settings + $VignettePostEffect::VMax = $PostFXManager::Settings::Vignette::VMax; + $VignettePostEffect::VMin = $PostFXManager::Settings::Vignette::VMin; + + if ( $PostFXManager::forceEnableFromPresets ) + { + $PostFXManager::PostFX::Enabled = $PostFXManager::Settings::EnablePostFX; + $PostFXManager::PostFX::EnableDOF = $pref::PostFX::EnableDOF ? $PostFXManager::Settings::EnableDOF : false; + $PostFXManager::PostFX::EnableVignette = $pref::PostFX::EnableVignette ? $PostFXManager::Settings::EnableVignette : false; + $PostFXManager::PostFX::EnableLightRays = $pref::PostFX::EnableLightRays ? $PostFXManager::Settings::EnableLightRays : false; + $PostFXManager::PostFX::EnableHDR = $pref::PostFX::EnableHDR ? $PostFXManager::Settings::EnableHDR : false; + $PostFXManager::PostFX::EnableSSAO = $pref::PostFX::EnabledSSAO ? $PostFXManager::Settings::EnableSSAO : false; + + %this.settingsSetEnabled( true ); + } + + //make sure we apply the correct settings to the DOF + ppOptionsUpdateDOFSettings(); + + // Update the actual GUI controls if its awake ( otherwise it will when opened ). + if ( PostFXManager.isAwake() ) + %this.settingsRefreshAll(); +} + +function PostFXManager::settingsApplySSAO(%this) +{ + $PostFXManager::Settings::SSAO::blurDepthTol = $SSAOPostFx::blurDepthTol; + $PostFXManager::Settings::SSAO::blurNormalTol = $SSAOPostFx::blurNormalTol; + $PostFXManager::Settings::SSAO::lDepthMax = $SSAOPostFx::lDepthMax; + $PostFXManager::Settings::SSAO::lDepthMin = $SSAOPostFx::lDepthMin; + $PostFXManager::Settings::SSAO::lDepthPow = $SSAOPostFx::lDepthPow; + $PostFXManager::Settings::SSAO::lNormalPow = $SSAOPostFx::lNormalPow; + $PostFXManager::Settings::SSAO::lNormalTol = $SSAOPostFx::lNormalTol; + $PostFXManager::Settings::SSAO::lRadius = $SSAOPostFx::lRadius; + $PostFXManager::Settings::SSAO::lStrength = $SSAOPostFx::lStrength; + $PostFXManager::Settings::SSAO::overallStrength = $SSAOPostFx::overallStrength; + $PostFXManager::Settings::SSAO::quality = $SSAOPostFx::quality; + $PostFXManager::Settings::SSAO::sDepthMax = $SSAOPostFx::sDepthMax; + $PostFXManager::Settings::SSAO::sDepthMin = $SSAOPostFx::sDepthMin; + $PostFXManager::Settings::SSAO::sDepthPow = $SSAOPostFx::sDepthPow; + $PostFXManager::Settings::SSAO::sNormalPow = $SSAOPostFx::sNormalPow; + $PostFXManager::Settings::SSAO::sNormalTol = $SSAOPostFx::sNormalTol; + $PostFXManager::Settings::SSAO::sRadius = $SSAOPostFx::sRadius; + $PostFXManager::Settings::SSAO::sStrength = $SSAOPostFx::sStrength; + + postVerbose("% - PostFX Manager - Settings Saved - SSAO"); + +} + +function PostFXManager::settingsApplyHDR(%this) +{ + $PostFXManager::Settings::HDR::adaptRate = $HDRPostFX::adaptRate; + $PostFXManager::Settings::HDR::blueShiftColor = $HDRPostFX::blueShiftColor; + $PostFXManager::Settings::HDR::brightPassThreshold = $HDRPostFX::brightPassThreshold; + $PostFXManager::Settings::HDR::enableBloom = $HDRPostFX::enableBloom; + $PostFXManager::Settings::HDR::enableBlueShift = $HDRPostFX::enableBlueShift; + $PostFXManager::Settings::HDR::enableToneMapping = $HDRPostFX::enableToneMapping; + $PostFXManager::Settings::HDR::gaussMean = $HDRPostFX::gaussMean; + $PostFXManager::Settings::HDR::gaussMultiplier = $HDRPostFX::gaussMultiplier; + $PostFXManager::Settings::HDR::gaussStdDev = $HDRPostFX::gaussStdDev; + $PostFXManager::Settings::HDR::keyValue = $HDRPostFX::keyValue; + $PostFXManager::Settings::HDR::minLuminace = $HDRPostFX::minLuminace; + $PostFXManager::Settings::HDR::whiteCutoff = $HDRPostFX::whiteCutoff; + $PostFXManager::Settings::ColorCorrectionRamp = $HDRPostFX::colorCorrectionRamp; + + postVerbose("% - PostFX Manager - Settings Saved - HDR"); +} + +function PostFXManager::settingsApplyLightRays(%this) +{ + $PostFXManager::Settings::LightRays::brightScalar = $LightRayPostFX::brightScalar; + + $PostFXManager::Settings::LightRays::numSamples = $LightRayPostFX::numSamples; + $PostFXManager::Settings::LightRays::density = $LightRayPostFX::density; + $PostFXManager::Settings::LightRays::weight = $LightRayPostFX::weight; + $PostFXManager::Settings::LightRays::decay = $LightRayPostFX::decay; + + postVerbose("% - PostFX Manager - Settings Saved - Light Rays"); + +} + +function PostFXManager::settingsApplyDOF(%this) +{ + $PostFXManager::Settings::DOF::EnableAutoFocus = $DOFPostFx::EnableAutoFocus; + $PostFXManager::Settings::DOF::BlurMin = $DOFPostFx::BlurMin; + $PostFXManager::Settings::DOF::BlurMax = $DOFPostFx::BlurMax; + $PostFXManager::Settings::DOF::FocusRangeMin = $DOFPostFx::FocusRangeMin; + $PostFXManager::Settings::DOF::FocusRangeMax = $DOFPostFx::FocusRangeMax; + $PostFXManager::Settings::DOF::BlurCurveNear = $DOFPostFx::BlurCurveNear; + $PostFXManager::Settings::DOF::BlurCurveFar = $DOFPostFx::BlurCurveFar; + + postVerbose("% - PostFX Manager - Settings Saved - DOF"); + +} + +function PostFXManager::settingsApplyVignette(%this) +{ + $PostFXManager::Settings::Vignette::VMax = $VignettePostEffect::VMax; + $PostFXManager::Settings::Vignette::VMin = $VignettePostEffect::VMin; + + postVerbose("% - PostFX Manager - Settings Saved - Vignette"); + +} + +function PostFXManager::settingsApplyAll(%this, %sFrom) +{ + // Apply settings which control if effects are on/off altogether. + $PostFXManager::Settings::EnablePostFX = $PostFXManager::PostFX::Enabled; + $PostFXManager::Settings::EnableDOF = $PostFXManager::PostFX::EnableDOF; + $PostFXManager::Settings::EnableVignette = $PostFXManager::PostFX::EnableVignette; + $PostFXManager::Settings::EnableLightRays = $PostFXManager::PostFX::EnableLightRays; + $PostFXManager::Settings::EnableHDR = $PostFXManager::PostFX::EnableHDR; + $PostFXManager::Settings::EnableSSAO = $PostFXManager::PostFX::EnableSSAO; + + // Apply settings should save the values in the system to the + // the preset structure ($PostFXManager::Settings::*) + + // SSAO Settings + %this.settingsApplySSAO(); + // HDR settings + %this.settingsApplyHDR(); + // Light rays settings + %this.settingsApplyLightRays(); + // DOF + %this.settingsApplyDOF(); + // Vignette + %this.settingsApplyVignette(); + + postVerbose("% - PostFX Manager - All Settings applied to $PostFXManager::Settings"); +} + +function PostFXManager::settingsApplyDefaultPreset(%this) +{ + PostFXManager::loadPresetHandler($PostFXManager::defaultPreset); +} + diff --git a/Templates/BaseGame/game/core/postFX/scripts/postFxManager.persistance.cs b/Templates/BaseGame/game/core/postFX/scripts/postFxManager.persistance.cs new file mode 100644 index 000000000..31fec95f1 --- /dev/null +++ b/Templates/BaseGame/game/core/postFX/scripts/postFxManager.persistance.cs @@ -0,0 +1,79 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + + +// Used to name the saved files. +$PostFXManager::fileExtension = ".postfxpreset.cs"; + +// The filter string for file open/save dialogs. +$PostFXManager::fileFilter = "Post Effect Presets|*.postfxpreset.cs"; + +// Enable / disable PostFX when loading presets or just apply the settings? +$PostFXManager::forceEnableFromPresets = true; + +//Load a preset file from the disk, and apply the settings to the +//controls. If bApplySettings is true - the actual values in the engine +//will be changed to reflect the settings from the file. +function PostFXManager::loadPresetFile() +{ + //Show the dialog and set the flag + getLoadFilename($PostFXManager::fileFilter, "PostFXManager::loadPresetHandler"); +} + +function PostFXManager::loadPresetHandler( %filename ) +{ + //Check the validity of the file + if ( isScriptFile( %filename ) ) + { + %filename = expandFilename(%filename); + postVerbose("% - PostFX Manager - Executing " @ %filename); + exec(%filename); + + PostFXManager.settingsApplyFromPreset(); + } +} + +//Save a preset file to the specified file. The extension used +//is specified by $PostFXManager::fileExtension for on the fly +//name changes to the extension used. + +function PostFXManager::savePresetFile(%this) +{ + %defaultFile = filePath($Client::MissionFile) @ "/" @ fileBase($Client::MissionFile); + getSaveFilename($PostFXManager::fileFilter, "PostFXManager::savePresetHandler", %defaultFile); +} + +//Called from the PostFXManager::savePresetFile() function +function PostFXManager::savePresetHandler( %filename ) +{ + %filename = makeRelativePath( %filename, getMainDotCsDir() ); + if(strStr(%filename, ".") == -1) + %filename = %filename @ $PostFXManager::fileExtension; + + //Apply the current settings to the preset + PostFXManager.settingsApplyAll(); + + export("$PostFXManager::Settings::*", %filename, false); + + postVerbose("% - PostFX Manager - Save complete. Preset saved at : " @ %filename); +} + diff --git a/Templates/BaseGame/game/core/postFX/scripts/ssao.cs b/Templates/BaseGame/game/core/postFX/scripts/ssao.cs new file mode 100644 index 000000000..5fe405a82 --- /dev/null +++ b/Templates/BaseGame/game/core/postFX/scripts/ssao.cs @@ -0,0 +1,302 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + + +/// +$SSAOPostFx::overallStrength = 2.0; + +// TODO: Add small/large param docs. + +// The small radius SSAO settings. +$SSAOPostFx::sRadius = 0.1; +$SSAOPostFx::sStrength = 6.0; +$SSAOPostFx::sDepthMin = 0.1; +$SSAOPostFx::sDepthMax = 1.0; +$SSAOPostFx::sDepthPow = 1.0; +$SSAOPostFx::sNormalTol = 0.0; +$SSAOPostFx::sNormalPow = 1.0; + +// The large radius SSAO settings. +$SSAOPostFx::lRadius = 1.0; +$SSAOPostFx::lStrength = 10.0; +$SSAOPostFx::lDepthMin = 0.2; +$SSAOPostFx::lDepthMax = 2.0; +$SSAOPostFx::lDepthPow = 0.2; +$SSAOPostFx::lNormalTol = -0.5; +$SSAOPostFx::lNormalPow = 2.0; + +/// Valid values: 0, 1, 2 +$SSAOPostFx::quality = 0; + +/// +$SSAOPostFx::blurDepthTol = 0.001; + +/// +$SSAOPostFx::blurNormalTol = 0.95; + +/// +$SSAOPostFx::targetScale = "0.5 0.5"; + + +function SSAOPostFx::onAdd( %this ) +{ + %this.wasVis = "Uninitialized"; + %this.quality = "Uninitialized"; +} + +function SSAOPostFx::preProcess( %this ) +{ + if ( $SSAOPostFx::quality !$= %this.quality ) + { + %this.quality = mClamp( mRound( $SSAOPostFx::quality ), 0, 2 ); + + %this.setShaderMacro( "QUALITY", %this.quality ); + } + + %this.targetScale = $SSAOPostFx::targetScale; +} + +function SSAOPostFx::setShaderConsts( %this ) +{ + %this.setShaderConst( "$overallStrength", $SSAOPostFx::overallStrength ); + + // Abbreviate is s-small l-large. + + %this.setShaderConst( "$sRadius", $SSAOPostFx::sRadius ); + %this.setShaderConst( "$sStrength", $SSAOPostFx::sStrength ); + %this.setShaderConst( "$sDepthMin", $SSAOPostFx::sDepthMin ); + %this.setShaderConst( "$sDepthMax", $SSAOPostFx::sDepthMax ); + %this.setShaderConst( "$sDepthPow", $SSAOPostFx::sDepthPow ); + %this.setShaderConst( "$sNormalTol", $SSAOPostFx::sNormalTol ); + %this.setShaderConst( "$sNormalPow", $SSAOPostFx::sNormalPow ); + + %this.setShaderConst( "$lRadius", $SSAOPostFx::lRadius ); + %this.setShaderConst( "$lStrength", $SSAOPostFx::lStrength ); + %this.setShaderConst( "$lDepthMin", $SSAOPostFx::lDepthMin ); + %this.setShaderConst( "$lDepthMax", $SSAOPostFx::lDepthMax ); + %this.setShaderConst( "$lDepthPow", $SSAOPostFx::lDepthPow ); + %this.setShaderConst( "$lNormalTol", $SSAOPostFx::lNormalTol ); + %this.setShaderConst( "$lNormalPow", $SSAOPostFx::lNormalPow ); + + %blur = %this->blurY; + %blur.setShaderConst( "$blurDepthTol", $SSAOPostFx::blurDepthTol ); + %blur.setShaderConst( "$blurNormalTol", $SSAOPostFx::blurNormalTol ); + + %blur = %this->blurX; + %blur.setShaderConst( "$blurDepthTol", $SSAOPostFx::blurDepthTol ); + %blur.setShaderConst( "$blurNormalTol", $SSAOPostFx::blurNormalTol ); + + %blur = %this->blurY2; + %blur.setShaderConst( "$blurDepthTol", $SSAOPostFx::blurDepthTol ); + %blur.setShaderConst( "$blurNormalTol", $SSAOPostFx::blurNormalTol ); + + %blur = %this->blurX2; + %blur.setShaderConst( "$blurDepthTol", $SSAOPostFx::blurDepthTol ); + %blur.setShaderConst( "$blurNormalTol", $SSAOPostFx::blurNormalTol ); +} + +function SSAOPostFx::onEnabled( %this ) +{ + // This tells the AL shaders to reload and sample + // from our #ssaoMask texture target. + $AL::UseSSAOMask = true; + + return true; +} + +function SSAOPostFx::onDisabled( %this ) +{ + $AL::UseSSAOMask = false; +} + + +//----------------------------------------------------------------------------- +// GFXStateBlockData / ShaderData +//----------------------------------------------------------------------------- + +singleton GFXStateBlockData( SSAOStateBlock : PFX_DefaultStateBlock ) +{ + samplersDefined = true; + samplerStates[0] = SamplerClampPoint; + samplerStates[1] = SamplerWrapLinear; + samplerStates[2] = SamplerClampPoint; +}; + +singleton GFXStateBlockData( SSAOBlurStateBlock : PFX_DefaultStateBlock ) +{ + samplersDefined = true; + samplerStates[0] = SamplerClampLinear; + samplerStates[1] = SamplerClampPoint; +}; + +singleton ShaderData( SSAOShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/postFxV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/ssao/SSAO_P.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/ssao/gl/SSAO_P.glsl"; + + samplerNames[0] = "$deferredMap"; + samplerNames[1] = "$randNormalTex"; + samplerNames[2] = "$powTable"; + + pixVersion = 3.0; +}; + +singleton ShaderData( SSAOBlurYShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/ssao/SSAO_Blur_V.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/ssao/SSAO_Blur_P.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/ssao/gl/SSAO_Blur_V.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/ssao/gl/SSAO_Blur_P.glsl"; + + samplerNames[0] = "$occludeMap"; + samplerNames[1] = "$deferredMap"; + + pixVersion = 3.0; + + defines = "BLUR_DIR=float2(0.0,1.0)"; +}; + +singleton ShaderData( SSAOBlurXShader : SSAOBlurYShader ) +{ + defines = "BLUR_DIR=float2(1.0,0.0)"; +}; + +//----------------------------------------------------------------------------- +// PostEffects +//----------------------------------------------------------------------------- + +singleton PostEffect( SSAOPostFx ) +{ + allowReflectPass = false; + + renderTime = "PFXBeforeBin"; + renderBin = "AL_LightBinMgr"; + renderPriority = 10; + + shader = SSAOShader; + stateBlock = SSAOStateBlock; + + texture[0] = "#deferred"; + texture[1] = "core/postFX/images/noise.png"; + texture[2] = "#ssao_pow_table"; + + target = "$outTex"; + targetScale = "0.5 0.5"; + targetViewport = "PFXTargetViewport_NamedInTexture0"; + + singleton PostEffect() + { + internalName = "blurY"; + + shader = SSAOBlurYShader; + stateBlock = SSAOBlurStateBlock; + + texture[0] = "$inTex"; + texture[1] = "#deferred"; + + target = "$outTex"; + }; + + singleton PostEffect() + { + internalName = "blurX"; + + shader = SSAOBlurXShader; + stateBlock = SSAOBlurStateBlock; + + texture[0] = "$inTex"; + texture[1] = "#deferred"; + + target = "$outTex"; + }; + + singleton PostEffect() + { + internalName = "blurY2"; + + shader = SSAOBlurYShader; + stateBlock = SSAOBlurStateBlock; + + texture[0] = "$inTex"; + texture[1] = "#deferred"; + + target = "$outTex"; + }; + + singleton PostEffect() + { + internalName = "blurX2"; + + shader = SSAOBlurXShader; + stateBlock = SSAOBlurStateBlock; + + texture[0] = "$inTex"; + texture[1] = "#deferred"; + + // We write to a mask texture which is then + // read by the lighting shaders to mask ambient. + target = "#ssaoMask"; + }; +}; + + +/// Just here for debug visualization of the +/// SSAO mask texture used during lighting. +singleton PostEffect( SSAOVizPostFx ) +{ + allowReflectPass = false; + + shader = PFX_PassthruShader; + stateBlock = PFX_DefaultStateBlock; + + texture[0] = "#ssaoMask"; + + target = "$backbuffer"; +}; + +singleton ShaderData( SSAOPowTableShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/ssao/SSAO_PowerTable_V.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/ssao/SSAO_PowerTable_P.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/ssao/gl/SSAO_PowerTable_V.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/ssao/gl/SSAO_PowerTable_P.glsl"; + + pixVersion = 2.0; +}; + +singleton PostEffect( SSAOPowTablePostFx ) +{ + shader = SSAOPowTableShader; + stateBlock = PFX_DefaultStateBlock; + + renderTime = "PFXTexGenOnDemand"; + + target = "#ssao_pow_table"; + + targetFormat = "GFXFormatR16F"; + targetSize = "256 1"; +}; \ No newline at end of file diff --git a/Templates/BaseGame/game/core/postFX/scripts/turbulence.cs b/Templates/BaseGame/game/core/postFX/scripts/turbulence.cs new file mode 100644 index 000000000..967c3b2bf --- /dev/null +++ b/Templates/BaseGame/game/core/postFX/scripts/turbulence.cs @@ -0,0 +1,57 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +singleton GFXStateBlockData( PFX_TurbulenceStateBlock : PFX_DefaultStateBlock) +{ + zDefined = false; + zEnable = false; + zWriteEnable = false; + + samplersDefined = true; + samplerStates[0] = SamplerClampLinear; +}; + +singleton ShaderData( PFX_TurbulenceShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/postFxV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/turbulenceP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/gl/turbulenceP.glsl"; + + samplerNames[0] = "$inputTex"; + pixVersion = 3.0; +}; + +singleton PostEffect( TurbulenceFx ) +{ + isEnabled = false; + allowReflectPass = true; + + renderTime = "PFXAfterDiffuse"; + renderBin = "GlowBin"; + renderPriority = 0.5; // Render after the glows themselves + + shader = PFX_TurbulenceShader; + stateBlock=PFX_TurbulenceStateBlock; + texture[0] = "$backBuffer"; + }; diff --git a/Templates/BaseGame/game/core/postFX/scripts/vignette.cs b/Templates/BaseGame/game/core/postFX/scripts/vignette.cs new file mode 100644 index 000000000..d22f7d14a --- /dev/null +++ b/Templates/BaseGame/game/core/postFX/scripts/vignette.cs @@ -0,0 +1,55 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +$VignettePostEffect::VMax = 0.6; +$VignettePostEffect::VMin = 0.2; + +singleton ShaderData( VignetteShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/postFX/postFxV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/postFX/vignette/VignetteP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/postFX/gl/postFxV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/postFX/vignette/gl/VignetteP.glsl"; + + samplerNames[0] = "$backBuffer"; + + pixVersion = 2.0; +}; + +singleton PostEffect( VignettePostEffect ) +{ + isEnabled = false; + allowReflectPass = false; + renderTime = "PFXAfterBin"; + renderBin = "GlowBin"; + shader = VignetteShader; + stateBlock = PFX_DefaultStateBlock; + texture[0] = "$backBuffer"; + renderPriority = 10; +}; + +function VignettePostEffect::setShaderConsts(%this) +{ + %this.setShaderConst("$Vmax", $VignettePostEffect::VMax); + %this.setShaderConst("$Vmin", $VignettePostEffect::VMin); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/Core_Rendering.cs b/Templates/BaseGame/game/core/rendering/Core_Rendering.cs new file mode 100644 index 000000000..d09e0cbe3 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/Core_Rendering.cs @@ -0,0 +1,20 @@ + +function Core_Rendering::onCreate(%this) +{ + $Core::MissingTexturePath = "core/rendering/images/missingTexture"; + $Core::UnAvailableTexturePath = "core/rendering/images/unavailable"; + $Core::WarningTexturePath = "core/rendering/images/warnMat"; + $Core::CommonShaderPath = "core/rendering/shaders"; + + exec("./scripts/renderManager.cs"); + exec("./scripts/gfxData/clouds.cs"); + exec("./scripts/gfxData/commonMaterialData.cs"); + exec("./scripts/gfxData/scatterSky.cs"); + exec("./scripts/gfxData/shaders.cs"); + exec("./scripts/gfxData/terrainBlock.cs"); + exec("./scripts/gfxData/water.cs"); +} + +function Core_Rendering::onDestroy(%this) +{ +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/Core_Rendering.module b/Templates/BaseGame/game/core/rendering/Core_Rendering.module new file mode 100644 index 000000000..9dbbfc33a --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/Core_Rendering.module @@ -0,0 +1,9 @@ + + \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/images/materials.cs b/Templates/BaseGame/game/core/rendering/images/materials.cs new file mode 100644 index 000000000..a13c751b3 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/images/materials.cs @@ -0,0 +1,32 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +singleton Material( Empty ) +{ +}; + +singleton Material(WarningMaterial) { + detailMap[0] = "missingTexture"; + diffuseColor[0] = "25 16 0"; + emissive[0] = false; + translucent = false; +}; diff --git a/Templates/BaseGame/game/core/rendering/images/missingTexture.png b/Templates/BaseGame/game/core/rendering/images/missingTexture.png new file mode 100644 index 0000000000000000000000000000000000000000..80a7874da967ad523e1a3308f3f14c66d4eed503 GIT binary patch literal 10645 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 literal 0 HcmV?d00001 diff --git a/Templates/BaseGame/game/core/rendering/images/warnMat.dds b/Templates/BaseGame/game/core/rendering/images/warnMat.dds new file mode 100644 index 0000000000000000000000000000000000000000..ea99dcbd74a8b2ae49c5cff5a69743498a66e937 GIT binary patch literal 699192 zcmeFaPi$M+p67Q(#Rw%q$lVCxuCM)|w4M~V{T2fJ7L9l5=?1EHs%~9T&ZsR?vxyfI zsJbygxsX^C8(DbKi&_Xl?Ia2f*klZ%fGCLvqZVm(77oyhDio(NUSwqH4PbCKf$})> zK(x$!f9LR!6h(@c5=l|gmq67qMe^Qr&pE%(@6Y+2bN=K{{@nQ=Ez9~Z?NQ76FYpif z&kD-_tTFX}|NnFFRr&d!EYAO`*{_1Od*;t>$tlSnS+X5C4k!oY069PokOSlZIY17O z1LOcXKn{=tbP?mEh4x0G{HM%>a}6jFwRD81ID`aV8azt6j+Y!2Ta>0>S?>#-q__zuK?WeVjr#I665w zc~jc8`_Ccz-TFrP=kceWh4zA)_i}DHIFIpvT8|g^R&40;d^w{^DEb86pH#|nIj!D{ z{+GX(_fn&(Or@-j%Fn4+>igz8<&wJIGA_I#_cx_i{%m~+2gfRQf;E=cc8V3)>3%zr zuifA)`-S6ZkjGJY9o)l9`78O82bwo~6|QOCm8-n#-us*zQ+|)~w*o`s*IiDa|1GHh zsL>y)9Z$+>;d-$L?I+i5)-U2WLj6h6oWt{TUZF(&Gsybq zx^w@!*Wc)W;mKYmJuSRRk6Ma%aBr;bP)x-)ds7xtZYdF(oDe@o@p|a`wr9*<#Y@`p zq`a5WdSf)8+bx~yP5Y(JT-P~H+*18t)%QUw{*9W4{|0`&vBz{gzNq~8s-EAI@g5Fl zQlnbG!+%%$7j~PJQ14ogr&0lVpT_t0LrIjDDp6QRq3w|9dsU{T+z%oAU-n<(_od43 z)%}uoDz2|zQuj&NrPM2BZ67%#jI?9%WG^En^ak_?xZc(FYkocFc-y{B{=dv4SypsO{NL4u z27QlsR>dAuahN?g@-oh$-Z8$#f8SGj9{#*~Z}dCdeXZAxJ};J2zjgLQc?4XfL~*A4 z(_dOv3a^Wnjn@_XLE9CuCtx5bdm>UUC_4l8f*MboVkgw>gEbfc>bYPS)W;3*^Udtr zn6d|)66}Fti4Sc40G?c9dz<>87y97(@|WY`BICj6fALSD{-OVq_SooXKzIZ7m2Tux zx8BS3m&>Js-0vVBw+`MXZG-{9rG#TyfosU6m@V;t(Kj=A35PS8bXs_gqG#>c*dK1` z$eG3K=F0KbBaHK?;e24c@D@c zfSr*0V#S_-{iO16MkFq9@E#bvhW2-JzFj|#@HsI4Zk-;!s&RVN`oG4j?NF(p=QUrH z3ZD=MumhM7xT<#P{Jv-Pe+Dn=|I6|W@#^Se#N_AeJk{cT(f23ijMDq*>41uZi(VIf z4>JJsE!&|{a75Z);sIuy^;!=P+V#zIOFKl?J{RikfognU`7@*~9F(vC>;QXYHV->s zOV%4Qe~@tj#szM$J#y9h-|$lS^a6PR!l#4HcwFKDvxrZEN3ze#HSkAbK^HIKXf6Iv z{olDArTkA<{QT_dQZ;{X1?`$I?y9^>OiL+0e=jqm{Cx5IW!%g_;mbIJ9gs14&x|jY zIzPd*i?ox84-_^{9!}wvnI~{dEB2(8Kjc>oU;FhrosYxI+O7OOxJ^HP!0pFD(f{>a zT3&wfLj1TACIpbrZVzEXVDRO)wf-;S)i3>XedGV}Ey0DX%a1NDRQ0~tQ$;xXQbO&k zJp6o7=T(ZIFL8Z@`PIBV*5#M`)y~)bKK1g3{M(eoOE%E~O74(1unqZ(EWh}4@b6ZF z2nWCpUw2@JGf!Z^c|Q1@q+J9t8yLH2Q1rjyso|3FC>yt|@N?t^dcvO-qy-KSa6B^H z(*LLaKX1HO^gi}2IHUK?I?8FS_u>8{zK`{HqXF&bBVo^s7c+iXUThtLX-6FwSoQ(E<+j9SU`CDGoc{!gp_51+L0+pYu=LJ@94nkmn<8s~QCG`*6^CsC*gR1`xXN5y+ znAa8m4{3pxQ%Hui|M3p_$%C{{0QJ8=xrl}0?%Yzn-iJT0=J#hRael4$lQ!Ic>itXZ zD`e#8vZad0sr=mS&_TRr2Uv#*`wj#Wc^h(m(g4QgsIUCVCEMvXw$q^Nf5R=|&vIp- zfWoIul^2NZ0yhT79;g04Uw&c^q64d&Kj{7UC7-`|qVxIFGkShs{CoQQ7n{E~a?Up-qW?`iQuIR{9U|QMyOP8qla4hI`vfTc zpOrXv%ouov(Try%yh)A;bOrS#^n`uSVk-}IBR15}=%+P^byeK7ff z*L5H7%klK`i^Sni+%g7Y&80v zj`yqlzP-JS>@Nd%e@6NZ>3yT3Kk}FeF#Xy}-}LM6PC@B=_^;5%lL6@W#LJ!$w=mkf7gK0xx3*1tnuARH#)4)!a%f_&tf{(tb`fjal^4PMHx&FAx`-n}jd zXa66Z$G5n&AoKj#w{KVUKf?Vg-mmrlc4!!WwCTrQw@bV0D?Ph09&k&KpLEBs?=~-w zoTaGv1risCEDlP$nRYexQS)<)-3D z{|$Fk{1FoZ!W+09aR(=#-no)Iq}WT>&8qo-+4o=SWAs1N|1Hx0IFC2(M%Slme!s-~ zr9FzU1JpeKSmk_47y_mr`(5T=}ft3 z^l!i0vGIOVpZfVZ?Au`@O*en_?RH)Im-VDxX8gaAE3Mue?j0cxV9pPM+ac?dLvTC# zn1_^oYv%v!^}qN-Sf?0hRsU}P{i^+ctn0Vn_s@&p4|T8C^^NNMe&qX2i+;$%5HS7L z?dNZIy~=#P=>4h55sB|#SKbc&BzAzx7nonoO1r`g$X`{vnszt$m-+b*8bI0rxfb)aEb+b>v&{zH0C!o3h7rR940aMRjmsh9%*Rda5 z)*Xs9@%v#1h~E#lzi;PCH@0(~zkkj3{u!PX#123_!0{GzJYer+aO?oHZ->a^o!N;E z>c2Dn$9;6w_+`7Cr>A=*H#bH98{UiGf$akI{^cqUDH-a|J^^R-|1Ms)NB?90{?)m~ zir@c6=KC?-ug>c+e!s;3O+WRktmMu8M*RKR@gdCb-&D?QZHXPA^97gYL=FbQ4p8#A z_Tt68C)<_$9ND*PnEM3X*l~DMm}S7#Y9Q$9cJ{>IdEzqwpHfuicLRyJ`C0_?5!F7iNDFObAH)QSTFQ z@FRw0&-{;8`rmNS)UQ`%|KtC6Ei0aNV?oUK@9e03eP$|o{uwy_(hpZL-|rkte&5C{ z&W-%~YS!;vEkB&&ZF_Omjf>t51V&XqWcGIZb`Evp_*QWMoa^nDwnLZ(U_K!If6jXh zfPHjR^}o@#!ky~*LC8ar^+?z*5PG3Ee7=49ALsY2&dtelpX~1KZHHo2{~u<+sI)(( z|NEBzVDygIL6hS{!@cU~YjE94UO+PBEzB=g@=(W&T$pz1S1I?E{G7u_`=JfBPWRpu zoafy$JNz2-5B1*w=)c=OPHw9HH(WEkGx5idx#~Uv$jk3Oe{P%pmvj7(?mu67Zne%2 z^B#!*%liI6-`Dr6eE9qX>^tkjZS?!k@+=uzjY=FKVUNzFGs+&jg8V=uhmsE?^K!C& zacE?m`vUaH4>>yydgJf#KG(ZlZ@T_Bc7SjX;m6uO0i`7NC!6Sc95VOCian2)@V0*b z-|)}Wr&ndagHs}@ECmV5qrOJGO zi36PUY8>I^Ycy&f5Z<$T43BkUf?VyByoQEa}0+|`;ECTV!_+t|A%eY zjYh@q-^0HCGVhG#=l{mntv5UK9 zXSchKx!>bw(Em#AoI*F`j{VMY-)!7-T%12H20{Oi<0bQflCLa&<6gP!Ntw#*mD};8 z)6WfmR2&i$0>Z-*_6d-@z;2u$boY5IxUjHr3*!G_dv$eH<^9#IcYGuB{(-BQ_eZ|} zHDy@(#4qcbyVUBH{&-JMS5=(67z`9ogrvRk?r3k-KZ4~N`8pZjbd zwvX6LSEc`r9u~bne&|{(Ico{&-_Spf4L9bB5UZ0>=PhyfaKI=&MT>J z&zn8}9}dnfE-vbM{~49{Cw72v9rONuUuP!qfN4+B|NU&wtI+>TOG|3qAC~!#NV24 ze>YkGyCt3Hn6P6(H_=X+g>-YVfmUi#GsF*}Nv^qc5?k^5>M01^Ru z-CySVHM?!!rvAS?$2tD}j(>hn)T$XTgP{K>@iO%}TfUn@TA(H8hhTbM?PtE*!~IJ{ zpDbfSK)8tQ0##n%I1VsBTd(HhDEqdS|6iy7`xamASNz}T|9U@i46lCsk@vpB{=yRz z6Mp-L-!u9@4E;X{aU1IYdLDCpHs>nar8n&|`1)Tzw{x5fAuZ6=^XZlOfK2!O72}sk zUKI8zONkxucY2?IkcA0>cH^*_{uj=g>l**3SLJQf|8lPK(_p_G+)jW#e^?JRts0|G&;3<2W_rlx08c!t0{{;cvclr9lo62Z+c%X0kq@ zcX^7!!xx`R1+h0i$%Fvr1N8YpTU)3_%lQDK|Lgr?>i<-#k^kL#ulnhQ&^{{~0@A4&e-Ejpi>daWON&A&dm-TiS@`rqj3i^i)lA7CRbFe?7J z6&N*nfnCo#Gj@Q)8xG=@6Vi zP5R?@%XcFO#crF!#toy!QcGOk*|J=8sz1`N>k9<$L?uH$8UG=|PI&_g1sMiPJ zU=x|IPxWvg6XD}BCIlo7fV9B4!~u{Ni1h)D<525=*$;o_!2|4vFYBxHe)#=ZUv*J? z>g;ngK3C)W81|E&o4acLFZLOx|10ar>i3aotS{edUP#<#enIJfj7vTLKcn^km8{#` zwywej;^o%H~p4W`vwcgMn|U=$1+$TVB!niDoq?f(O;+ZKh*!5Zpll#>lk@*OY7ea4F`HY&q+OJ#sN#(O|^K_RqKCn z+XlBgnE!7+er4Z2y>GD02LyVSZ?F7K>{}v!J;FexH>=kFBk*7EM`9Uy-`A1nUgJC&wO>Q-2go<`0MFO~cP$*(7+q24HNH{j zHSHlFCF2v_r{v`XgT?}%a{-ly(jwwxY$>HMC}ux_5U{hj`>uz|F8I2GJkNh;{V~7a-N*Tk+F}= zR7L-%nfG6vTU7fs;*8kQdoTFjI1c!po8$2J@q`{>n=cB@&5xiPyg%oKKOCP#&L4$yhE{X;zC9^7@yio4ky;{FjG_s>+;{qMe!{@M;@Z~#!h^}pn)@Vv%a9G2tNj8~TR`nlKR zVnFnN7vq3>-(cr(+wRA{!J>CwsPlu8_AAT>h~EF4O1+XYlS)mCeSqU|t(&U<-O>uy z0W4yFW;`zf|DsRQumk$7PgFmATPhvG4#R#x$OlY1n2zCkfKu3YSLc=_?q9^bjE>ig z2Bg2zGc(iDZu0kb{(84R7yXap8hKt5df(vK z^WN?oZ1kLPG_qXAe86^S6CEXfe`-3Q^nSj0Qa0b~Hb)z;*T4LK)6Oe4(g0o2Cy4tO z<++i5(X;%E#^*KfP5Vmw#}SZ0K1k>eHf-v({XDqW&wU|&zxAQ!_gCZoQ21)zAAx_< zZl)c3U2bjdV;^ss_s{(>1UVVp_A}#~WiRv&`+YFR)y>uax_$ep@nbGnTw)<%Jx_x;4+aU++=kxpd zrt5!MU*w7b`vLO-SRf$&VK4U$Zq!Hpe&2unZ^l<5v@pMf_LcqQbshl10bO5**{(f} zy(RvwI>!;~LiD--%m*~xugTQ^rj+4eJiEFW3&HP)K_+@1et%l;)1cR*%#4kye3aeY z{+;)0`VIRug~mr1_orUEDe`u`pJOoe|Hek|z_t^h=0Hfb@K7iz7B{5q`ev4WyYzFNzZs|E_s>pppZ|Vw zo%d{zzbFy}bReodkemthFVehuTZ9^wHxF4$@-Ra8@0Ulu-|(-8unva&J$P_Zu}@&R=m;40PwG`5SH4_K4)8*fU{Uk-Kw){De~m>z%~0R20*AtmP7t@~%kPq*b+?h{{>{d%oc z==*i;=gYi4^r?#PV>=0@_u=NNeSDzi)qcM4_f=j$;sICY@0)&*aR|4c`}=TzAMWo1 zaP*!V7vm81ziGGr>>F(O*sF4I^uKA>guRM{i@=v+UwO#4fPHmx_4ZZ09k5)P7x)CV zFY$o2QsI@H--L2g?19fP2x2Jzpj?WJULMPfT@bUav5I|Q&EUOcwOhMxDf$v+(Jf`) zqQu`#8T}6Lmn+|Uq3jCl6F!HYKZtnNVK{hz1~UGA41RtY8%T1jD{ zDKi>S^(^jXQc_=-0cM}6fzbQj#;mOGFEG!4aJfII`iS*1-0V*|Ao_n}0Q$Y)0?=}f zU_bT^zCHS1kK<DU!})f^RqOwIUtM+l zzp;JZJrsYn*ZT%H^0Qm-2haaE?OT}-D5!H8RtI$-ruw)*WbJc7>Uq#$58%(r@Aj6< zuoe*~D5sQNP)h0Z5TWkXxri_eRQv$jKx%#7Sf(rAOHHfq<7bxa(}V9%D}9dufY$dZ z#QBqUdQ|Is?+Wwz8pr98qxQM{4aQw)a(tM)WxStu$2GD$sQ-E8GnP z#%9Dn%w%>4J}+=^^}lIfm?`Z?K#rc#ZZA9(?_8+WYX~oNHMhf0Vef z&I`!wom|=a0KauV@_i5tYhL8Zr`=S?YppH_dD=RPSb{qB|3 z`UtTPrhyc~pZsZr-VV zgXLV=@=5V`!s|iaH~9MKf79Rlp+y7)^to`_4nSVOz{gqot#1eAelotijY+KMANq;; zebluD+7rkO+V~U zi5+15q~--wegNYES7#SEg`@Bea78Wb<7S0R&(y~%`^~&D-MHu?t^Cn~*YD)7oA42J8O@x!(@1#zhXq4p=&<*a4g$Xfr>c z&*kxEF|T58Xg{Cp_qxc_ZgH8{xh$9YdkpKgcEW(@|8L#W%6cFWxJLeeb$pq9gF}O` zZ}9EW|JC+ac7fyxEJRJdKxCD10UZ~}ZK*hkitBqDBjCZkCnG+%K>c%ie6c;)9)9%c zbsHyFt^bA7Yk1)t_LtWy{@*AMdf(vi^KBKER`UT@aL&zb)&DiQvp%>GRIvvlt5QmQ zI}*Ju_Q23jM>76I--o=7G3fi@UsK<=_k(KVr%|r?{wC@@_O~9_)c@U<@49`1NBh5T zF!g_{{@f2ejf)--d*B-@_k;3_7u(IJ4C?2PV@l6Y==Bjh$kWGj-IwRv`kw3asqd-Z zT5*7XKW)#&>_|l91^bhGQVJLAOW};X?^S8;C;q?O=eqaL)|QI~c1yBvaD6+P=j>HG zR(W)}e{-&mb13!kW^}zCNIj>t zo_`!0SL3YL?ZoS&nbGcS2et#p0p)-kxE&n$n2RdzA3a>w<&=j^17!y*yH4T=h06W} zpN-w1KZn7r?d2w=+Rva|`CUrBhwI3CJCu9s`c7Wu;U`|goyXrf-p~we2abb={9noi z<$_$Gejo?P0djyGAP2|+a)2Bl2gm_(fE*wP$N_SI93ThC0djyGAP2|+a)2Bl2gm_( zfE*wP$N_SI93ThC0djyGAP2|+a)2Bl2gm_(fE*wP$N_SI93ThC0djyGAP2|+a)2Bl z2gm_(fE*wP$N_SI93ThC0djyGAP2|+a)2Bl2gm_(fE*wP$N_SI93ThC0djyGAP2|+ za)2Bl2gm_(fE*wP$N_SI93ThC0djyGAP2|+a)2Bl2gm_(fE?&G2lVmhZYdmuym_6M zn?K-pLl^I-SO~wL>-@f|z8e?6Z@YH&)gF@i*-Gzi(r`l$`h-FC*Q*zk05v z_Wh&2=cB(HpO5cFP`cl5Y*)7HdE+YQ$}1eaEBfCuWh@vDdY)HqSGuKGXn1Jk!n|_| z;o#ij(!9B^DcjvQ`!*b$z^nW65)Q_*?y9LrV`=JT9fpIm6L}B!FQD1#^r>HY%f4;a z?&f~xKHV;HE3%VA{s=_mQ#JYMGcP1)}Htv)xum+^HU16k>doU_+$ z*WL&3r8=9h!Tkl#Tfu$vCwm!npK?0Y>VD?$+1!flN3V2VFKv%VeY|RWWSX}}Ar*H^ zD|TRb=mNag`oGfdJMvs7wRWF2&)MzLEq(l=nf|ZTqtgEV`@dcNK7Qe^pN#(3?NHYB z*h_V%9m**^p30?^*lptzVh^lOSysS@pWK;zU_5kN|BHR8{Qmich?bM$$!R%Brvj!Q z;#+9%ys~$mT4AI4zzdr+)jpbGbafe!L#rr@4M(yPV%Hns169 zd!m11!I{y3wI52@`En*LWf}ZzRl22QXksG|o_5;Ku~61^qlzcRU1fJ<($k~cxSvd!RYeNqfaULB-_xi{;Fzc33VKQqFPWg8r7) z|8gJb{XJ>-^jIJu_sPQ!Xw}}A`TH8$(=7$QY|#H-NF3s#{ok%WfiL~_Q_hVk|6l5X zVW8TU)?`F zQ<2kM)j#!e>bJkUR)RpiZ#{n2nZH%j z|7dr`(c;POuG}Y$`|A6gG->x%{n764XwQ=9|9fAx(*K!sx`Y02cR&64y|4WBQ|=3` z|79GYIUdM3^fL}jf3zy4pI)J#q+JW>FuCsMLTXdW$nsiA>B;f);#Yp<#Zzu*4uR=s$g^ZSkM!}bCGn#BE0yVUqLgO_ko^pWs1Un~~?^p}>E!mF|Tt+O90 z<0bN6DijKCX+H#a!*@QM^#Oi10-DO7sN8q=jof!Tlz}2L*KfS9dEagQulQD}59|=F zk6{Ri-T>|bQlAq%ueraepM1UraY4O z^X9&-%9XFx_a;8(REgg=miy|u75yKmap7at{`1rSm3j@Iy?*2U%zKQZeEyvAr^lhu z|1$nyeyMg3;APs`Ja^^(jUBw8xk)+_z_~# z#D4WBALjaygD&a++!vOWb%$b*6AXZg->u|xcUQ*eb|?UQ)ZEuRuRPz2Qb|4Er_If{ zTY5KzX#gMd9EJzYOQZiQ_8IOExxh>AUoRKb|IOR4CU5-we0{|B>2LeA<{Q+1RsScR z3t#gShBKyAym|5BTjzK`Gz*8L{WuTX782}~pIwRj!_QW6%nTIJFW@iYKC|Zft;+7{ z|CkNTMpb-uXXlTFv#5ru56qDnWsjuOsYcG4ddc%IFF$>O_(xa$ty(+oha@jf?vu)t zPg>O@@$%?`@sQT~zrO#?^SY&9G{g_OBd?A6U)zD1Oyl#m*RMxYi&@K(@#uLAi;cfG z?{&Yu&~^Y6rTEJTUv;Ga>)Xd%w|)KmwpZA85g=1?0);R0L&on;V|+^eB~E4f#gwKV z(tafv=CDgc7t7B%UC&nfU+N+Lg1JBS|LJzC$ua-lU%kfm_SfG2^uPF95^w+b9$bwq zRQ*xIn|n_X=Y^kw{OYeQ>%4h@n2kKLc^2Z!!;*pEWZ*syHkD))D+1xc~oOV||2w+TTjrpAIVi78XQw zPwuys{+IT#tkG$?-(LBoXxiP>C-Kr>oc(OQ{Pn-N-`V+t?#Nm9^uMXk(bTHzX2nm2 z9H@RwXZB7^dzt5{>B)U(WTaW%ey8oz9sghQ6qk?~E90^nkJ{035ljzN<06%D`A_D# zOey1J`NfMD)*;44UgR=&sdc*4|7KjV^ru(YPS>NI{PE4`e~I(YFD=dqU*M0b`RPL8 zKk9h^U1W9 zxVY%E8vji_Zo2+A?d;#b{)qV%J>Nf_mUa{SDNwNkGJB@ol>MgSSKIaoUT6EwpL}#) zzgFWxtv^+HvH7B2j{|pK$Hy{h#G}-_+%D|okeA<>ka4*Hfi%x!N>d+sZcGCpKPM^c zbX&^h+2=l8KkEO}?a{8i_&M9_X6b+U5gQwb?;lOgtwvqpP#J!OD$C`fl*`L&Yr>=E z>yKTmyN+89;Qkh>6|MH(bcJ=kwB9-eG^K$)6X0OWa%j^G`jeNhk71$v~ z_*J6+fmxMzF7ps_Kj3%Qf&T=|&bp=HU%{P>%imK71gJ7yE*s9ud-z+WgWPt--`aZJ zSw3JZd0A2Ve;fM$&F;>Q@H~L|5_4a}`(EpRc|J@lBVTSmG_2x03ENU-ET~KD|D)bF zDG@hn$HR91zjR;!%YGO# z9ubc+d9koZ6UfJ{#iOLYvy*qQ?)1o+gFwo2$hb7^WJ>vaWO@08%mZLs0LX8vad!US zssGP!pNqCDf5&#cT06m?e^b*hkDoyeT89s1e$|_=#8)lh%-UM{1g<;m1c^6VAMjjN zo`N4T&Aux7R{VV(XV-bmVh4y`ftp4B+`gU7x~}qDkawu{-L#H-pPW?Vx0lubl2;AP zMufAn{y_LD`d;o=pYP`!A32kEgtKOx>iG|O-jlqxe_)sF8s4gU$K#TBg*Zqz)?ewo zcxkT(c**sl29zILKkr)WA5%}irN91{=N0|0o)7+{v={81&(eM+B+^L<^;21AUn{X6 zjlcbWD*69%U5t-iiKoc(nRYd$U;XbKi+wkz^eD_Z6=#y`$#b-rw+{^s57*^In)dV8 zKAqODHlECVEVceL{(a3pMtDrsTjrlc&g%31MDLFb4Gp7wDDrqTwT*SU<bxx;@VJA3wiZJ;wIGSo{0q+gbgx9YPwwlIR2Y zqe?%Y0Ib3(s6XU;Z_B+~f2>NqQiv-HU-8`e zdftk^CG!CAxAK?g#9-+E+ViRP9_W{ZEqY(d2o~CleS&57mMY7&Qr6e`S*PjO{};a( z>+Aj&cEwAKcjz;)zX}q7*yBd#z{iF8bFzf7QW|VwMoGSNP$Nk;X&`(2X0COD~Z#8+Go{@36hd_s^ zmyt{P9?a5np0_zissEd|i)nwBY@dti->Ysne|$Tu|C6Cbr3VxCbSkCvW*QUJ!kuNj zz(J>ycdYg=vpztNVgIrUkEca%AirL(_k+F_ZbHq%4%k-uUp`O$UAZiJ7GYal|FqwB zas99N9aw>05Wh9N{c3*otXwDTC>$=SpZNXC{s{!C@p$>Y^0(lR z{bsFPMqaty*}e#k<6$uLznN!{=Ue++Du|tgb@VA^2gUXJdTbMEsrQw#fKvLioBChw ztK$#}8|iH?WIQ3y{gbTUh(unf()0BGc(R|O>fb%xzi_9u9z~qTJdfC$ljB28{C?99 z{^Y~x*^BCb*e{arcWyii{yoOiQ3zqOGxPW|zrQ#)7nO0T<#0PBrKy+n8_ZHQ51{w! zIvt-oJI>AX>yrBabbGXGFMiJUx*qm`KfayS|A}Co9^BJIkqJUP`_6{A%MkKKRi^$7XZbPtIGw{0HWhM|HkH=FM((9zg3Uz5Z(CLi;0| z`wo`=H+s{wlPN{NApDYlTo7Zaf{QB?I|L3>Q+5X`7 zfyruoitRI~i}}3p8{vU7^R}J)|6v=Lom&B4Wu9Mg7W3$G{Y+ZdTmEkJ zn~wW8GF88wy126Px8R>Thwy(l@`z8j+F!<8uT?o%`d{>qmmZdR zXU9|ieYNMX&lf7UlrlE_=Se!O3y4uB65F;H;cXS>C>lIkKu2MKc(!4bXvs^gs=K}YVlTc zojQN(g6AX-n*MLxKe#*N+pqo~{*}_>G1Wii&jl%)?@x`tV`F+{r#u)&UdhU{kqh}F z{^Y~-w}1aXz9s8n4&H~W>tPU%QsYVHpTusdUw>+@FXIVjbzH_}ZT_QFs2`W3)6+_B z5dJ@7H%oiHc=2s1hV?cRkV{!_bN+rEx__zvyED#P+iko)?TD+eBmD8L)xKV$|7AU( z($fH!@JaS<70zH90P%b5lONaf!v8w;%9791)1!gMPlVgz&#XK@?aw4aQM@Fs3-^5b z^7=pKNWNcvKA6k{%XKmDuk#OJhZw$^QtB<^QN9QDU(j*pxQR2rlJ_&yqw4e8b%B}{;bJ&Lf$w3eHI z8kZQ>Gx9sww2`8Kfbln|JYaTk*q(G z`PP}42YMcTY)o;dTs}Dw{w%{^meTlXc{tjbe|0t{n&n+%e?X=G!@+61F022ATUh45 zv;sbgUnTW~zJ4Irg&8oa_=vw7yb<q$JyJcqfyJP+b(YcdWC zsaJ6+*KiP*9+!Kn#4(j9lX8BSCEqWeoK*MCFxQj6OFm#FPY3qV`Rzgde}4P4Yd?O@ z_8Uxlz#rdQ>wn#^)*;q`E$DsfFzu+~jwje>#c->!lzC)qUsAU|(2S36>3@~q>`Gp> zS$BZ2zlyKI-BRZpBHypNkE-FKDNTJ9ZuNP_3Pfv_qCqW`V#XupAZKK1x7kq|K?9VOg}f)?`%J#We|^A zpTf9A{9W1)@u*SJ->^&5GQQxqSL0FUIZUaZ^K%K~5aTXViLa?~i1Aq&mq-s#;}UlE zo~f7ly(#7I2+t||_CW1hjeNjU>vd0$OTYSG>Lv3M@;uVs@_ZOBn__=IMZ6*$ysJh? zW9b~|MdqcQVRoL{k3s4w^_KG)V(ZwCK+St6 z9h{4IW*yzxe(@(CrhU%Vud#o_HuC){@u)W@9;L>)j89enx_A`EA)f2C&bK^wJT{I? zX^%qO$V+2s>MQn!J}2m%(|q4fUH=aCziDsSiP$IV=?iTq7GA|0$A@_@*Qfrc9zQF8 zjq=0y7t`~t+RY!|eCU77+q+qj_qz2*)phZPKkED-z22`y{&h|NL;au9|2ue9uai4} zU70>NeO~SVhGTuqKB~AL;-bj+Q=EleVXg;mhfeSF)2h9i|6TNtITr!P^i}nbx&A4C zYjYF(vHx}OJb$Yu2ZN>mrQML$spHQ$KUeIjHRX5K=0(i>h?IdZySx8SYyJApSzL8h zeFE6%SL%uF8LIIoUGFvJmzFT0<3Jn#J4n1Mj{D2_F#AL;SLZ48{8{}tk@FX^uaocfh-aVIJU2@;JL3Vq{j1wP zUi|T`qW|-)le}gTaP5KdZ_-~ z^okt;x9Uv3-_QqeR@o!g2Y>6q8tZG`?}tntB#!Az3s-SWU)2sUTvYxR)?dlKIOq9W zwRRp1{crlO_8e%pCi5cleB%F`vc27?+pk^zzqxN~{c8Fl>0mw}Ds~=@Niz0lH7`T8 ze@V}mV;iGa61N(MA%OLnqMw`C0siEpef`40T0E*@{V65@WV}e6%CxiCljqBcdERy< z&W}{g`|fg8w=ZE^lm zyXWKQ7`N2-)c2)}jRSvt6FHW7y_#NXC3gv1&Lb23KU3KcaHlT+SmOSe_HV*jbG?|o zir2;Ue^|~JuAG~`r{k-;I^Qpi0IT9G5&;dTWFMI3`}~;t_$}}1a}gdTVgJav2(k`h zbWHAtFhlizm3Azxe`oxy$IqJiTeWr`Ed6iV&6Gy(wJQ6s{{vsTiig|qpBI)y&!jLB zRbM|n@4X#5h-?28?r%ZXu?&wlJGarFe3c!eNGTItf-AYeZ5ZgzZoBsS9=C0u8$5A~J%SpM&``2)TlbxZ3HEi1n49EXFJ zRq~wUSjgJ+P~v^+Z0VN5w)%S^W?NQKf8Uz%+|p1C*V}PRRsrRR|9X($Xs-_X?b^3j zA?vzs^t*8I)xyHU&@+rP&-472)?v(ku;F36-F;?RfuUZFGw1l@qSVuGy;^+_^5u+; zj9j5SSRXLFqFTNWo?3^H-)}rm+8>3Nu){$wzc;PQa>`1|dz9OuSer5&EZ2QM843qy zm&>VaE*2ciSGX~@gMM0{LO*V-$oT9=uf~;gJoH5BDRS{YhD|Du1hkarXZPY-?!2M?ZV zIgjLbXXJTKGNWkc6+2(n?OsgF`=q@)ZCSr{l6E<$lO3m&=XiQD{3<#^+M5 z6;dgA-qI^e^6*i@xXTcc<_Cnx(zL5vFN$+)NpIsYy?)15|{4XYy{LA>s zq|<2`Ul?X;oSk33v&$H7cc1KsCNQqt(z_`uFf!hK{@;Bj@-KSuK3-D4;>pR0|9b9+ z*6<*1>1e7y^8axTcD(3$JNr$vj?Ci8Ad*(W`-!ggqKb^{zZ$U)(CaU9)!-YEYN{}aFUH1g1E`B(nBm0g8hAN*!P z>-pmDjIvYmJ2Rsq?o z_I*X}?~ewQ+(Yd9rr%9JT(qpW3%)ssTTUSn(j17r?5;g`W96wqZw>r&c2)k(xDz`- zI3RYw_~dLJc7V*^UBVxTe{bX;;y(!T{~Z3kEAwxQ3z3Sxf1vdJjFS6zb_VvnX^-nx z8jg!Spg17$UEPlo&%8uG4!k^EH~GD6eS0GR#;!b?+P42-?ek}ey9b6xCNJ&}#9q4D zY!>l9d-4ze@DHz8|Hqv|*p99)ElB)+_x{+J$jSY&(SXR!W#qonZhJ!?jvUX+-*=8t z=4asFq0ES%H~cFvRV(p%$ioP53iAEmTe;VG?|I*t_P;E5c^4s zOY|eyUqlKjgo&c}g>W zFRuS%jup>Fw;n<7NAgPV!|WfG>s}np6xRv{%I~-8) zU1iU0ZC%WsYpCD#*Q3{!3w@FQdJZhZkd(L}@&xj(?|hSkA4UIfO={yCZ&9~L{mzjEM!1Bpj{So}xRE~bC{ zmeT$(17HX2JHsQr$oJ}RyY#ys2Izi$mw&O7W&FI*c>)+ee&R{i2hsmmB>&3phuIIi zA923>_u=oqlRT-8<=-jnhh`_oJFt7YEeF=23wOXlo>pXGX;H~P0x5pw-h5AfC-$81 zzkiu@1%`bgqTe`dxD{_Dm;=%4@9{$Gn-iD9JT zbLWjG^E;8_N}hm&aMDI)oHkjPrsO~SaV}wFnPT7M-#N~~?ZCVP=J_7nfAFAF?il$W z!hBwSV`3K1R~YWBe|qFsu7B?$9xxQ!4tbGQL#OK5sT`X7bRPd(ccOSz z)*a2rbvnsAG;-o#{(g3La-inT*EOY!v0n>R+T{g%?MYcTYj<9lBT|F8Oac>j+5 zpHq7E5_0vheqF81^DoUsvofwy>2$`(U#oFtK9}!*3x`0hA38n1e2nma_U<$7|Lb~Y zGOe!H_;+*t&h>xHUd5{t_fzYR&+}^A}Tziu$(ANgxJ7v`nJyFC+UF1L>}OI%&%m15tS^+U3sfXWkq{Ku`k(Ek$u z6Zy~J)#*6xT>jTXs|b``R{n8c#K{NC{ulG#DXb{{FV6?@zl8ihenR=b)$-qTUk&H@ z@X@Lpx58h81D@BJKLCe7tsl~P0*4r`!{PP5%fI;l?q%g49CR>EHZfrKY5d?l<~1tw znir9O9q--4{*NoqhlYlS2kiMeiGvS{KJIrtx@G^j+*d0O!NtBn4#I*_ zPOqvZn_J0)NX^JJKJn3sGxHBaU{ z?qK9Z$2DZ#jQ9a6U*?L|(aS#LaTn__?Io4Zv|_)x|G>;^`p*9`&n5kiY0b9%PQPGa z?Taqy|08D{FF*Y(@+5hq2n$A)T>4nYYvfnT2mo>AL!3Yu> z{q(zT$F4pP?TyRZ8(otB{g7Yz*W=*c6Y&ScuJ@vL0<;#$i71dw!sme6{-f z<>lXu$E4UTt16CpLHU>b0r|c7Gn+poZN2^hd5?kdor)gqhCUVl!d3ebXTMo+p3DB@ z66ceB3-mt37umPq@0}yHFTBV3<_n)?pR{wbQ)e zR&w6z@79?Elq_cwayFM2V-pB0f`CS=VCyDa_aSos0`?lZ@<3SXAc< zC2Slsq|O<6bBXf?R-PS6{>Fsp{c&tq(nOD3wI1XB#o+7Q9_fz!7xwLo>Hh|~f*rAh z34+VYm60z~8aeBh{JYq<#MO3-Q(f=mBfrtqr?E8klXAJ@A1s&jIbO@={H}5;F6)r= zd4T%7Kl5Jl6THg#VfoCoB^*h^FPH0G=G*}j=aY8ZnAG+@=lL!qXM@V8fs%jZ$GkUk z)k)rPqdYafH}cgz`8V8p{I$d}u?`;VXqT|=QN=Mko*!&gUsG=>tLOd!5Hb%b=l!X_ z=k&xB-%`mN#(sg9 z@w3f%H}cSZ`8OQ6_arJDkbO40$N^LTew9Yw%YNco?uY(w%KeSzURUH_&)X^&Rz z%)eupuzff_I1ffSAP2|+a)2Bl2gm_(fE*wP$N_SI93ThC0djyGAP2|+a^OaC;NZPH zmRoYyQDR-`nerw6eokIr^t(2{m+Si27tA`u_p&YSf6jTiuGDX_$?sY{PyOHVTy3Af z{`;nV@@`43x5v5|RhoK7+SCKTll}Ls`;~dACi{G}tj}}&Zr1;Nmg>i)hWd2+`-O(z z*F87q&(I$?KrcqWNB)l+lYJr<{?i}Hx^d6jo7QCt`8F|oa&}^))wsj{GIBl^PUV!} z>2>F|-xuPt&!oR~!Ld+08;!1Gf0_j^f1#;{r>dxoPBP}|ILv9xRU>EJ7yPm?%$Vn<0t7rK*}=mO2S`bpE|W~{nqz5 zho^3w>i!o#EG{iA$oli*?wc9&J5$Pjw|?YbuCuzhG%x#6V}B~OFXc%pV9EL5`u@2V z<91!izuYg64eiW*+m+5S&Kbl@tuFxo^z%Q!J~^kKzwtVOFHs*Q|5y);mvBJ%nR~Pn zod5af-^urj>CtNYHU3`SFQ?*aeZIF=*mO$C(8#HCkDK?0b+~Q&lmD0lj;@N_|L@q~ zQ`ILkrt4FPBj51d)bLRI{m0|q%ef%)^OfI^o_%i0|4ovAk>4G>Bu~7E4ep13C3&QO z@wL3iw)HrNXWuzJZsJ>VeuVQpW@9^k@3&J)yLhr|&d2*)mv7%j{&5Zk^i}kGTt}Tl zk+ARoQtz*8*0C?EbATG}Z^qxcv-tmt9k%ay$ct0?^=nbRuW-41V(NiBSjQ{M{=_IN z`E!#G|26u0n=Dl zgS=bO*OlMP{g)4{_3!Za$~j2b?yGzk=V#!!Q?UnLYQAduZ|o0QSL{drokCb~RQ-PU zjp~mgI#lmJo=VAe?wsO{X~)xLT%EHpug+P=K7r|ba?bZD?w$UA&HmuuuNN22jyE~q zB8UC${-K;FiX?vo1fB2Apb)HZ3 za4OVc0WDsS#RX=cwEIj)y~;Th$>-8i_epEnqnV-~7!>k^g_YAm{VQzL+N`t>s_G&19d-MI1yS zcIM9H{rf{dVZSPzCnNH@xVVb_bmTh4{JogblYuYK8@JB!O3=u^IjTX`{pOy z(&J}1KM!1MUY~aIFL9C@M;|RTyCY@OD=X`NTem6EYit#V!$&8QVJ`bbVa9_#E=-3~baVvH{ zjsa{rZYAE>?7VLCJTYUgQ;ozIhgBh_K z;HUnvgY|AB>KxgF_c(5&y#9Ss_@nj%#`TI)uUQq3Y(8$gCI46_54~KRbY=Z49RF$w zKIIVrsL4xn`LFO}P1@rr03!Qz{v-Gy?~89{0xtXj=>7ZfGp5E>9KnpU=KaxH{@14z zN70V|X=nG1Twl)fk@y4LF~mEhoh;8OBy6##bbR8?8)@(V1%VZut2))}JVMI9>5rRU zHXm=0v&y{PyN9b##Clwf-Iww6Kj1uGdB2yMMm!nvsLp>2KZp3c@^=$QY%c$jFA#U* zuW=5II)4uFKAb}Zd9l;!|5!MBxNTb)ms?XSK`Rm|3umSfUodes8Mpslk6WkNxb2$! zU(){T}O!f6k$w_Cq_9qIYw$??#jJGn)5DEBQBmnD7PR6Mdc!;(cQ8 zkK@Mg9wzKfIB?RQ2l=A1XW({>>UdxwCGk>BufqR0Jvo4NZr;od1|2v3hOdybM5TtDAQQI%#sWqfj@GLGuvna%s7c0DsLCGQCw z{r(I`Lv`~eO5RJabUU7)J*9nd{73ctk9EXtEAtP?FOuic*KaQW(hkYS_E7DDbHHLq zW2pY#T!*FUuR$%FkGGoq>w2T#L-pt1%DL~_zf8PD*b4GjC;#w2Wt=yW|F{GHyc+L= zql);K4YB`?>`&vpmiQO;yTCZDD}N>LKjv^hI0A+f>o3i?4S#()9@riE7da8m2!A3^ zORr>pVj1@Pp}T_opFco-Pv`&STE_pt&p0e_#8a^^FwPGKKM@x_1Suz=pXFT9)8~LT z?~g|LHyoAum)(keBpekUdpmL-@0oT~?FxUx@&3CxvrqY+)JNtYgr`UgsK!+q<==2u z+T)wwAH=0S);^~!x&Ip4#W@~&qUSFLb)2(a7=?9u(zJ&jZ(=9r^Z8(9|EPfM6E}WG z{73UWoPWEz8WsB-a;^5?LYQ8S7YQ$+|6`*6j~>Q?_ep%> zvib9y-!+zxF%N<8KjdHK|G@51`ak<|5$A(1Ec{dD``Z7;gnhOBj+4$R0vfS(aKMY0 z?^&C#k=K*=U`M@s1dbukxp{q*KVQ3ETuKuSP#&It-^P0IJ(^pMAC_!~s+~}^w&W%% zuZ#B&X8m68?DwSJmg|sXnIi-ZXh*#rv z%zL-AADYFh^LAgKvaEwerw|JsJoUW&P&oLHd!wqp#Zk-pt&_CNsZ{E>&VI-%m&>&> zX@6FKPuk0cRO-k{*cf-FnV0eK5aVII^ZH!(aiaS__h{Sx9bSL>OUpttrA#U9 zhh{8qz1|N^2F*g^)uJ?Tbk#R@lwL`9{ji+npMx2oU#HVlkK1Hy7#-O|M~rI+S9a`Q`mRLCnxe~ zpX2lOLAUxp7P7L@#k(=p?|JF3H)$>3GA>R1E?dg;t>Jo`Z_PMQhOEHwE#QH_{x|KL zbbcG!Lpy;34+BHv=g3LYxt#nDJ+rL1d+_fP_R@mqnSM9*Fy-GnM~Y8Q;V9&JJLAsr z(Uf;z?5$sfPsBhd{o>1IRUSFsw{Z)f<9m^B%y>4}F{Sytb-3?fn1gq@j_jW6$BoYV zzpi~kvm4SrvFFg6XY4}jFd3S|OTK?G{>MVmRk0sd?D4VTfVr>fCsT?Z@ir!*k8)c> zs-F$lT9uEVMe#k@GmaNoT5WY*`TH7x06WDQ9yxEEx4O@D`Fm&mZ`xh84>%z0i00X- zjQgq`?G%#E#rr>=RdPSS5Rv(f)9bw?j*di-rSd z?9`R7@q8QkyjvRj3HHDl&Rz7rgY&!d``@&`=+(dc7k@o`?}^BZSCyCA=g^n48=hOT zega;HoZ}U16)(}-o%R36xvcBD!u^qvkulTXjU~pXR66KJpzAz zv$qF5u=V}$@K6`-H)tI2*Z*#5<@pd^4)o!|(kj~Poej6CD%a9}1^hweN%ST9KX}pp zNB5)u6Vm@9js0F5Z^OSvb$s}t=eM`SDWZ5Cg|87zf0**%z4o7+g7p7i{#EDlfA?$G&BiPJe@6bzeT4rbBjb1c zKWFpya*jp*=Mbl8&Z%F7_e1&o#suukABKj9tM<)h?>jiZ_uK!EW4ixMJMKG+(QN$i zVWU2Hr#NsIdNcN~wBH7-R^v%VzFO=5gCAvl#kbV>s_Gf@J5x&h5c&ps*(qQ&4tL(3 z2S4I>u639QEzK{$zf^uo)vhu3`S|`Qgzle}>jy4mXPWjJ)Y5PN-+OYp|D6)LN%>Kc zrKbHqpY9cPs5LD)!(MyOxd>o zkKav20fN9+r}<)jZ|*Y$dsO)!$4SQ;ne{Lqgm{G2*k9=HyI{pyc?-^XwN4~Lugzo{?u!D=+C`{ks{0n?t1 zWxM{D_LgCVcynlBakX;Y@)`fkj05S%r!YXB^<-!k4$8rgiBLe7b{wVi9C1XHBJaC1 z0jpKNi@gu`_BW{C)a>NQ1@ww(kLyzU?tihj&#`~4L$}gjFbj=8-EtiG>3>`fa`!PO z*OmV878c=m==rF|@nqhc&!vo@Bc;^yfbZ-*$hrC4eBYF&-^H%X&yGvK7yQK&uS-9- zs;BS%|JC{ZZ?6B&fmvv+e<$2N8&@;!?Z5xcb@e!q{)sF_uyXA3+D^NYP^~I-t*&(=OS<68Z0vGTpT&$BsvKU(+u%6(4V z@8#Lg)%8#xm1neHsTba#`rS_DbHsfbpF`ENF%AIUtKTo6l;>#tJYM-cQn}xy2#x`FkWWE#a{PDfc>sWWPZgdsVT-)>Bj3JNKZj!ebm;Ag% z1X7VtX(KF~M}J`4NM6X+l+3T_-)F{jnX*jjmXcF1@v7W^)cidVUI}h&{04rwbr{BL z>)}f9=lS3L8}s?$)QUapl~ah{+JW)e4fNNk=RjV7nm?+w|6Sx0WnK5>iaj4eJm5GP z8ox6+Tl?HOmOR*@C-{7R{%6czPu;<*?(-XJFPL^qgvRk&c_w!9@}Egw2d2A6Fpp;= z4QDB_E`R@vuOuFGy8n?ki~0IPHxc~#KNoi&$CRBtFL^ToOax-yJQjtZImdx7J&ZGn zyI|VzjdT2qFFh4cxcB5`JRZkL`z6s-O>)n1XXRd>J%8<+-n*NjViDA6>i*O={e5C&>CwYEqoNv9>Esj|*uy-p9B5&R2i_XLD!!KW3v@m*jVPo&@o_r6uJ3 z?>qQ833^9Yl6f8*c*6RIBWLGt?~KP}JVzEVPLHNAOhwKs z@_)Pg-zgkEiiLCQS;)t1-b249ZQZX)mCs%4{{!fUxSBtc@qxcPvy%uEU_Nbi)$?K? z`UHOOmL7wxt{A)gWUnkbL(eD!*BB!$> z^1aj7smcGk13X1VZ~Wo?kue#UBO{0p=P<4j5SDsZ^1Gz}-wi#v<^6v=99{>PH-FIb zf%d}u*CaUp|F?HFp;28?_+|#7Ng3)U?JOTtf+vqP($mF%)5J^G2i7I#FCm zDa49Y3(}bc7g)PCQ&xlVp2 z)~KUY@7o;Sd-w00d(XM|p7+jobv#F-|Mj}ycYH@Vdv@bS={N5#)?w7gyK1w{Bimp{ z%fUAJfAYclpa0#WdpuP|yiUcdu>W1m|3?2=|GvxZ?fE?GVfiKepV;%kH zUt5*wD^b%vw#)NAFYx;k$0_EgUjE-@`hV_fIT$eQ0ENBDE19p1J$qIt<;L$Ur7)z9 zdHPj+=OZnJ`_j~_dN=_6!g>k+bCWV|gEZ$P^?lf@Fr8B~{_-pgF8;?3r}{KydaMKb zbvs4`J!FY&V_Z{z<#%&^J~6QZa~)qH>kA#UORO8Q@Xv+O21n^FibgapV4)_<;(W3 z9p6^JtsSs-z}f+82do{icEH*JYX__yuy(-O0c!`W9k6!5+5u|^tR1j+z}f+82do{i zcEH*JYX__yuy(-Ofv0K*5T`2jKc^II3;&i{IZzMmII!cujsvR))(%)Zu$mok<^?7s z>CE$72ZjH+*D`&lvlw2-wxs(KE!|UL8b2Ce{fQsi%~>< z`Wy+=b7u8&TC2bOUt8ntPU8FqjuZU1FY!&elW3pdwrDv_N<1Fpu$Yecx1G3FwwrRv zW*E;mo8AW8oZag$`ZV7Dl5-V;lfi8_fxCnHUX*hb7-#2`xGP;>Yxy?qZt$=1VGPa- z<2?XV9yRIQTfmjVMf^(Qk`^!2m+>!gr-*9-el_?uI6;eWLJ&7_UjBpkyw8A>!8ii% z9u6YoNf3^RaUpTDi{#!~IV|Vj;9oG#Nyp)oiD!?vn^Kr@Sd-}>6+3qe}jMqp3N6++&s+J;~<6HKw*8kLF;`SRp7$?*90Q@WPpH8Rm;WaXD1l2dO zzs=?MsB&1&Kll!kf8f(403)Xu&*OQiH1R5rLSZ%kckeDA|Fjp$!Hnn!`=7WnT7ODB zAEt?2<9RfNOy*=c$hcyImreT{2xz>Vr!oH7kD7lY?>h0>vJ2zjj_Kd!{1ZQq@=`V8 zMHqe8?B!GIW3dy!Pr*1+FJT^N zb-$bPYwmV!r+RkN4$aqk_Q-v$C!wE*5#9;=r{<_q!s_4|E zbJf7%56~YGRo-)exIt>q$QQF$albbaS5=%({m#2vh-0Rro)Mb5+BCt z+S}pl&A@R+oTy*^KF$4MAn92=uWW+_Whs_Gc^>ga54_&J+q6(sq0( zVY^r6&!XSz&aprT^al1kMtv%;zYgGk=Gz6wGwjM%^POQ?{^JD~UovJw108=HRI0jp z;G1jzz+Q&>-@Gx7`_R_VS2vJ9z8~KyJ66{JNb-NE{}<7I$#?(pI(G@(;;L#rqAq+3 z`xfeVQdh2^9|rK5pE!#}H(MyEs=xP3H9bu}Q_gvmJ9nu~a2Sn!27e2BVQ7ck6R+_! raGdj4Z)`w+6{m>%2LJK#4dUl7PN}gm$ggc?divbC*=z9`o}2kEfiE*! literal 0 HcmV?d00001 diff --git a/Templates/BaseGame/game/core/rendering/scripts/gfxData/clouds.cs b/Templates/BaseGame/game/core/rendering/scripts/gfxData/clouds.cs new file mode 100644 index 000000000..00d56d6d3 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/scripts/gfxData/clouds.cs @@ -0,0 +1,55 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +// CloudLayer +//------------------------------------------------------------------------------ + +singleton ShaderData( CloudLayerShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/cloudLayerV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/cloudLayerP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/gl/cloudLayerV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/gl/cloudLayerP.glsl"; + + samplerNames[0] = "$normalHeightMap"; + + pixVersion = 2.0; +}; + +//------------------------------------------------------------------------------ +// BasicClouds +//------------------------------------------------------------------------------ + +singleton ShaderData( BasicCloudsShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/basicCloudsV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/basicCloudsP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/gl/basicCloudsV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/gl/basicCloudsP.glsl"; + + samplerNames[0] = "$diffuseMap"; + + pixVersion = 2.0; +}; diff --git a/Templates/BaseGame/game/core/rendering/scripts/gfxData/commonMaterialData.cs b/Templates/BaseGame/game/core/rendering/scripts/gfxData/commonMaterialData.cs new file mode 100644 index 000000000..c5d8ef5bc --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/scripts/gfxData/commonMaterialData.cs @@ -0,0 +1,79 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Anim flag settings - must match material.h +// These cannot be enumed through script becuase it cannot +// handle the "|" operation for combining them together +// ie. Scroll | Wave does not work. +//----------------------------------------------------------------------------- +$scroll = 1; +$rotate = 2; +$wave = 4; +$scale = 8; +$sequence = 16; + + +// Common stateblock definitions +new GFXSamplerStateData(SamplerClampLinear) +{ + textureColorOp = GFXTOPModulate; + addressModeU = GFXAddressClamp; + addressModeV = GFXAddressClamp; + addressModeW = GFXAddressClamp; + magFilter = GFXTextureFilterLinear; + minFilter = GFXTextureFilterLinear; + mipFilter = GFXTextureFilterLinear; +}; + +new GFXSamplerStateData(SamplerClampPoint) +{ + textureColorOp = GFXTOPModulate; + addressModeU = GFXAddressClamp; + addressModeV = GFXAddressClamp; + addressModeW = GFXAddressClamp; + magFilter = GFXTextureFilterPoint; + minFilter = GFXTextureFilterPoint; + mipFilter = GFXTextureFilterPoint; +}; + +new GFXSamplerStateData(SamplerWrapLinear) +{ + textureColorOp = GFXTOPModulate; + addressModeU = GFXTextureAddressWrap; + addressModeV = GFXTextureAddressWrap; + addressModeW = GFXTextureAddressWrap; + magFilter = GFXTextureFilterLinear; + minFilter = GFXTextureFilterLinear; + mipFilter = GFXTextureFilterLinear; +}; + +new GFXSamplerStateData(SamplerWrapPoint) +{ + textureColorOp = GFXTOPModulate; + addressModeU = GFXTextureAddressWrap; + addressModeV = GFXTextureAddressWrap; + addressModeW = GFXTextureAddressWrap; + magFilter = GFXTextureFilterPoint; + minFilter = GFXTextureFilterPoint; + mipFilter = GFXTextureFilterPoint; +}; diff --git a/Templates/BaseGame/game/core/rendering/scripts/gfxData/scatterSky.cs b/Templates/BaseGame/game/core/rendering/scripts/gfxData/scatterSky.cs new file mode 100644 index 000000000..5add01d8b --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/scripts/gfxData/scatterSky.cs @@ -0,0 +1,48 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +new GFXStateBlockData( ScatterSkySBData ) +{ + cullMode = "GFXCullNone"; + + zDefined = true; + zEnable = true; + zWriteEnable = false; + + samplersDefined = true; + samplerStates[0] = SamplerClampLinear; + samplerStates[1] = SamplerClampLinear; + vertexColorEnable = true; +}; + +singleton ShaderData( ScatterSkyShaderData ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/scatterSkyV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/scatterSkyP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/gl/scatterSkyV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/gl/scatterSkyP.glsl"; + + samplerNames[0] = "$nightSky"; + + pixVersion = 2.0; +}; diff --git a/Templates/BaseGame/game/core/rendering/scripts/gfxData/shaders.cs b/Templates/BaseGame/game/core/rendering/scripts/gfxData/shaders.cs new file mode 100644 index 000000000..da3b7c864 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/scripts/gfxData/shaders.cs @@ -0,0 +1,152 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// This file contains shader data necessary for various engine utility functions +//----------------------------------------------------------------------------- + + +singleton ShaderData( ParticlesShaderData ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/particlesV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/particlesP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/gl/particlesV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/gl/particlesP.glsl"; + + samplerNames[0] = "$diffuseMap"; + samplerNames[1] = "$deferredTex"; + samplerNames[2] = "$paraboloidLightMap"; + + pixVersion = 2.0; +}; + +singleton ShaderData( OffscreenParticleCompositeShaderData ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/particleCompositeV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/particleCompositeP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/gl/particleCompositeV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/gl/particleCompositeP.glsl"; + + samplerNames[0] = "$colorSource"; + samplerNames[1] = "$edgeSource"; + + pixVersion = 2.0; +}; + +//----------------------------------------------------------------------------- +// Planar Reflection +//----------------------------------------------------------------------------- +new ShaderData( ReflectBump ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/planarReflectBumpV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/planarReflectBumpP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/gl/planarReflectBumpV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/gl/planarReflectBumpP.glsl"; + + samplerNames[0] = "$diffuseMap"; + samplerNames[1] = "$refractMap"; + samplerNames[2] = "$bumpMap"; + + pixVersion = 2.0; +}; + +new ShaderData( Reflect ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/planarReflectV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/planarReflectP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/gl/planarReflectV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/gl/planarReflectP.glsl"; + + samplerNames[0] = "$diffuseMap"; + samplerNames[1] = "$refractMap"; + + pixVersion = 1.4; +}; + +//----------------------------------------------------------------------------- +// fxFoliageReplicator +//----------------------------------------------------------------------------- +new ShaderData( fxFoliageReplicatorShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/fxFoliageReplicatorV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/fxFoliageReplicatorP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/gl/fxFoliageReplicatorV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/gl/fxFoliageReplicatorP.glsl"; + + samplerNames[0] = "$diffuseMap"; + samplerNames[1] = "$alphaMap"; + + pixVersion = 1.4; +}; + +singleton ShaderData( VolumetricFogDeferredShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/VolumetricFog/VFogPreV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/VolumetricFog/VFogPreP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/VolumetricFog/gl/VFogPreV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/VolumetricFog/gl/VFogPreP.glsl"; + + pixVersion = 3.0; +}; +singleton ShaderData( VolumetricFogShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/VolumetricFog/VFogV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/VolumetricFog/VFogP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/VolumetricFog/gl/VFogV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/VolumetricFog/gl/VFogP.glsl"; + + samplerNames[0] = "$deferredTex"; + samplerNames[1] = "$depthBuffer"; + samplerNames[2] = "$frontBuffer"; + samplerNames[3] = "$density"; + + pixVersion = 3.0; +}; +singleton ShaderData( VolumetricFogReflectionShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/VolumetricFog/VFogPreV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/VolumetricFog/VFogRefl.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/VolumetricFog/gl/VFogPreV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/VolumetricFog/gl/VFogRefl.glsl"; + + pixVersion = 3.0; +}; +singleton ShaderData( CubemapSaveShader ) +{ + DXVertexShaderFile = "shaders/common/cubemapSaveV.hlsl"; + DXPixelShaderFile = "shaders/common/cubemapSaveP.hlsl"; + + OGLVertexShaderFile = "shaders/common/gl/cubemapSaveV.glsl"; + OGLPixelShaderFile = "shaders/common/gl/cubemapSaveP.glsl"; + + samplerNames[0] = "$cubemapTex"; + + pixVersion = 3.0; +}; \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/scripts/gfxData/terrainBlock.cs b/Templates/BaseGame/game/core/rendering/scripts/gfxData/terrainBlock.cs new file mode 100644 index 000000000..69802b1da --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/scripts/gfxData/terrainBlock.cs @@ -0,0 +1,36 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +/// Used when generating the blended base texture. +singleton ShaderData( TerrainBlendShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/terrain/blendV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/terrain/blendP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/terrain/gl/blendV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/terrain/gl/blendP.glsl"; + + samplerNames[0] = "layerTex"; + samplerNames[1] = "textureMap"; + + pixVersion = 2.0; +}; diff --git a/Templates/BaseGame/game/core/rendering/scripts/gfxData/water.cs b/Templates/BaseGame/game/core/rendering/scripts/gfxData/water.cs new file mode 100644 index 000000000..ec5e4be71 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/scripts/gfxData/water.cs @@ -0,0 +1,208 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + + + +//----------------------------------------------------------------------------- +// Water +//----------------------------------------------------------------------------- + +singleton ShaderData( WaterShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/water/waterV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/water/waterP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/water/gl/waterV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/water/gl/waterP.glsl"; + + samplerNames[0] = "$bumpMap"; // noise + samplerNames[1] = "$deferredTex"; // #deferred + samplerNames[2] = "$reflectMap"; // $reflectbuff + samplerNames[3] = "$refractBuff"; // $backbuff + samplerNames[4] = "$skyMap"; // $cubemap + samplerNames[5] = "$foamMap"; // foam + samplerNames[6] = "$depthGradMap"; // depthMap ( color gradient ) + + pixVersion = 3.0; +}; + +new GFXSamplerStateData(WaterSampler) +{ + textureColorOp = GFXTOPModulate; + addressModeU = GFXAddressWrap; + addressModeV = GFXAddressWrap; + addressModeW = GFXAddressWrap; + magFilter = GFXTextureFilterLinear; + minFilter = GFXTextureFilterAnisotropic; + mipFilter = GFXTextureFilterLinear; + maxAnisotropy = 4; +}; + +singleton GFXStateBlockData( WaterStateBlock ) +{ + samplersDefined = true; + samplerStates[0] = WaterSampler; // noise + samplerStates[1] = SamplerClampPoint; // #deferred + samplerStates[2] = SamplerClampLinear; // $reflectbuff + samplerStates[3] = SamplerClampPoint; // $backbuff + samplerStates[4] = SamplerWrapLinear; // $cubemap + samplerStates[5] = SamplerWrapLinear; // foam + samplerStates[6] = SamplerClampLinear; // depthMap ( color gradient ) + cullDefined = true; + cullMode = "GFXCullCCW"; +}; + +singleton GFXStateBlockData( UnderWaterStateBlock : WaterStateBlock ) +{ + cullMode = "GFXCullCW"; +}; + +singleton CustomMaterial( WaterMat ) +{ + sampler["deferredTex"] = "#deferred"; + sampler["reflectMap"] = "$reflectbuff"; + sampler["refractBuff"] = "$backbuff"; + // These samplers are set in code not here. + // This is to allow different WaterObject instances + // to use this same material but override these textures + // per instance. + //sampler["bumpMap"] = ""; + //sampler["skyMap"] = ""; + //sampler["foamMap"] = ""; + //sampler["depthGradMap"] = ""; + + shader = WaterShader; + stateBlock = WaterStateBlock; + version = 3.0; + + useAnisotropic[0] = true; +}; + +//----------------------------------------------------------------------------- +// Underwater +//----------------------------------------------------------------------------- + +singleton ShaderData( UnderWaterShader : WaterShader ) +{ + defines = "UNDERWATER"; +}; + +singleton CustomMaterial( UnderwaterMat ) +{ + // These samplers are set in code not here. + // This is to allow different WaterObject instances + // to use this same material but override these textures + // per instance. + //sampler["bumpMap"] = "core/art/water/noise02"; + //sampler["foamMap"] = "core/art/water/foam"; + + sampler["deferredTex"] = "#deferred"; + sampler["refractBuff"] = "$backbuff"; + + shader = UnderWaterShader; + stateBlock = UnderWaterStateBlock; + specular = "0.75 0.75 0.75 1.0"; + specularPower = 48.0; + version = 3.0; +}; + +//----------------------------------------------------------------------------- +// Basic Water +//----------------------------------------------------------------------------- + +singleton ShaderData( WaterBasicShader ) +{ + DXVertexShaderFile = $Core::CommonShaderPath @ "/water/waterBasicV.hlsl"; + DXPixelShaderFile = $Core::CommonShaderPath @ "/water/waterBasicP.hlsl"; + + OGLVertexShaderFile = $Core::CommonShaderPath @ "/water/gl/waterBasicV.glsl"; + OGLPixelShaderFile = $Core::CommonShaderPath @ "/water/gl/waterBasicP.glsl"; + + samplerNames[0] = "$bumpMap"; + samplerNames[2] = "$reflectMap"; + samplerNames[3] = "$refractBuff"; + samplerNames[4] = "$skyMap"; + samplerNames[5] = "$depthGradMap"; + + pixVersion = 2.0; +}; + +singleton GFXStateBlockData( WaterBasicStateBlock ) +{ + samplersDefined = true; + samplerStates[0] = WaterSampler; // noise + samplerStates[2] = SamplerClampLinear; // $reflectbuff + samplerStates[3] = SamplerClampPoint; // $backbuff + samplerStates[4] = SamplerWrapLinear; // $cubemap + cullDefined = true; + cullMode = "GFXCullCCW"; +}; + +singleton GFXStateBlockData( UnderWaterBasicStateBlock : WaterBasicStateBlock ) +{ + cullMode = "GFXCullCW"; +}; + +singleton CustomMaterial( WaterBasicMat ) +{ + // These samplers are set in code not here. + // This is to allow different WaterObject instances + // to use this same material but override these textures + // per instance. + //sampler["bumpMap"] = "core/art/water/noise02"; + //sampler["skyMap"] = "$cubemap"; + + //sampler["deferredTex"] = "#deferred"; + sampler["reflectMap"] = "$reflectbuff"; + sampler["refractBuff"] = "$backbuff"; + + cubemap = NewLevelSkyCubemap; + shader = WaterBasicShader; + stateBlock = WaterBasicStateBlock; + version = 2.0; +}; + +//----------------------------------------------------------------------------- +// Basic UnderWater +//----------------------------------------------------------------------------- + +singleton ShaderData( UnderWaterBasicShader : WaterBasicShader) +{ + defines = "UNDERWATER"; +}; + +singleton CustomMaterial( UnderwaterBasicMat ) +{ + // These samplers are set in code not here. + // This is to allow different WaterObject instances + // to use this same material but override these textures + // per instance. + //sampler["bumpMap"] = "core/art/water/noise02"; + //samplers["skyMap"] = "$cubemap"; + + //sampler["deferredTex"] = "#deferred"; + sampler["refractBuff"] = "$backbuff"; + + shader = UnderWaterBasicShader; + stateBlock = UnderWaterBasicStateBlock; + version = 2.0; +}; \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/scripts/gfxprofile/D3D9.ATITechnologiesInc.cs b/Templates/BaseGame/game/core/rendering/scripts/gfxprofile/D3D9.ATITechnologiesInc.cs new file mode 100644 index 000000000..10c6bdf5b --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/scripts/gfxprofile/D3D9.ATITechnologiesInc.cs @@ -0,0 +1,36 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// ATI Vendor Profile Script +// +// This script is responsible for setting global +// capability strings based on the nVidia vendor. + +if(GFXCardProfiler::getVersion() < 64.44) +{ + $GFX::OutdatedDrivers = true; + $GFX::OutdatedDriversLink = "You can get newer drivers here.."; +} +else +{ + $GFX::OutdatedDrivers = false; +} diff --git a/Templates/BaseGame/game/core/rendering/scripts/gfxprofile/D3D9.NVIDIA.GeForce8600.cs b/Templates/BaseGame/game/core/rendering/scripts/gfxprofile/D3D9.NVIDIA.GeForce8600.cs new file mode 100644 index 000000000..328788dac --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/scripts/gfxprofile/D3D9.NVIDIA.GeForce8600.cs @@ -0,0 +1,36 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// nVidia Vendor Profile Script +// +// This script is responsible for setting global +// capability strings based on the nVidia vendor. + +if(GFXCardProfiler::getVersion() < 1.2) +{ + $GFX::OutdatedDrivers = true; + $GFX::OutdatedDriversLink = "You can get newer drivers here.."; +} +else +{ + $GFX::OutdatedDrivers = false; +} diff --git a/Templates/BaseGame/game/core/rendering/scripts/gfxprofile/D3D9.NVIDIA.QuadroFXGo1000.cs b/Templates/BaseGame/game/core/rendering/scripts/gfxprofile/D3D9.NVIDIA.QuadroFXGo1000.cs new file mode 100644 index 000000000..5681b2f6d --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/scripts/gfxprofile/D3D9.NVIDIA.QuadroFXGo1000.cs @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// nVidia Vendor Profile Script +// +// This script is responsible for setting global +// capability strings based on the nVidia vendor. + +if(GFXCardProfiler::getVersion() < 53.82) +{ + $GFX::OutdatedDrivers = true; + $GFX::OutdatedDriversLink = "You can get newer drivers here.."; +} +else +{ + $GFX::OutdatedDrivers = false; +} + +// Silly card has trouble with this! +GFXCardProfiler::setCapability("autoMipmapLevel", false); diff --git a/Templates/BaseGame/game/core/rendering/scripts/gfxprofile/D3D9.NVIDIA.cs b/Templates/BaseGame/game/core/rendering/scripts/gfxprofile/D3D9.NVIDIA.cs new file mode 100644 index 000000000..b33b8d5d3 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/scripts/gfxprofile/D3D9.NVIDIA.cs @@ -0,0 +1,36 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// nVidia Vendor Profile Script +// +// This script is responsible for setting global +// capability strings based on the nVidia vendor. + +if(GFXCardProfiler::getVersion() < 56.72) +{ + $GFX::OutdatedDrivers = true; + $GFX::OutdatedDriversLink = "You can get newer drivers here.."; +} +else +{ + $GFX::OutdatedDrivers = false; +} diff --git a/Templates/BaseGame/game/core/rendering/scripts/gfxprofile/D3D9.cs b/Templates/BaseGame/game/core/rendering/scripts/gfxprofile/D3D9.cs new file mode 100644 index 000000000..e1e299341 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/scripts/gfxprofile/D3D9.cs @@ -0,0 +1,26 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// Direct3D 9 Renderer Profile Script +// +// This script is responsible for setting global +// capability strings based on the D3D9 renderer type. \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/scripts/renderManager.cs b/Templates/BaseGame/game/core/rendering/scripts/renderManager.cs new file mode 100644 index 000000000..4a80a45b1 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/scripts/renderManager.cs @@ -0,0 +1,126 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +function initRenderManager() +{ + assert( !isObject( DiffuseRenderPassManager ), "initRenderManager() - DiffuseRenderPassManager already initialized!" ); + + new RenderPassManager( DiffuseRenderPassManager ); + + // This token, and the associated render managers, ensure that driver MSAA + // does not get used for Advanced Lighting renders. The 'AL_FormatResolve' + // PostEffect copies the result to the backbuffer. + new RenderFormatToken(AL_FormatToken) + { + enabled = "false"; + + //When hdr is enabled this will be changed to the appropriate format + format = "GFXFormatR8G8B8A8_SRGB"; + depthFormat = "GFXFormatD24S8"; + aaLevel = 0; // -1 = match backbuffer + + // The contents of the back buffer before this format token is executed + // is provided in $inTex + copyEffect = "AL_FormatCopy"; + + // The contents of the render target created by this format token is + // provided in $inTex + resolveEffect = "AL_FormatCopy"; + }; + DiffuseRenderPassManager.addManager( new RenderPassStateBin() { renderOrder = 0.001; stateToken = AL_FormatToken; } ); + + // We really need to fix the sky to render after all the + // meshes... but that causes issues in reflections. + DiffuseRenderPassManager.addManager( new RenderObjectMgr(SkyBin) { bintype = "Sky"; renderOrder = 0.1; processAddOrder = 0.1; } ); + + //DiffuseRenderPassManager.addManager( new RenderVistaMgr() { bintype = "Vista"; renderOrder = 0.15; processAddOrder = 0.15; } ); + + DiffuseRenderPassManager.addManager( new RenderObjectMgr(BeginBin) { bintype = "Begin"; renderOrder = 0.2; processAddOrder = 0.2; } ); + // Normal mesh rendering. + DiffuseRenderPassManager.addManager( new RenderTerrainMgr(TerrainBin) { renderOrder = 0.4; processAddOrder = 0.4; basicOnly = true; } ); + DiffuseRenderPassManager.addManager( new RenderMeshMgr(MeshBin) { bintype = "Mesh"; renderOrder = 0.5; processAddOrder = 0.5; basicOnly = true; } ); + DiffuseRenderPassManager.addManager( new RenderImposterMgr(ImposterBin) { renderOrder = 0.56; processAddOrder = 0.56; } ); + DiffuseRenderPassManager.addManager( new RenderObjectMgr(ObjectBin) { bintype = "Object"; renderOrder = 0.6; processAddOrder = 0.6; } ); + + DiffuseRenderPassManager.addManager( new RenderObjectMgr(ShadowBin) { bintype = "Shadow"; renderOrder = 0.7; processAddOrder = 0.7; } ); + DiffuseRenderPassManager.addManager( new RenderMeshMgr(DecalRoadBin) { bintype = "DecalRoad"; renderOrder = 0.8; processAddOrder = 0.8; } ); + DiffuseRenderPassManager.addManager( new RenderMeshMgr(DecalBin) { bintype = "Decal"; renderOrder = 0.81; processAddOrder = 0.81; } ); + DiffuseRenderPassManager.addManager( new RenderOcclusionMgr(OccluderBin){ bintype = "Occluder"; renderOrder = 0.9; processAddOrder = 0.9; } ); + + // We now render translucent objects that should handle + // their own fogging and lighting. + + // Note that the fog effect is triggered before this bin. + DiffuseRenderPassManager.addManager( new RenderObjectMgr(ObjTranslucentBin) { bintype = "ObjectTranslucent"; renderOrder = 1.0; processAddOrder = 1.0; } ); + + DiffuseRenderPassManager.addManager( new RenderObjectMgr(WaterBin) { bintype = "Water"; renderOrder = 1.2; processAddOrder = 1.2; } ); + DiffuseRenderPassManager.addManager( new RenderObjectMgr(FoliageBin) { bintype = "Foliage"; renderOrder = 1.3; processAddOrder = 1.3; } ); + DiffuseRenderPassManager.addManager( new RenderParticleMgr(ParticleBin) { renderOrder = 1.35; processAddOrder = 1.35; } ); + DiffuseRenderPassManager.addManager( new RenderTranslucentMgr(TranslucentBin){ renderOrder = 1.4; processAddOrder = 1.4; } ); + + DiffuseRenderPassManager.addManager(new RenderObjectMgr(FogBin){ bintype = "ObjectVolumetricFog"; renderOrder = 1.45; processAddOrder = 1.45; } ); + + // Note that the GlowPostFx is triggered after this bin. + DiffuseRenderPassManager.addManager( new RenderGlowMgr(GlowBin) { renderOrder = 1.5; processAddOrder = 1.5; } ); + + // We render any editor stuff from this bin. Note that the HDR is + // completed before this bin to keep editor elements from tone mapping. + DiffuseRenderPassManager.addManager( new RenderObjectMgr(EditorBin) { bintype = "Editor"; renderOrder = 1.6; processAddOrder = 1.6; } ); + + // Resolve format change token last. + DiffuseRenderPassManager.addManager( new RenderPassStateBin(FinalBin) { renderOrder = 1.7; stateToken = AL_FormatToken; } ); +} + +/// This is the Default PostFX state block. Put here to prevent any missing object +/// errors for below dependencies +singleton GFXStateBlockData( PFX_DefaultStateBlock ) +{ + zDefined = true; + zEnable = false; + zWriteEnable = false; + + samplersDefined = true; + samplerStates[0] = SamplerClampLinear; +}; + +/// This post effect is used to copy data from the non-MSAA back-buffer to the +/// device back buffer (which could be MSAA). It must be declared here so that +/// it is initialized when 'AL_FormatToken' is initialzed. +singleton GFXStateBlockData( AL_FormatTokenState : PFX_DefaultStateBlock ) +{ + samplersDefined = true; + samplerStates[0] = SamplerClampPoint; +}; + +singleton PostEffect( AL_FormatCopy ) +{ + // This PostEffect is used by 'AL_FormatToken' directly. It is never added to + // the PostEffectManager. Do not call enable() on it. + isEnabled = false; + allowReflectPass = true; + + shader = PFX_PassthruShader; + stateBlock = AL_FormatTokenState; + + texture[0] = "$inTex"; + target = "$backbuffer"; +}; diff --git a/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/VFogP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/VFogP.hlsl new file mode 100644 index 000000000..7de14a87d --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/VFogP.hlsl @@ -0,0 +1,87 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// Volumetric Fog final pixel shader V2.00 +#include "../shaderModel.hlsl" +#include "../shaderModelAutoGen.hlsl" +#include "../torque.hlsl" + +TORQUE_UNIFORM_SAMPLER2D(deferredTex, 0); +TORQUE_UNIFORM_SAMPLER2D(depthBuffer, 1); +TORQUE_UNIFORM_SAMPLER2D(frontBuffer, 2); +TORQUE_UNIFORM_SAMPLER2D(density, 3); + +uniform float3 ambientColor; +uniform float accumTime; +uniform float4 fogColor; +uniform float4 modspeed;//xy speed layer 1, zw speed layer 2 +uniform float2 viewpoint; +uniform float2 texscale; +uniform float fogDensity; +uniform float preBias; +uniform float textured; +uniform float modstrength; +uniform float numtiles; +uniform float fadesize; +uniform float2 PixelSize; + +struct ConnectData +{ + float4 hpos : TORQUE_POSITION; + float4 htpos : TEXCOORD0; + float2 uv0 : TEXCOORD1; +}; + +float4 main( ConnectData IN ) : TORQUE_TARGET0 +{ + float2 uvscreen=((IN.htpos.xy/IN.htpos.w) + 1.0 ) / 2.0; + uvscreen.y = 1.0 - uvscreen.y; + + float obj_test = TORQUE_DEFERRED_UNCONDITION(deferredTex, uvscreen).w * preBias; + float depth = TORQUE_TEX2D(depthBuffer, uvscreen).r; + float front = TORQUE_TEX2D(frontBuffer, uvscreen).r; + + if (depth <= front) + return float4(0,0,0,0); + else if ( obj_test < depth ) + depth = obj_test; + if ( front >= 0.0) + depth -= front; + + float diff = 1.0; + float3 col = fogColor.rgb; + if (textured != 0.0) + { + float2 offset = viewpoint + ((-0.5 + (texscale * uvscreen)) * numtiles); + + float2 mod1 = TORQUE_TEX2D(density, (offset + (modspeed.xy*accumTime))).rg; + float2 mod2 = TORQUE_TEX2D(density, (offset + (modspeed.zw*accumTime))).rg; + diff = (mod2.r + mod1.r) * modstrength; + col *= (2.0 - ((mod1.g + mod2.g) * fadesize))/2.0; + } + + col *= ambientColor; + + float4 resultColor = float4(col, 1.0 - saturate(exp(-fogDensity * depth * diff * fadesize))); + + return hdrEncode(resultColor); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/VFogPreP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/VFogPreP.hlsl new file mode 100644 index 000000000..9d5060935 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/VFogPreP.hlsl @@ -0,0 +1,40 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// Volumetric Fog deferred pixel shader V1.00 +#include "../shaderModel.hlsl" + +struct ConnectData +{ + float4 hpos : TORQUE_POSITION; + float4 pos : TEXCOORD0; +}; + +float4 main( ConnectData IN ) : TORQUE_TARGET0 +{ + float OUT; + + clip( IN.pos.w ); + OUT = IN.pos.w; + + return float4(OUT,0,0,1); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/VFogPreV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/VFogPreV.hlsl new file mode 100644 index 000000000..b736e0d0d --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/VFogPreV.hlsl @@ -0,0 +1,44 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// Volumetric Fog deferred vertex shader V1.00 + +#include "../shaderModel.hlsl" +#include "../hlslStructs.hlsl" + +struct ConnectData +{ + float4 hpos : TORQUE_POSITION; + float4 pos : TEXCOORD0; +}; + +uniform float4x4 modelView; + +ConnectData main( VertexIn_P IN) +{ + ConnectData OUT; + + OUT.hpos = mul(modelView, float4(IN.pos, 1.0)); + OUT.pos = OUT.hpos; + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/VFogRefl.hlsl b/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/VFogRefl.hlsl new file mode 100644 index 000000000..380233b5f --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/VFogRefl.hlsl @@ -0,0 +1,38 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// Volumetric Fog Reflection pixel shader V1.00 +#include "../shaderModel.hlsl" +uniform float4 fogColor; +uniform float fogDensity; +uniform float reflStrength; + +struct ConnectData +{ + float4 hpos : TORQUE_POSITION; + float4 pos : TEXCOORD0; +}; + +float4 main( ConnectData IN ) : TORQUE_TARGET0 +{ + return float4(fogColor.rgb,saturate(fogDensity*reflStrength)); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/VFogV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/VFogV.hlsl new file mode 100644 index 000000000..167f83946 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/VFogV.hlsl @@ -0,0 +1,46 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// Volumetric Fog final vertex shader V1.00 + +#include "../shaderModel.hlsl" +#include "../hlslStructs.hlsl" + +struct ConnectData +{ + float4 hpos : TORQUE_POSITION; + float4 htpos : TEXCOORD0; + float2 uv0 : TEXCOORD1; +}; + +uniform float4x4 modelView; + +ConnectData main( VertexIn_PNTT IN) +{ + ConnectData OUT; + + OUT.hpos = mul(modelView, float4(IN.pos,1.0)); + OUT.htpos = OUT.hpos; + OUT.uv0 = IN.uv0; + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/gl/VFogP.glsl b/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/gl/VFogP.glsl new file mode 100644 index 000000000..fcfa31244 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/gl/VFogP.glsl @@ -0,0 +1,87 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../gl/hlslCompat.glsl" +#include "shadergen:/autogenConditioners.h" +#include "../../gl/torque.glsl" + +uniform sampler2D deferredTex; +uniform sampler2D depthBuffer; +uniform sampler2D frontBuffer; +uniform sampler2D density; + +uniform float accumTime; +uniform vec4 fogColor; +uniform float fogDensity; +uniform float preBias; +uniform float textured; +uniform float modstrength; +uniform vec4 modspeed;//xy speed layer 1, zw speed layer 2 +uniform vec2 viewpoint; +uniform vec2 texscale; +uniform vec3 ambientColor; +uniform float numtiles; +uniform float fadesize; +uniform vec2 PixelSize; + +in vec4 _hpos; +#define IN_hpos _hpos +out vec4 OUT_col; + +void main() +{ + vec2 uvscreen=((IN_hpos.xy/IN_hpos.w) + 1.0 ) / 2.0; + uvscreen.y = 1.0 - uvscreen.y; + + float obj_test = deferredUncondition( deferredTex, uvscreen).w * preBias; + float depth = tex2D(depthBuffer,uvscreen).r; + float front = tex2D(frontBuffer,uvscreen).r; + + if (depth <= front) + { + OUT_col = vec4(0,0,0,0); + return; + } + + else if ( obj_test < depth ) + depth = obj_test; + if ( front >= 0.0) + depth -= front; + + float diff = 1.0; + vec3 col = fogColor.rgb; + if (textured != 0.0) + { + vec2 offset = viewpoint + ((-0.5 + (texscale * uvscreen)) * numtiles); + + vec2 mod1 = tex2D(density,(offset + (modspeed.xy*accumTime))).rg; + vec2 mod2= tex2D(density,(offset + (modspeed.zw*accumTime))).rg; + diff = (mod2.r + mod1.r) * modstrength; + col *= (2.0 - ((mod1.g + mod2.g) * fadesize))/2.0; + } + + col *= ambientColor; + + vec4 returnColor = vec4(col, 1.0 - saturate(exp(-fogDensity * depth * diff * fadesize))); + + OUT_col = hdrEncode(returnColor); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/gl/VFogPreP.glsl b/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/gl/VFogPreP.glsl new file mode 100644 index 000000000..017ea6ef8 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/gl/VFogPreP.glsl @@ -0,0 +1,37 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../gl/hlslCompat.glsl" + +in vec4 _hpos; +#define IN_hpos _hpos + +out vec4 OUT_col; + +void main() +{ + float OUT; + clip( IN_hpos.w ); + OUT = IN_hpos.w; + + OUT_col = vec4(OUT,0,0,1); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/gl/VFogPreV.glsl b/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/gl/VFogPreV.glsl new file mode 100644 index 000000000..2f2a1318a --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/gl/VFogPreV.glsl @@ -0,0 +1,42 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../gl/hlslCompat.glsl" + +in vec4 vPosition; +#define IN_position vPosition + +out vec4 _hpos; +#define OUT_hpos _hpos + +uniform mat4 modelView; + +void main() +{ + vec4 inPos = IN_position; + inPos.w = 1.0; + + OUT_hpos = tMul( modelView, inPos ); + + gl_Position = OUT_hpos; + correctSSP(gl_Position); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/gl/VFogRefl.glsl b/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/gl/VFogRefl.glsl new file mode 100644 index 000000000..78e149fbf --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/gl/VFogRefl.glsl @@ -0,0 +1,33 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../gl/hlslCompat.glsl" + +uniform vec4 fogColor; +uniform float fogDensity; +uniform float reflStrength; +out vec4 OUT_col; + +void main() +{ + OUT_col = vec4(fogColor.rgb,saturate(fogDensity*reflStrength)); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/gl/VFogV.glsl b/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/gl/VFogV.glsl new file mode 100644 index 000000000..57b3ba87e --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/VolumetricFog/gl/VFogV.glsl @@ -0,0 +1,38 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../gl/hlslCompat.glsl" + +in vec4 vPosition; +#define IN_position vPosition + +out vec4 _hpos; +#define OUT_hpos _hpos + +uniform mat4 modelView; + +void main() +{ + OUT_hpos = tMul(modelView, IN_position); + gl_Position = OUT_hpos; + correctSSP(gl_Position); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/basicCloudsP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/basicCloudsP.hlsl new file mode 100644 index 000000000..4b40e5e8c --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/basicCloudsP.hlsl @@ -0,0 +1,37 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "torque.hlsl" + +struct ConnectData +{ + float4 hpos : TORQUE_POSITION; + float2 texCoord : TEXCOORD0; +}; + +TORQUE_UNIFORM_SAMPLER2D(diffuseMap, 0); + +float4 main( ConnectData IN ) : TORQUE_TARGET0 +{ + float4 col = TORQUE_TEX2D(diffuseMap, IN.texCoord); + return hdrEncode( col ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/basicCloudsV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/basicCloudsV.hlsl new file mode 100644 index 000000000..a176fdbcd --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/basicCloudsV.hlsl @@ -0,0 +1,58 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "shaderModel.hlsl" + +struct CloudVert +{ + float3 pos : POSITION; + float2 uv0 : TEXCOORD0; +}; + +struct ConnectData +{ + float4 hpos : TORQUE_POSITION; + float2 texCoord : TEXCOORD0; +}; + +uniform float4x4 modelview; +uniform float2 texDirection; +uniform float2 texOffset; +uniform float accumTime; +uniform float texScale; + + +ConnectData main( CloudVert IN ) +{ + ConnectData OUT; + + OUT.hpos = mul(modelview, float4(IN.pos,1.0)); + + float2 uv = IN.uv0; + uv += texOffset; + uv *= texScale; + uv += accumTime * texDirection; + + OUT.texCoord = uv; + + return OUT; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/cloudLayerP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/cloudLayerP.hlsl new file mode 100644 index 000000000..efa8fe0b4 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/cloudLayerP.hlsl @@ -0,0 +1,146 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "shaderModel.hlsl" +#include "torque.hlsl" + +//----------------------------------------------------------------------------- +// Structures +//----------------------------------------------------------------------------- +struct ConnectData +{ + float4 hpos : TORQUE_POSITION; + float4 texCoord12 : TEXCOORD0; + float4 texCoord34 : TEXCOORD1; + float3 vLightTS : TEXCOORD2; // light vector in tangent space, denormalized + float3 vViewTS : TEXCOORD3; // view vector in tangent space, denormalized + float worldDist : TEXCOORD4; +}; + +//----------------------------------------------------------------------------- +// Uniforms +//----------------------------------------------------------------------------- +TORQUE_UNIFORM_SAMPLER2D(normalHeightMap, 0); +uniform float3 ambientColor; +uniform float3 sunColor; +uniform float cloudCoverage; +uniform float3 cloudBaseColor; +uniform float cloudExposure; + +//----------------------------------------------------------------------------- +// Globals +//----------------------------------------------------------------------------- +// The per-color weighting to be used for luminance calculations in RGB order. +static const float3 LUMINANCE_VECTOR = float3(0.2125f, 0.7154f, 0.0721f); + + +//----------------------------------------------------------------------------- +// Functions +//----------------------------------------------------------------------------- + +// Calculates the Rayleigh phase function +float getRayleighPhase( float angle ) +{ + return 0.75 * ( 1.0 + pow( angle, 2 ) ); +} + +// Returns the output rgb color given a texCoord and parameters it uses +// for lighting calculation. +float3 ComputeIllumination( float2 texCoord, + float3 vLightTS, + float3 vViewTS, + float3 vNormalTS ) +{ + //return noiseNormal; + //return vNormalTS; + + float3 vLightTSAdj = float3( -vLightTS.x, -vLightTS.y, vLightTS.z ); + + float dp = dot( vNormalTS, vLightTSAdj ); + + // Calculate the amount of illumination (lightTerm)... + + // We do both a rim lighting effect and a halfLambertian lighting effect + // and combine the result. + float halfLambertTerm = saturate( pow( dp * 0.5 + 0.5, 1 ) ); + float rimLightTerm = pow( ( 1.0 - dp ), 1.0 ); + float lightTerm = saturate( halfLambertTerm * 1.0 + rimLightTerm * dp ); + lightTerm *= 0.5; + + // Use a simple RayleighPhase function to simulate single scattering towards + // the camera. + float angle = dot( vLightTS, vViewTS ); + lightTerm *= getRayleighPhase( angle ); + + // Combine terms and colors into the output color. + //float3 lightColor = ( lightTerm * sunColor * fOcclusionShadow ) + ambientColor; + float3 lightColor = lerp( ambientColor, sunColor, lightTerm ); + //lightColor = lerp( lightColor, ambientColor, cloudCoverage ); + float3 finalColor = cloudBaseColor * lightColor; + + return finalColor; +} + +float4 main( ConnectData IN ) : TORQUE_TARGET0 +{ + // Normalize the interpolated vectors: + float3 vViewTS = normalize( IN.vViewTS ); + float3 vLightTS = normalize( IN.vLightTS ); + + float4 cResultColor = float4( 0, 0, 0, 1 ); + + float2 texSample = IN.texCoord12.xy; + + float4 noise1 = TORQUE_TEX2D( normalHeightMap, IN.texCoord12.zw ); + noise1 = normalize( ( noise1 - 0.5 ) * 2.0 ); + //return noise1; + + float4 noise2 = TORQUE_TEX2D(normalHeightMap, IN.texCoord34.xy); + noise2 = normalize( ( noise2 - 0.5 ) * 2.0 ); + //return noise2; + + float3 noiseNormal = normalize( noise1 + noise2 ).xyz; + //return float4( noiseNormal, 1.0 ); + + float noiseHeight = noise1.a * noise2.a * ( cloudCoverage / 2.0 + 0.5 ); + + float3 vNormalTS = normalize( TORQUE_TEX2D(normalHeightMap, texSample).xyz * 2.0 - 1.0); + vNormalTS += noiseNormal; + vNormalTS = normalize( vNormalTS ); + + // Compute resulting color for the pixel: + cResultColor.rgb = ComputeIllumination( texSample, vLightTS, vViewTS, vNormalTS ); + + float coverage = ( cloudCoverage - 0.5 ) * 2.0; + cResultColor.a = TORQUE_TEX2D(normalHeightMap, texSample).a + coverage + noiseHeight; + + if ( cloudCoverage > -1.0 ) + cResultColor.a /= 1.0 + coverage; + + cResultColor.a = saturate( cResultColor.a * pow( saturate(cloudCoverage), 0.25 ) ); + + cResultColor.a = lerp( cResultColor.a, 0.0, 1.0 - pow(IN.worldDist,2.0) ); + + cResultColor.rgb *= cloudExposure; + + return hdrEncode( cResultColor ); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/cloudLayerV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/cloudLayerV.hlsl new file mode 100644 index 000000000..d60dd251d --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/cloudLayerV.hlsl @@ -0,0 +1,106 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Structures +//----------------------------------------------------------------------------- +#include "shaderModel.hlsl" + +struct CloudVert +{ + float3 pos : POSITION; + float3 normal : NORMAL; + float3 binormal : BINORMAL; + float3 tangent : TANGENT; + float2 uv0 : TEXCOORD0; +}; + +struct ConnectData +{ + float4 hpos : TORQUE_POSITION; + float4 texCoord12 : TEXCOORD0; + float4 texCoord34 : TEXCOORD1; + float3 vLightTS : TEXCOORD2; // light vector in tangent space, denormalized + float3 vViewTS : TEXCOORD3; // view vector in tangent space, denormalized + float worldDist : TEXCOORD4; +}; + +//----------------------------------------------------------------------------- +// Uniforms +//----------------------------------------------------------------------------- +uniform float4x4 modelview; +uniform float3 eyePosWorld; +uniform float3 sunVec; +uniform float2 texOffset0; +uniform float2 texOffset1; +uniform float2 texOffset2; +uniform float3 texScale; + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +ConnectData main( CloudVert IN ) +{ + ConnectData OUT; + + OUT.hpos = mul(modelview, float4(IN.pos,1.0)); + // Offset the uv so we don't have a seam directly over our head. + float2 uv = IN.uv0 + float2( 0.5, 0.5 ); + + OUT.texCoord12.xy = uv * texScale.x; + OUT.texCoord12.xy += texOffset0; + + OUT.texCoord12.zw = uv * texScale.y; + OUT.texCoord12.zw += texOffset1; + + OUT.texCoord34.xy = uv * texScale.z; + OUT.texCoord34.xy += texOffset2; + + OUT.texCoord34.z = IN.pos.z; + OUT.texCoord34.w = 0.0; + + // Transform the normal, tangent and binormal vectors from object space to + // homogeneous projection space: + float3 vNormalWS = -IN.normal; + float3 vTangentWS = -IN.tangent; + float3 vBinormalWS = -IN.binormal; + + // Compute position in world space: + float4 vPositionWS = float4(IN.pos, 1.0) + float4(eyePosWorld, 1); //mul( IN.pos, objTrans ); + + // Compute and output the world view vector (unnormalized): + float3 vViewWS = eyePosWorld - vPositionWS.xyz; + + // Compute denormalized light vector in world space: + float3 vLightWS = -sunVec; + + // Normalize the light and view vectors and transform it to the tangent space: + float3x3 mWorldToTangent = float3x3( vTangentWS, vBinormalWS, vNormalWS ); + + // Propagate the view and the light vectors (in tangent space): + OUT.vLightTS = mul( vLightWS, mWorldToTangent ); + OUT.vViewTS = mul( mWorldToTangent, vViewWS ); + + OUT.worldDist = saturate( pow( max( IN.pos.z, 0 ), 2 ) ); + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/addColorTextureP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/addColorTextureP.hlsl new file mode 100644 index 000000000..d0577428f --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/addColorTextureP.hlsl @@ -0,0 +1,37 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../shaderModel.hlsl" + +struct Conn +{ + float4 HPOS : TORQUE_POSITION; + float4 color : COLOR; + float2 texCoord : TEXCOORD0; +}; + +TORQUE_UNIFORM_SAMPLER2D(diffuseMap, 0); + +float4 main( Conn IN ) : TORQUE_TARGET0 +{ + return float4(IN.color.rgb, IN.color.a * TORQUE_TEX2D(diffuseMap, IN.texCoord).a); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/addColorTextureV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/addColorTextureV.hlsl new file mode 100644 index 000000000..8bf4e88d8 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/addColorTextureV.hlsl @@ -0,0 +1,48 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../shaderModel.hlsl" + +struct Appdata +{ + float3 position : POSITION; + float4 color : COLOR; + float2 texCoord : TEXCOORD0; +}; + +struct Conn +{ + float4 HPOS : TORQUE_POSITION; + float4 color : COLOR; + float2 texCoord : TEXCOORD0; +}; + +uniform float4x4 modelview; + +Conn main( Appdata In ) +{ + Conn Out; + Out.HPOS = mul(modelview, float4(In.position,1.0)); + Out.color = In.color; + Out.texCoord = In.texCoord; + return Out; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/colorP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/colorP.hlsl new file mode 100644 index 000000000..dd9990e07 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/colorP.hlsl @@ -0,0 +1,34 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../shaderModel.hlsl" + +struct Conn +{ + float4 HPOS : TORQUE_POSITION; + float4 color : COLOR; +}; + +float4 main(Conn IN) : TORQUE_TARGET0 +{ + return IN.color; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/colorV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/colorV.hlsl new file mode 100644 index 000000000..d16dfb863 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/colorV.hlsl @@ -0,0 +1,45 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../shaderModel.hlsl" + +struct Appdata +{ + float3 position : POSITION; + float4 color : COLOR; +}; + +struct Conn +{ + float4 HPOS : TORQUE_POSITION; + float4 color : COLOR; +}; + +uniform float4x4 modelview; + +Conn main( Appdata In ) +{ + Conn Out; + Out.HPOS = mul(modelview, float4(In.position,1.0)); + Out.color = In.color; + return Out; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/addColorTextureP.glsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/addColorTextureP.glsl new file mode 100644 index 000000000..b9a10adf3 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/addColorTextureP.glsl @@ -0,0 +1,32 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +uniform sampler2D diffuseMap; +in vec4 color; +in vec2 texCoord; + +out vec4 OUT_col; + +void main() +{ + OUT_col = vec4(color.rgb, color.a * texture(diffuseMap, texCoord).a); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/addColorTextureV.glsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/addColorTextureV.glsl new file mode 100644 index 000000000..5d7f10168 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/addColorTextureV.glsl @@ -0,0 +1,38 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- +#include "../../gl/hlslCompat.glsl" + +in vec4 vPosition; +in vec4 vColor; +in vec2 vTexCoord0; + +uniform mat4 modelview; +out vec4 color; +out vec2 texCoord; + +void main() +{ + gl_Position = tMul(modelview, vPosition); + correctSSP(gl_Position); + color = vColor; + texCoord = vTexCoord0.st; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/colorP.glsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/colorP.glsl new file mode 100644 index 000000000..f9dfc3d4f --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/colorP.glsl @@ -0,0 +1,30 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +in vec4 color; + +out vec4 OUT_col; + +void main() +{ + OUT_col = color; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/colorV.glsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/colorV.glsl new file mode 100644 index 000000000..895917b55 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/colorV.glsl @@ -0,0 +1,35 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- +#include "../../gl/hlslCompat.glsl" + +in vec4 vPosition; +in vec4 vColor; + +uniform mat4 modelview; +out vec4 color; + +void main() +{ + gl_Position = tMul(modelview, vPosition); + correctSSP(gl_Position); + color = vColor; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/modColorTextureP.glsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/modColorTextureP.glsl new file mode 100644 index 000000000..c24b9db12 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/modColorTextureP.glsl @@ -0,0 +1,32 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +uniform sampler2D diffuseMap; +in vec4 color; +in vec2 texCoord; + +out vec4 OUT_col; + +void main() +{ + OUT_col = texture(diffuseMap, texCoord) * color; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/modColorTextureV.glsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/modColorTextureV.glsl new file mode 100644 index 000000000..5d7f10168 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/modColorTextureV.glsl @@ -0,0 +1,38 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- +#include "../../gl/hlslCompat.glsl" + +in vec4 vPosition; +in vec4 vColor; +in vec2 vTexCoord0; + +uniform mat4 modelview; +out vec4 color; +out vec2 texCoord; + +void main() +{ + gl_Position = tMul(modelview, vPosition); + correctSSP(gl_Position); + color = vColor; + texCoord = vTexCoord0.st; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/targetRestoreP.glsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/targetRestoreP.glsl new file mode 100644 index 000000000..770f8904d --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/targetRestoreP.glsl @@ -0,0 +1,31 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +uniform sampler2D colorTarget0Texture ; + +vec4 main( vec2 ScreenPos : VPOS ) : COLOR0 +{ + vec2 TexCoord = ScreenPos; + vec4 diffuse; + asm { tfetch2D diffuse, TexCoord, colorTarget0Texture, UnnormalizedTextureCoords = true }; + return diffuse; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/targetRestoreV.glsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/targetRestoreV.glsl new file mode 100644 index 000000000..e99d2e537 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/targetRestoreV.glsl @@ -0,0 +1,22 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/textureP.glsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/textureP.glsl new file mode 100644 index 000000000..50cef4bda --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/textureP.glsl @@ -0,0 +1,31 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +uniform sampler2D diffuseMap; +in vec2 texCoord; + +out vec4 OUT_col; + +void main() +{ + OUT_col = texture(diffuseMap, texCoord); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/textureV.glsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/textureV.glsl new file mode 100644 index 000000000..20dbb6f10 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/textureV.glsl @@ -0,0 +1,35 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- +#include "../../gl/hlslCompat.glsl" + +in vec4 vPosition; +in vec2 vTexCoord0; + +uniform mat4 modelview; +out vec2 texCoord; + +void main() +{ + gl_Position = tMul(modelview, vPosition); + correctSSP(gl_Position); + texCoord = vTexCoord0.st; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/modColorTextureP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/modColorTextureP.hlsl new file mode 100644 index 000000000..63afec2a4 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/modColorTextureP.hlsl @@ -0,0 +1,37 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../shaderModel.hlsl" + +struct Conn +{ + float4 HPOS : TORQUE_POSITION; + float4 color : COLOR; + float2 texCoord : TEXCOORD0; +}; + +TORQUE_UNIFORM_SAMPLER2D(diffuseMap, 0); + +float4 main( Conn IN ) : TORQUE_TARGET0 +{ + return TORQUE_TEX2D(diffuseMap, IN.texCoord) * IN.color; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/modColorTextureV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/modColorTextureV.hlsl new file mode 100644 index 000000000..8bf4e88d8 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/modColorTextureV.hlsl @@ -0,0 +1,48 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../shaderModel.hlsl" + +struct Appdata +{ + float3 position : POSITION; + float4 color : COLOR; + float2 texCoord : TEXCOORD0; +}; + +struct Conn +{ + float4 HPOS : TORQUE_POSITION; + float4 color : COLOR; + float2 texCoord : TEXCOORD0; +}; + +uniform float4x4 modelview; + +Conn main( Appdata In ) +{ + Conn Out; + Out.HPOS = mul(modelview, float4(In.position,1.0)); + Out.color = In.color; + Out.texCoord = In.texCoord; + return Out; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/targetRestoreP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/targetRestoreP.hlsl new file mode 100644 index 000000000..9ef44f426 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/targetRestoreP.hlsl @@ -0,0 +1,31 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +uniform sampler2D colorTarget0Texture : register(s0); + +float4 main( float2 ScreenPos : VPOS ) : COLOR0 +{ + float2 TexCoord = ScreenPos; + float4 diffuse; + asm { tfetch2D diffuse, TexCoord, colorTarget0Texture, UnnormalizedTextureCoords = true }; + return diffuse; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/targetRestoreV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/targetRestoreV.hlsl new file mode 100644 index 000000000..3c4aefaec --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/targetRestoreV.hlsl @@ -0,0 +1,26 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +float4 main( const float2 inPosition : POSITION ) : POSITION +{ + return float4( inPosition, 0, 1 ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/textureP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/textureP.hlsl new file mode 100644 index 000000000..82dbd4ce9 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/textureP.hlsl @@ -0,0 +1,36 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../shaderModel.hlsl" + +TORQUE_UNIFORM_SAMPLER2D(diffuseMap, 0); + +struct Conn +{ + float4 hpos : TORQUE_POSITION; + float2 texCoord : TEXCOORD0; +}; + +float4 main(Conn IN) : TORQUE_TARGET0 +{ + return TORQUE_TEX2D(diffuseMap, IN.texCoord); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/textureV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/textureV.hlsl new file mode 100644 index 000000000..204cf9514 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/textureV.hlsl @@ -0,0 +1,46 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../shaderModel.hlsl" + +struct Appdata +{ + float3 position : POSITION; + float4 color : COLOR; + float2 texCoord : TEXCOORD0; +}; + +struct Conn +{ + float4 hpos : TORQUE_POSITION; + float2 texCoord : TEXCOORD0; +}; + +uniform float4x4 modelview; + +Conn main( Appdata In ) +{ + Conn Out; + Out.hpos = mul(modelview, float4(In.position, 1.0)); + Out.texCoord = In.texCoord; + return Out; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/foliage.hlsl b/Templates/BaseGame/game/core/rendering/shaders/foliage.hlsl new file mode 100644 index 000000000..9952c29d6 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/foliage.hlsl @@ -0,0 +1,186 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// CornerId corresponds to this arrangement +// from the perspective of the camera. +// +// 3 ---- 2 +// | | +// 0 ---- 1 +// + +#define MAX_COVERTYPES 8 + +uniform float2 gc_fadeParams; +uniform float2 gc_windDir; +uniform float3 gc_camRight; +uniform float3 gc_camUp; +uniform float4 gc_typeRects[MAX_COVERTYPES]; + +// .x = gust length +// .y = premultiplied simulation time and gust frequency +// .z = gust strength +uniform float3 gc_gustInfo; + +// .x = premultiplied simulation time and turbulance frequency +// .y = turbulance strength +uniform float2 gc_turbInfo; + + +static float sCornerRight[4] = { -0.5, 0.5, 0.5, -0.5 }; + +static float sCornerUp[4] = { 0, 0, 1, 1 }; + +static float sMovableCorner[4] = { 0, 0, 1, 1 }; + +static float2 sUVCornerExtent[4] = +{ + float2( 0, 1 ), + float2( 1, 1 ), + float2( 1, 0 ), + float2( 0, 0 ) +}; + + +/////////////////////////////////////////////////////////////////////////////// +// The following wind effect was derived from the GPU Gems 3 chapter... +// +// "Vegetation Procedural Animation and Shading in Crysis" +// by Tiago Sousa, Crytek +// + +float2 smoothCurve( float2 x ) +{ + return x * x * ( 3.0 - 2.0 * x ); +} + +float2 triangleWave( float2 x ) +{ + return abs( frac( x + 0.5 ) * 2.0 - 1.0 ); +} + +float2 smoothTriangleWave( float2 x ) +{ + return smoothCurve( triangleWave( x ) ); +} + +float windTurbulence( float bbPhase, float frequency, float strength ) +{ + // We create the input value for wave generation from the frequency and phase. + float2 waveIn = bbPhase.xx + frequency.xx; + + // We use two square waves to generate the effect which + // is then scaled by the overall strength. + float2 waves = ( frac( waveIn.xy * float2( 1.975, 0.793 ) ) * 2.0 - 1.0 ); + waves = smoothTriangleWave( waves ); + + // Sum up the two waves into a single wave. + return ( waves.x + waves.y ) * strength; +} + +float2 windEffect( float bbPhase, + float2 windDirection, + float gustLength, + float gustFrequency, + float gustStrength, + float turbFrequency, + float turbStrength ) +{ + // Calculate the ambient wind turbulence. + float turbulence = windTurbulence( bbPhase, turbFrequency, turbStrength ); + + // We simulate the overall gust via a sine wave. + float gustPhase = clamp( sin( ( bbPhase - gustFrequency ) / gustLength ) , 0, 1 ); + float gustOffset = ( gustPhase * gustStrength ) + ( ( 0.2 + gustPhase ) * turbulence ); + + // Return the final directional wind effect. + return gustOffset.xx * windDirection.xy; +} + +void foliageProcessVert( inout float3 position, + inout float4 diffuse, + inout float4 texCoord, + inout float3 normal, + inout float3 T, + in float3 eyePos ) +{ + // Assign the normal and tagent values. + //normal = float3( 0, 0, 1 );//cross( gc_camUp, gc_camRight ); + T = gc_camRight; + + // Pull out local vars we need for work. + int corner = ( diffuse.a * 255.0f ) + 0.5f; + float2 size = texCoord.xy; + int type = texCoord.z; + + // The billboarding is based on the camera direction. + float3 rightVec = gc_camRight * sCornerRight[corner]; + float3 upVec = gc_camUp * sCornerUp[corner]; + + // Figure out the corner position. + float3 outPos = ( upVec * size.y ) + ( rightVec * size.x ); + float len = length( outPos.xyz ); + + // We derive the billboard phase used for wind calculations from its position. + float bbPhase = dot( position.xyz, 1 ); + + // Get the overall wind gust and turbulence effects. + float3 wind; + wind.xy = windEffect( bbPhase, + gc_windDir, + gc_gustInfo.x, gc_gustInfo.y, gc_gustInfo.z, + gc_turbInfo.x, gc_turbInfo.y ); + wind.z = 0; + + // Add the summed wind effect into the point. + outPos.xyz += wind.xyz * texCoord.w; + + // Do a simple spherical clamp to keep the foliage + // from stretching too much by wind effect. + outPos.xyz = normalize( outPos.xyz ) * len; + + // Move the point into world space. + position += outPos; + + // Grab the uv set and setup the texture coord. + float4 uvSet = gc_typeRects[type]; + texCoord.x = uvSet.x + ( uvSet.z * sUVCornerExtent[corner].x ); + texCoord.y = uvSet.y + ( uvSet.w * sUVCornerExtent[corner].y ); + + // Animate the normal to get lighting changes + // across the the wind swept foliage. + // + // TODO: Expose the 10x as a factor to control + // how much the wind effects the lighting on the grass. + // + normal.xy += wind.xy * ( 10.0 * texCoord.w ); + normal = normalize( normal ); + + // Get the alpha fade value. + + float fadeStart = gc_fadeParams.x; + float fadeEnd = gc_fadeParams.y; + const float fadeRange = fadeEnd - fadeStart; + + float dist = distance( eyePos, position.xyz ) - fadeStart; + diffuse.a = 1 - clamp( dist / fadeRange, 0, 1 ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/fxFoliageReplicatorP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/fxFoliageReplicatorP.hlsl new file mode 100644 index 000000000..a8bb68e28 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fxFoliageReplicatorP.hlsl @@ -0,0 +1,60 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "shdrConsts.h" +#include "shaderModel.hlsl" +//----------------------------------------------------------------------------- +// Structures +//----------------------------------------------------------------------------- +struct ConnectData +{ + float4 hpos : TORQUE_POSITION; + float2 outTexCoord : TEXCOORD0; + float4 color : COLOR0; + float4 groundAlphaCoeff : COLOR1; + float2 alphaLookup : TEXCOORD1; +}; + +struct Fragout +{ + float4 col : TORQUE_TARGET0; +}; + +TORQUE_UNIFORM_SAMPLER2D(diffuseMap, 0); +TORQUE_UNIFORM_SAMPLER2D(alphaMap, 1); + +uniform float4 groundAlpha; +uniform float4 ambient; + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +Fragout main( ConnectData IN ) +{ + Fragout OUT; + + float4 alpha = TORQUE_TEX2D(alphaMap, IN.alphaLookup); + OUT.col = float4( ambient.rgb * IN.lum.rgb, 1.0 ) * TORQUE_TEX2D(diffuseMap, IN.texCoord); + OUT.col.a = OUT.col.a * min(alpha, groundAlpha + IN.groundAlphaCoeff.x).x; + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/fxFoliageReplicatorV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/fxFoliageReplicatorV.hlsl new file mode 100644 index 000000000..70ec9ff4c --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/fxFoliageReplicatorV.hlsl @@ -0,0 +1,129 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Structures +//----------------------------------------------------------------------------- + +#include "shaderModel.hlsl" + +struct VertData +{ + float3 position : POSITION; + float3 normal : NORMAL; + float2 texCoord : TEXCOORD0; + float2 waveScale : TEXCOORD1; +}; + +struct ConnectData +{ + float4 hpos : TORQUE_POSITION; + float2 outTexCoord : TEXCOORD0; + float4 color : COLOR0; + float4 groundAlphaCoeff : COLOR1; + float2 alphaLookup : TEXCOORD1; +}; + +uniform float4x4 projection : register(C0); +uniform float4x4 world : register(C4); +uniform float GlobalSwayPhase : register(C8); +uniform float SwayMagnitudeSide : register(C9); +uniform float SwayMagnitudeFront : register(C10); +uniform float GlobalLightPhase : register(C11); +uniform float LuminanceMagnitude : register(C12); +uniform float LuminanceMidpoint : register(C13); +uniform float DistanceRange : register(C14); +uniform float3 CameraPos : register(C15); +uniform float TrueBillboard : register(C16); + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +ConnectData main( VertData IN ) +{ + ConnectData OUT; + + // Init a transform matrix to be used in the following steps + float4x4 trans = 0; + trans[0][0] = 1; + trans[1][1] = 1; + trans[2][2] = 1; + trans[3][3] = 1; + trans[0][3] = IN.position.x; + trans[1][3] = IN.position.y; + trans[2][3] = IN.position.z; + + // Billboard transform * world matrix + float4x4 o = world; + o = mul(o, trans); + + // Keep only the up axis result and position transform. + // This gives us "cheating" cylindrical billboarding. + o[0][0] = 1; + o[1][0] = 0; + o[2][0] = 0; + o[3][0] = 0; + o[0][1] = 0; + o[1][1] = 1; + o[2][1] = 0; + o[3][1] = 0; + + // Unless the user specified TrueBillboard, + // in which case we want the z axis to also be camera facing. + +#ifdef TRUE_BILLBOARD + + o[0][2] = 0; + o[1][2] = 0; + o[2][2] = 1; + o[3][2] = 0; + +#endif + + // Handle sway. Sway is stored in a texture coord. The x coordinate is the sway phase multiplier, + // the y coordinate determines if this vertex actually sways or not. + float xSway, ySway; + float wavePhase = GlobalSwayPhase * IN.waveScale.x; + sincos(wavePhase, ySway, xSway); + xSway = xSway * IN.waveScale.y * SwayMagnitudeSide; + ySway = ySway * IN.waveScale.y * SwayMagnitudeFront; + float4 p; + p = mul(o, float4(IN.normal.x + xSway, ySway, IN.normal.z, 1)); + + // Project the point + OUT.hpos = mul(projection, p); + + // Lighting + float Luminance = LuminanceMidpoint + LuminanceMagnitude * cos(GlobalLightPhase + IN.normal.y); + + // Alpha + float3 worldPos = IN.position; + float alpha = abs(distance(worldPos, CameraPos)) / DistanceRange; + alpha = clamp(alpha, 0.0f, 1.0f); //pass it through + + OUT.alphaLookup = float2(alpha, 0.0f); + OUT.groundAlphaCoeff = all(IN.normal.z); + OUT.outTexCoord = IN.texCoord; + OUT.color = float4(Luminance, Luminance, Luminance, 1.0f); + + return OUT; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/basicCloudsP.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/basicCloudsP.glsl new file mode 100644 index 000000000..5b3f50519 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/basicCloudsP.glsl @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "torque.glsl" +#include "hlslCompat.glsl" + +//ConnectData +in vec2 texCoord; +#define IN_texCoord texCoord + + +uniform sampler2D diffuseMap ; + +out vec4 OUT_col; + +void main() +{ + vec4 col = texture( diffuseMap, IN_texCoord ); + OUT_col = hdrEncode( col ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/basicCloudsV.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/basicCloudsV.glsl new file mode 100644 index 000000000..cccbafa8c --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/basicCloudsV.glsl @@ -0,0 +1,53 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "hlslCompat.glsl" + +//CloudVert +in vec4 vPosition; +in vec2 vTexCoord0; + +#define IN_pos vPosition +#define IN_uv0 vTexCoord0 + +uniform mat4 modelview; +uniform float accumTime; +uniform float texScale; +uniform vec2 texDirection; +uniform vec2 texOffset; + +out vec2 texCoord; +#define OUT_texCoord texCoord + +void main() +{ + gl_Position = tMul(modelview, IN_pos); + + vec2 uv = IN_uv0; + uv += texOffset; + uv *= texScale; + uv += accumTime * texDirection; + + OUT_texCoord = uv; + + correctSSP(gl_Position); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/blurP.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/blurP.glsl new file mode 100644 index 000000000..a27538762 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/blurP.glsl @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//***************************************************************************** +// Glow Shader +//***************************************************************************** +uniform vec4 kernel; +uniform sampler2D diffuseMap; + +in vec2 texc0, texc1, texc2, texc3; + +out vec4 OUT_col; + +void main() +{ + OUT_col = texture(diffuseMap, texc0) * kernel.x; + OUT_col += texture(diffuseMap, texc1) * kernel.y; + OUT_col += texture(diffuseMap, texc2) * kernel.z; + OUT_col += texture(diffuseMap, texc3) * kernel.w; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/blurV.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/blurV.glsl new file mode 100644 index 000000000..1bfb0cd1b --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/blurV.glsl @@ -0,0 +1,48 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//***************************************************************************** +// Glow shader +//***************************************************************************** + +in vec4 vPosition; +in vec4 vColor; +in vec2 vTexCoord0; + +uniform mat4 modelview; +uniform vec2 offset0, offset1, offset2, offset3; + +out vec2 texc0, texc1, texc2, texc3; + +void main() +{ + gl_Position = modelview * vPosition; + + vec2 tc = vTexCoord0.st; + tc.y = 1.0 - tc.y; + + texc0 = tc + offset0; + texc1 = tc + offset1; + texc2 = tc + offset2; + texc3 = tc + offset3; + gl_Position.y *= -1; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/cloudLayerP.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/cloudLayerP.glsl new file mode 100644 index 000000000..877a132da --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/cloudLayerP.glsl @@ -0,0 +1,147 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "hlslCompat.glsl" +#include "torque.glsl" +//----------------------------------------------------------------------------- +// Structures +//----------------------------------------------------------------------------- +//ConnectData +in vec4 texCoord12; +#define IN_texCoord12 texCoord12 +in vec4 texCoord34; +#define IN_texCoord34 texCoord34 +in vec3 vLightTS; // light vector in tangent space, denormalized +#define IN_vLightTS vLightTS +in vec3 vViewTS; // view vector in tangent space, denormalized +#define IN_vViewTS vViewTS +in float worldDist; +#define IN_worldDist worldDist + +//----------------------------------------------------------------------------- +// Uniforms +//----------------------------------------------------------------------------- +uniform sampler2D normalHeightMap; +uniform vec3 ambientColor; +uniform vec3 sunColor; +uniform float cloudCoverage; +uniform vec3 cloudBaseColor; +uniform float cloudExposure; + +out vec4 OUT_col; + +//----------------------------------------------------------------------------- +// Globals +//----------------------------------------------------------------------------- +// The per-color weighting to be used for luminance calculations in RGB order. +const vec3 LUMINANCE_VECTOR = vec3(0.2125f, 0.7154f, 0.0721f); + + +//----------------------------------------------------------------------------- +// Functions +//----------------------------------------------------------------------------- + +// Calculates the Rayleigh phase function +float getRayleighPhase( float angle ) +{ + return 0.75 * ( 1.0 + pow( angle, 2.0 ) ); +} + +// Returns the output rgb color given a texCoord and parameters it uses +// for lighting calculation. +vec3 ComputeIllumination( vec2 texCoord, + vec3 vLightTS, + vec3 vViewTS, + vec3 vNormalTS ) +{ + //return noiseNormal; + //return vNormalTS; + + vec3 vLightTSAdj = vec3( -vLightTS.x, -vLightTS.y, vLightTS.z ); + + float dp = dot( vNormalTS, vLightTSAdj ); + + // Calculate the amount of illumination (lightTerm)... + + // We do both a rim lighting effect and a halfLambertian lighting effect + // and combine the result. + float halfLambertTerm = clamp( pow( dp * 0.5 + 0.5, 1.0 ), 0.0, 1.0 ); + float rimLightTerm = pow( ( 1.0 - dp ), 1.0 ); + float lightTerm = clamp( halfLambertTerm * 1.0 + rimLightTerm * dp, 0.0, 1.0 ); + lightTerm *= 0.5; + + // Use a simple RayleighPhase function to simulate single scattering towards + // the camera. + float angle = dot( vLightTS, vViewTS ); + lightTerm *= getRayleighPhase( angle ); + + // Combine terms and colors into the output color. + //vec3 lightColor = ( lightTerm * sunColor * fOcclusionShadow ) + ambientColor; + vec3 lightColor = mix( ambientColor, sunColor, lightTerm ); + //lightColor = mix( lightColor, ambientColor, cloudCoverage ); + vec3 finalColor = cloudBaseColor * lightColor; + + return finalColor; +} + +void main() +{ + // Normalize the interpolated vectors: + vec3 vViewTS = normalize( vViewTS ); + vec3 vLightTS = normalize( vLightTS ); + + vec4 cResultColor = vec4( 0, 0, 0, 1 ); + + vec2 texSample = IN_texCoord12.xy; + + vec4 noise1 = texture( normalHeightMap, IN_texCoord12.zw ); + noise1 = normalize( ( noise1 - 0.5 ) * 2.0 ); + //return noise1; + + vec4 noise2 = texture( normalHeightMap, IN_texCoord34.xy ); + noise2 = normalize( ( noise2 - 0.5 ) * 2.0 ); + //return noise2; + + vec3 noiseNormal = normalize( noise1 + noise2 ).xyz; + //return vec4( noiseNormal, 1.0 ); + + float noiseHeight = noise1.a * noise2.a * ( cloudCoverage / 2.0 + 0.5 ); + + vec3 vNormalTS = normalize( texture( normalHeightMap, texSample ).xyz * 2.0 - 1.0 ); + vNormalTS += noiseNormal; + vNormalTS = normalize( vNormalTS ); + + // Compute resulting color for the pixel: + cResultColor.rgb = ComputeIllumination( texSample, vLightTS, vViewTS, vNormalTS ); + + float coverage = ( cloudCoverage - 0.5 ) * 2.0; + cResultColor.a = texture( normalHeightMap, texSample ).a + coverage + noiseHeight; + + if ( cloudCoverage > -1.0 ) + cResultColor.a /= 1.0 + coverage; + + cResultColor.a = clamp( cResultColor.a * pow( saturate(cloudCoverage), 0.25 ), 0.0, 1.0 ); + + cResultColor.a = mix( cResultColor.a, 0.0, 1.0 - pow(IN_worldDist,2.0) ); + + OUT_col = hdrEncode(cResultColor); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/cloudLayerV.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/cloudLayerV.glsl new file mode 100644 index 000000000..395c6f286 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/cloudLayerV.glsl @@ -0,0 +1,106 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "hlslCompat.glsl" + +in vec4 vPosition; +in vec3 vNormal; +in vec3 vBinormal; +in vec3 vTangent; +in vec2 vTexCoord0; + +out vec4 texCoord12; +#define OUT_texCoord12 texCoord12 +out vec4 texCoord34; +#define OUT_texCoord34 texCoord34 +out vec3 vLightTS; // light vector in tangent space, denormalized +#define OUT_vLightTS vLightTS +out vec3 vViewTS; // view vector in tangent space, denormalized +#define OUT_vViewTS vViewTS +out float worldDist; +#define OUT_worldDist worldDist + +//----------------------------------------------------------------------------- +// Uniforms +//----------------------------------------------------------------------------- +uniform mat4 modelview; +uniform vec3 eyePosWorld; +uniform vec3 sunVec; +uniform vec2 texOffset0; +uniform vec2 texOffset1; +uniform vec2 texOffset2; +uniform vec3 texScale; + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +void main() +{ + vec4 IN_pos = vPosition; + vec3 IN_normal = vNormal; + vec3 IN_binormal = vBinormal; + vec3 IN_tangent = vTangent; + vec2 IN_uv0 = vTexCoord0.st; + + gl_Position = modelview * IN_pos; + + // Offset the uv so we don't have a seam directly over our head. + vec2 uv = IN_uv0 + vec2( 0.5, 0.5 ); + + OUT_texCoord12.xy = uv * texScale.x; + OUT_texCoord12.xy += texOffset0; + + OUT_texCoord12.zw = uv * texScale.y; + OUT_texCoord12.zw += texOffset1; + + OUT_texCoord34.xy = uv * texScale.z; + OUT_texCoord34.xy += texOffset2; + + OUT_texCoord34.z = IN_pos.z; + OUT_texCoord34.w = 0.0; + + // Transform the normal, tangent and binormal vectors from object space to + // homogeneous projection space: + vec3 vNormalWS = -IN_normal; + vec3 vTangentWS = -IN_tangent; + vec3 vBinormalWS = -IN_binormal; + + // Compute position in world space: + vec4 vPositionWS = IN_pos + vec4( eyePosWorld, 1 ); //tMul( IN_pos, objTrans ); + + // Compute and output the world view vector (unnormalized): + vec3 vViewWS = eyePosWorld - vPositionWS.xyz; + + // Compute denormalized light vector in world space: + vec3 vLightWS = -sunVec; + + // Normalize the light and view vectors and transform it to the IN_tangent space: + mat3 mWorldToTangent = mat3( vTangentWS, vBinormalWS, vNormalWS ); + + // Propagate the view and the light vectors (in tangent space): + OUT_vLightTS = vLightWS * mWorldToTangent; + OUT_vViewTS = mWorldToTangent * vViewWS; + + OUT_worldDist = clamp( pow( max( IN_pos.z, 0 ), 2 ), 0.0, 1.0 ); + + correctSSP(gl_Position); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/foliage.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/foliage.glsl new file mode 100644 index 000000000..38b66e767 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/foliage.glsl @@ -0,0 +1,186 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// CornerId corresponds to this arrangement +// from the perspective of the camera. +// +// 3 ---- 2 +// | | +// 0 ---- 1 +// + +#define MAX_COVERTYPES 8 + +uniform vec3 gc_camRight; +uniform vec3 gc_camUp; +uniform vec4 gc_typeRects[MAX_COVERTYPES]; +uniform vec2 gc_fadeParams; +uniform vec2 gc_windDir; + +// .x = gust length +// .y = premultiplied simulation time and gust frequency +// .z = gust strength +uniform vec3 gc_gustInfo; + +// .x = premultiplied simulation time and turbulance frequency +// .y = turbulance strength +uniform vec2 gc_turbInfo; + + +const float sCornerRight[4] = float[]( -0.5, 0.5, 0.5, -0.5 ); + +const float sCornerUp[4] = float[]( 0, 0, 1, 1 ); + +const float sMovableCorner[4] = float[]( 0, 0, 1, 1 ); + +const vec2 sUVCornerExtent[4] = vec2[] +( + vec2( 0, 1 ), + vec2( 1, 1 ), + vec2( 1, 0 ), + vec2( 0, 0 ) +); + + +/////////////////////////////////////////////////////////////////////////////// +// The following wind effect was derived from the GPU Gems 3 chapter... +// +// "Vegetation Procedural Animation and Shading in Crysis" +// by Tiago Sousa, Crytek +// + +vec2 smoothCurve( vec2 x ) +{ + return x * x * ( 3.0 - 2.0 * x ); +} + +vec2 triangleWave( vec2 x ) +{ + return abs( fract( x + 0.5 ) * 2.0 - 1.0 ); +} + +vec2 smoothTriangleWave( vec2 x ) +{ + return smoothCurve( triangleWave( x ) ); +} + +float windTurbulence( float bbPhase, float frequency, float strength ) +{ + // We create the input value for wave generation from the frequency and phase. + vec2 waveIn = vec2( bbPhase + frequency ); + + // We use two square waves to generate the effect which + // is then scaled by the overall strength. + vec2 waves = ( fract( waveIn.xy * vec2( 1.975, 0.793 ) ) * 2.0 - 1.0 ); + waves = smoothTriangleWave( waves ); + + // Sum up the two waves into a single wave. + return ( waves.x + waves.y ) * strength; +} + +vec2 windEffect( float bbPhase, + vec2 windDirection, + float gustLength, + float gustFrequency, + float gustStrength, + float turbFrequency, + float turbStrength ) +{ + // Calculate the ambient wind turbulence. + float turbulence = windTurbulence( bbPhase, turbFrequency, turbStrength ); + + // We simulate the overall gust via a sine wave. + float gustPhase = clamp( sin( ( bbPhase - gustFrequency ) / gustLength ) , 0.0, 1.0 ); + float gustOffset = ( gustPhase * gustStrength ) + ( ( 0.2 + gustPhase ) * turbulence ); + + // Return the final directional wind effect. + return vec2(gustOffset) * windDirection.xy; +} + +void foliageProcessVert( inout vec3 position, + inout vec4 diffuse, + inout vec4 texCoord, + inout vec3 normal, + inout vec3 T, + in vec3 eyePos ) +{ + // Assign the normal and tagent values. + //normal = vec3( 0, 0, 1 );//cross( gc_camUp, gc_camRight ); + T = gc_camRight; + + // Pull out local vars we need for work. + int corner = int( ( diffuse.a * 255.0 ) + 0.5 ); + vec2 size = texCoord.xy; + int type = int( texCoord.z ); + + // The billboarding is based on the camera direction. + vec3 rightVec = gc_camRight * sCornerRight[corner]; + vec3 upVec = gc_camUp * sCornerUp[corner]; + + // Figure out the corner position. + vec3 outPos = ( upVec * size.y ) + ( rightVec * size.x ); + float len = length( outPos.xyz ); + + // We derive the billboard phase used for wind calculations from its position. + float bbPhase = dot( position.xyz, vec3( 1.0 ) ); + + // Get the overall wind gust and turbulence effects. + vec3 wind; + wind.xy = windEffect( bbPhase, + gc_windDir, + gc_gustInfo.x, gc_gustInfo.y, gc_gustInfo.z, + gc_turbInfo.x, gc_turbInfo.y ); + wind.z = 0.0; + + // Add the summed wind effect into the point. + outPos.xyz += wind.xyz * texCoord.w; + + // Do a simple spherical clamp to keep the foliage + // from stretching too much by wind effect. + outPos.xyz = normalize( outPos.xyz ) * len; + + // Move the point into world space. + position += outPos; + + // Grab the uv set and setup the texture coord. + vec4 uvSet = gc_typeRects[type]; + texCoord.x = uvSet.x + ( uvSet.z * sUVCornerExtent[corner].x ); + texCoord.y = uvSet.y + ( uvSet.w * sUVCornerExtent[corner].y ); + + // Animate the normal to get lighting changes + // across the the wind swept foliage. + // + // TODO: Expose the 10x as a factor to control + // how much the wind effects the lighting on the grass. + // + normal.xy += wind.xy * ( 10.0 * texCoord.w ); + normal = normalize( normal ); + + // Get the alpha fade value. + + float fadeStart = gc_fadeParams.x; + float fadeEnd = gc_fadeParams.y; + float fadeRange = fadeEnd - fadeStart; + + float dist = distance( eyePos, position.xyz ) - fadeStart; + diffuse.a = 1.0 - clamp( dist / fadeRange, 0.0, 1.0 ); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/fxFoliageReplicatorP.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/fxFoliageReplicatorP.glsl new file mode 100644 index 000000000..b4d591486 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/fxFoliageReplicatorP.glsl @@ -0,0 +1,42 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Data +//----------------------------------------------------------------------------- +uniform sampler2D diffuseMap, alphaMap; +uniform vec4 groundAlpha; + +in vec4 color, groundAlphaCoeff; +in vec2 outTexCoord, alphaLookup; + +out vec4 OUT_col; + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +void main() +{ + vec4 alpha = texture(alphaMap, alphaLookup); + OUT_col = color * texture(diffuseMap, outTexCoord); + OUT_col.a = OUT_col.a * min(alpha, groundAlpha + groundAlphaCoeff.x).x; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/fxFoliageReplicatorV.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/fxFoliageReplicatorV.glsl new file mode 100644 index 000000000..c8dcf1ddb --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/fxFoliageReplicatorV.glsl @@ -0,0 +1,99 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Data +//----------------------------------------------------------------------------- +in vec4 vPosition; +in vec3 vNormal; +in vec4 vColor; +in vec2 vTexCoord0; +in vec2 vTexCoord1; +in vec2 vTexCoord2; + +uniform mat4 projection, world; +uniform vec3 CameraPos; +uniform float GlobalSwayPhase, SwayMagnitudeSide, SwayMagnitudeFront, + GlobalLightPhase, LuminanceMagnitude, LuminanceMidpoint, DistanceRange; + +out vec4 color, groundAlphaCoeff; +out vec2 outTexCoord, alphaLookup; + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +void main() +{ + // Init a transform matrix to be used in the following steps + mat4 trans = mat4(0.0); + trans[0][0] = 1.0; + trans[1][1] = 1.0; + trans[2][2] = 1.0; + trans[3][3] = 1.0; + trans[3][0] = vPosition.x; + trans[3][1] = vPosition.y; + trans[3][2] = vPosition.z; + + // Billboard transform * world matrix + mat4 o = world; + o = o * trans; + + // Keep only the up axis result and position transform. + // This gives us "cheating" cylindrical billboarding. + o[0][0] = 1.0; + o[0][1] = 0.0; + o[0][2] = 0.0; + o[0][3] = 0.0; + o[1][0] = 0.0; + o[1][1] = 1.0; + o[1][2] = 0.0; + o[1][3] = 0.0; + + // Handle sway. Sway is stored in a texture coord. The x coordinate is the sway phase multiplier, + // the y coordinate determines if this vertex actually sways or not. + float xSway, ySway; + float wavePhase = GlobalSwayPhase * vTexCoord1.x; + ySway = sin(wavePhase); + xSway = cos(wavePhase); + xSway = xSway * vTexCoord1.y * SwayMagnitudeSide; + ySway = ySway * vTexCoord1.y * SwayMagnitudeFront; + vec4 p; + p = o * vec4(vNormal.x + xSway, ySway, vNormal.z, 1.0); + + // Project the point + gl_Position = projection * p; + + // Lighting + float Luminance = LuminanceMidpoint + LuminanceMagnitude * cos(GlobalLightPhase + vNormal.y); + + // Alpha + vec3 worldPos = vec3(vPosition.x, vPosition.y, vPosition.z); + float alpha = abs(distance(worldPos, CameraPos)) / DistanceRange; + alpha = clamp(alpha, 0.0, 1.0); //pass it through + + alphaLookup = vec2(alpha, 0.0); + bool alphaCoeff = bool(vNormal.z); + groundAlphaCoeff = vec4(float(alphaCoeff)); + outTexCoord = vTexCoord0.st; + color = vec4(Luminance, Luminance, Luminance, 1.0); + gl_Position.y *= -1; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/guiMaterialV.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/guiMaterialV.glsl new file mode 100644 index 000000000..de3845ee7 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/guiMaterialV.glsl @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +in vec4 vPosition; +in vec2 vTexCoord0; + +uniform mat4x4 modelview; + +out vec4 hpos; +out vec2 uv0; + + +void main() +{ + hpos = vec4( modelview * vPosition ); + gl_Position = hpos; + + uv0 = vTexCoord0.st; + gl_Position.y *= -1; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/hlslCompat.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/hlslCompat.glsl new file mode 100644 index 000000000..b9a6e76d7 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/hlslCompat.glsl @@ -0,0 +1,101 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// These are some simple wrappers for simple +// HLSL compatibility. + +#define float4 vec4 +#define float3 vec3 +#define float2 vec2 + +#define half float +#define half2 vec2 +#define half3 vec3 +#define half4 vec4 + +#define float4x4 mat4 +#define float3x3 mat3 +#define float2x2 mat2 + +#define texCUBE texture +#define tex2D texture +#define tex1D texture +#define tex2Dproj textureProj +#define tex2Dlod( sampler, texCoord ) textureLod(sampler, texCoord.xy, texCoord.w) + +#define samplerCUBE samplerCube + +#define frac fract + +#define lerp mix + +void tSetMatrixRow(inout float3x3 m, int row, float3 value) +{ + m[0][row] = value.x; + m[1][row] = value.y; + m[2][row] = value.z; +} + +void tSetMatrixRow(inout float4x4 m, int row, float4 value) +{ + m[0][row] = value.x; + m[1][row] = value.y; + m[2][row] = value.z; + m[3][row] = value.w; +} + +#define tGetMatrix3Row(matrix, row) float3(matrix[0][row], matrix[1][row], matrix[2][row]) +#define tGetMatrix4Row(matrix, row) float4(matrix[0][row], matrix[1][row], matrix[2][row], matrix[3][row]) + +float3x3 float4x4to3x3(float4x4 m) +{ + return float3x3( vec3(m[0]).xyz, m[1].xyz, m[2].xyz); +} + +float3x3 float4x4to3x3_(float4x4 m) +{ + return float3x3( vec3(m[0]), m[1].xyz, m[2].xyz); +} + +mat4 mat4FromRow( float r0c0, float r0c1, float r0c2, float r0c3, + float r1c0, float r1c1, float r1c2, float r1c3, + float r2c0, float r2c1, float r2c2, float r2c3, + float r3c0, float r3c1, float r3c2, float r3c3 ) +{ + return mat4( r0c0, r1c0, r2c0, r3c0, + r0c1, r1c1, r2c1, r3c1, + r0c2, r1c2, r2c2, r3c2, + r0c3, r1c3, r2c3, r3c3 ); +} + + +#define saturate( val ) clamp( val, 0.0, 1.0 ) + +#define round( n ) (sign( n ) * floor( abs( n ) + 0.5 )) + +#define tMul(a, b) (a*b) + +#define correctSSP(vec) vec.y *= -1 + +#ifdef TORQUE_PIXEL_SHADER + void clip(float a) { if(a < 0) discard;} +#endif diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/imposter.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/imposter.glsl new file mode 100644 index 000000000..20bc62688 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/imposter.glsl @@ -0,0 +1,161 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "torque.glsl" + + +#define IMPOSTER_MAX_UVS 64 + + +void imposter_v( + // These parameters usually come from the vertex. + vec3 center, + int corner, + float halfSize, + vec3 imposterUp, + vec3 imposterRight, + + // These are from the imposter shader constant. + int numEquatorSteps, + int numPolarSteps, + float polarAngle, + bool includePoles, + + // Other shader constants. + vec3 camPos, + vec4 uvs[IMPOSTER_MAX_UVS], + + // The outputs of this function. + out vec3 outWsPosition, + out vec2 outTexCoord, + out mat3 outWorldToTangent + ) +{ + + float M_HALFPI_F = 1.57079632679489661923; + float M_PI_F = 3.14159265358979323846; + float M_2PI_F = 6.28318530717958647692; + + + float sCornerRight[4];// = float[]( -1.0, 1.0, 1.0, -1.0 ); + sCornerRight[0] = -1.0; + sCornerRight[1] = 1.0; + sCornerRight[2] = 1.0; + sCornerRight[3] = -1.0; + float sCornerUp[4];// = float[]( -1.0, -1.0, 1.0, 1.0 ); + sCornerUp[0] = -1.0; + sCornerUp[1] = -1.0; + sCornerUp[2] = 1.0; + sCornerUp[3] = 1.0; + vec2 sUVCornerExtent[4];// = vec2[](vec2( 0.0, 1.0 ), vec2( 1.0, 1.0 ), vec2( 1.0, 0.0 ), vec2( 0.0, 0.0 )); + sUVCornerExtent[0] = vec2( 0.0, 1.0 ); + sUVCornerExtent[1] = vec2( 1.0, 1.0 ); + sUVCornerExtent[2] = vec2( 1.0, 0.0 ); + sUVCornerExtent[3] = vec2( 0.0, 0.0 ); + + // TODO: This could all be calculated on the CPU. + float equatorStepSize = M_2PI_F / float( numEquatorSteps ); + float equatorHalfStep = ( equatorStepSize / 2.0 ) - 0.0001; + float polarStepSize = M_PI_F / float( numPolarSteps ); + float polarHalfStep = ( polarStepSize / 2.0 ) - 0.0001; + + // The vector between the camera and the billboard. + vec3 lookVec = normalize( camPos - center ); + + // Generate the camera up and right vectors from + // the object transform and camera forward. + vec3 camUp = imposterUp; + vec3 camRight = cross( -lookVec, camUp ); + + // The billboarding is based on the camera directions. + vec3 rightVec = camRight * sCornerRight[corner]; + vec3 upVec = camUp * sCornerUp[corner]; + + float lookPitch = acos( dot( imposterUp, lookVec ) ); + + // First check to see if we need to render the top billboard. + int index; + /* + if ( includePoles && ( lookPitch < polarAngle || lookPitch > sPi - polarAngle ) ) + { + index = numEquatorSteps * 3; + + // When we render the top/bottom billboard we always use + // a fixed vector that matches the rotation of the object. + rightVec = vec3( 1, 0, 0 ) * sCornerRight[corner]; + upVec = vec3( 0, 1, 0 ) * sCornerUp[corner]; + + if ( lookPitch > sPi - polarAngle ) + { + upVec = -upVec; + index++; + } + } + else + */ + { + // Calculate the rotation around the z axis then add the + // equator half step. This gets the images to switch a + // half step before the captured angle is met. + float lookAzimuth = atan( lookVec.y, lookVec.x ); + float azimuth = atan( imposterRight.y, imposterRight.x ); + float rotZ = ( lookAzimuth - azimuth ) + equatorHalfStep; + + // The y rotation is calculated from the look vector and + // the object up vector. + float rotY = lookPitch - polarHalfStep; + + // TODO: How can we do this without conditionals? + // Normalize the result to 0 to 2PI. + if ( rotZ < 0.0 ) + rotZ += M_2PI_F; + if ( rotZ > M_2PI_F ) + rotZ -= M_2PI_F; + if ( rotY < 0.0 ) + rotY += M_2PI_F; + if ( rotY > M_PI_F ) // Not M_2PI_F? + rotY -= M_2PI_F; + + float polarIdx = round( abs( rotY ) / polarStepSize ); + + // Get the index to the start of the right polar + // images for this viewing angle. + int numPolarOffset = int( float( numEquatorSteps ) * polarIdx ); + + // Calculate the final image index for lookup + // of the texture coords. + index = int( rotZ / equatorStepSize ) + numPolarOffset; + } + + // Generate the final world space position. + outWsPosition = center + ( upVec * halfSize ) + ( rightVec * halfSize ); + + // Grab the uv set and setup the texture coord. + vec4 uvSet = uvs[index]; + outTexCoord.x = uvSet.x + ( uvSet.z * sUVCornerExtent[corner].x ); + outTexCoord.y = uvSet.y + ( uvSet.w * sUVCornerExtent[corner].y ); + + // Needed for normal mapping and lighting. + outWorldToTangent[0] = vec3( 1, 0, 0 ); + outWorldToTangent[1] = vec3( 0, 1, 0 ); + outWorldToTangent[2] = vec3( 0, 0, -1 ); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/lighting.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/lighting.glsl new file mode 100644 index 000000000..804ab1e3b --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/lighting.glsl @@ -0,0 +1,249 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "./torque.glsl" + +#ifndef TORQUE_SHADERGEN + +// These are the uniforms used by most lighting shaders. + +uniform vec4 inLightPos[3]; +uniform vec4 inLightInvRadiusSq; +uniform vec4 inLightColor[4]; + +#ifndef TORQUE_BL_NOSPOTLIGHT + uniform vec4 inLightSpotDir[3]; + uniform vec4 inLightSpotAngle; + uniform vec4 inLightSpotFalloff; +#endif + +uniform vec4 ambient; +#define ambientCameraFactor 0.3 +uniform float specularPower; +uniform vec4 specularColor; + +#endif // !TORQUE_SHADERGEN + + +void compute4Lights( vec3 wsView, + vec3 wsPosition, + vec3 wsNormal, + vec4 shadowMask, + + #ifdef TORQUE_SHADERGEN + + vec4 inLightPos[3], + vec4 inLightInvRadiusSq, + vec4 inLightColor[4], + vec4 inLightSpotDir[3], + vec4 inLightSpotAngle, + vec4 inLightSpotFalloff, + float specularPower, + vec4 specularColor, + + #endif // TORQUE_SHADERGEN + + out vec4 outDiffuse, + out vec4 outSpecular ) +{ + // NOTE: The light positions and spotlight directions + // are stored in SoA order, so inLightPos[0] is the + // x coord for all 4 lights... inLightPos[1] is y... etc. + // + // This is the key to fully utilizing the vector units and + // saving a huge amount of instructions. + // + // For example this change saved more than 10 instructions + // over a simple for loop for each light. + + int i; + + vec4 lightVectors[3]; + for ( i = 0; i < 3; i++ ) + lightVectors[i] = wsPosition[i] - inLightPos[i]; + + vec4 squareDists = vec4(0); + for ( i = 0; i < 3; i++ ) + squareDists += lightVectors[i] * lightVectors[i]; + + // Accumulate the dot product between the light + // vector and the normal. + // + // The normal is negated because it faces away from + // the surface and the light faces towards the + // surface... this keeps us from needing to flip + // the light vector direction which complicates + // the spot light calculations. + // + // We normalize the result a little later. + // + vec4 nDotL = vec4(0); + for ( i = 0; i < 3; i++ ) + nDotL += lightVectors[i] * -wsNormal[i]; + + vec4 rDotL = vec4(0); + #ifndef TORQUE_BL_NOSPECULAR + + // We're using the Phong specular reflection model + // here where traditionally Torque has used Blinn-Phong + // which has proven to be more accurate to real materials. + // + // We do so because its cheaper as do not need to + // calculate the half angle for all 4 lights. + // + // Advanced Lighting still uses Blinn-Phong, but the + // specular reconstruction it does looks fairly similar + // to this. + // + vec3 R = reflect( wsView, -wsNormal ); + + for ( i = 0; i < 3; i++ ) + rDotL += lightVectors[i] * R[i]; + + #endif + + // Normalize the dots. + // + // Notice we're using the half type here to get a + // much faster sqrt via the rsq_pp instruction at + // the loss of some precision. + // + // Unless we have some extremely large point lights + // i don't believe the precision loss will matter. + // + half4 correction = half4(inversesqrt( squareDists )); + nDotL = saturate( nDotL * correction ); + rDotL = clamp( rDotL * correction, 0.00001, 1.0 ); + + // First calculate a simple point light linear + // attenuation factor. + // + // If this is a directional light the inverse + // radius should be greater than the distance + // causing the attenuation to have no affect. + // + vec4 atten = saturate( 1.0 - ( squareDists * inLightInvRadiusSq ) ); + + #ifndef TORQUE_BL_NOSPOTLIGHT + + // The spotlight attenuation factor. This is really + // fast for what it does... 6 instructions for 4 spots. + + vec4 spotAtten = vec4(0); + for ( i = 0; i < 3; i++ ) + spotAtten += lightVectors[i] * inLightSpotDir[i]; + + vec4 cosAngle = ( spotAtten * correction ) - inLightSpotAngle; + atten *= saturate( cosAngle * inLightSpotFalloff ); + + #endif + + // Finally apply the shadow masking on the attenuation. + atten *= shadowMask; + + // Get the final light intensity. + vec4 intensity = nDotL * atten; + + // Combine the light colors for output. + outDiffuse = vec4(0); + for ( i = 0; i < 4; i++ ) + outDiffuse += intensity[i] * inLightColor[i]; + + // Output the specular power. + vec4 specularIntensity = pow( rDotL, vec4(specularPower) ) * atten; + + // Apply the per-light specular attenuation. + vec4 specular = vec4(0,0,0,1); + for ( i = 0; i < 4; i++ ) + specular += vec4( inLightColor[i].rgb * inLightColor[i].a * specularIntensity[i], 1 ); + + // Add the final specular intensity values together + // using a single dot product operation then get the + // final specular lighting color. + outSpecular = specularColor * specular; +} + + +// This value is used in AL as a constant power to raise specular values +// to, before storing them into the light info buffer. The per-material +// specular value is then computer by using the integer identity of +// exponentiation: +// +// (a^m)^n = a^(m*n) +// +// or +// +// (specular^constSpecular)^(matSpecular/constSpecular) = specular^(matSpecular*constSpecular) +// +#define AL_ConstantSpecularPower 12.0f + +/// The specular calculation used in Advanced Lighting. +/// +/// @param toLight Normalized vector representing direction from the pixel +/// being lit, to the light source, in world space. +/// +/// @param normal Normalized surface normal. +/// +/// @param toEye The normalized vector representing direction from the pixel +/// being lit to the camera. +/// +float AL_CalcSpecular( vec3 toLight, vec3 normal, vec3 toEye ) +{ + // (R.V)^c + float specVal = dot( normalize( -reflect( toLight, normal ) ), toEye ); + + // Return the specular factor. + return pow( max( specVal, 0.00001f ), AL_ConstantSpecularPower ); +} + +/// The output for Deferred Lighting +/// +/// @param toLight Normalized vector representing direction from the pixel +/// being lit, to the light source, in world space. +/// +/// @param normal Normalized surface normal. +/// +/// @param toEye The normalized vector representing direction from the pixel +/// being lit to the camera. +/// +vec4 AL_DeferredOutput( + vec3 lightColor, + vec3 diffuseColor, + vec4 matInfo, + vec4 ambient, + float specular, + float shadowAttenuation) +{ + vec3 specularColor = vec3(specular); + bool metalness = getFlag(matInfo.r, 3); + if ( metalness ) + { + specularColor = 0.04 * (1 - specular) + diffuseColor * specular; + } + + //specular = color * map * spec^gloss + float specularOut = (specularColor * matInfo.b * min(pow(max(specular,1.0f), max((matInfo.a / AL_ConstantSpecularPower),1.0f)),matInfo.a)).r; + + lightColor *= vec3(shadowAttenuation); + lightColor += ambient.rgb; + return vec4(lightColor.rgb, specularOut); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/particleCompositeP.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/particleCompositeP.glsl new file mode 100644 index 000000000..e33c9bd97 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/particleCompositeP.glsl @@ -0,0 +1,62 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "torque.glsl" +#include "hlslCompat.glsl" + +in vec4 offscreenPos; +in vec4 backbufferPos; + +#define IN_offscreenPos offscreenPos +#define IN_backbufferPos backbufferPos + +uniform sampler2D colorSource; +uniform vec4 offscreenTargetParams; + +#ifdef TORQUE_LINEAR_DEPTH +#define REJECT_EDGES +uniform sampler2D edgeSource; +uniform vec4 edgeTargetParams; +#endif + +out vec4 OUT_col; + +void main() +{ + // Off-screen particle source screenspace position in XY + // Back-buffer screenspace position in ZW + vec4 ssPos = vec4(offscreenPos.xy / offscreenPos.w, backbufferPos.xy / backbufferPos.w); + + vec4 uvScene = ( ssPos + 1.0 ) / 2.0; + uvScene.yw = 1.0 - uvScene.yw; + uvScene.xy = viewportCoordToRenderTarget(uvScene.xy, offscreenTargetParams); + +#ifdef REJECT_EDGES + // Cut out particles along the edges, this will create the stencil mask + uvScene.zw = viewportCoordToRenderTarget(uvScene.zw, edgeTargetParams); + float edge = texture( edgeSource, uvScene.zw ).r; + clip( -edge ); +#endif + + // Sample offscreen target and return + OUT_col = texture( colorSource, uvScene.xy ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/particleCompositeV.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/particleCompositeV.glsl new file mode 100644 index 000000000..8c8f840d1 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/particleCompositeV.glsl @@ -0,0 +1,48 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "hlslCompat.glsl" + +in vec2 vTexCoord0; +#define uvCoord vTexCoord0 + +out vec4 offscreenPos; +out vec4 backbufferPos; + +#define OUT_hpos gl_Position +#define OUT_offscreenPos offscreenPos +#define OUT_backbufferPos backbufferPos + +uniform vec4 screenRect; // point, extent + +void main() +{ + OUT_hpos = vec4(uvCoord.xy, 1.0, 1.0); + OUT_hpos.xy *= screenRect.zw; + OUT_hpos.xy += screenRect.xy; + + OUT_backbufferPos = OUT_hpos; + OUT_offscreenPos = OUT_hpos; + + correctSSP(gl_Position); +} + diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/particlesP.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/particlesP.glsl new file mode 100644 index 000000000..cf35e5f1b --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/particlesP.glsl @@ -0,0 +1,113 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "torque.glsl" +#include "hlslCompat.glsl" + +// With advanced lighting we get soft particles. +#ifdef TORQUE_LINEAR_DEPTH + #define SOFTPARTICLES +#endif + +#ifdef SOFTPARTICLES + + #include "shadergen:/autogenConditioners.h" + + uniform float oneOverSoftness; + uniform float oneOverFar; + uniform sampler2D deferredTex; + //uniform vec3 vEye; + uniform vec4 deferredTargetParams; +#endif + +#define CLIP_Z // TODO: Make this a proper macro + +in vec4 color; +in vec2 uv0; +in vec4 pos; + +#define IN_color color +#define IN_uv0 uv0 +#define IN_pos pos + +uniform sampler2D diffuseMap; + +uniform sampler2D paraboloidLightMap; + +vec4 lmSample( vec3 nrm ) +{ + bool calcBack = (nrm.z < 0.0); + if ( calcBack ) + nrm.z = nrm.z * -1.0; + + vec2 lmCoord; + lmCoord.x = (nrm.x / (2*(1 + nrm.z))) + 0.5; + lmCoord.y = 1-((nrm.y / (2*(1 + nrm.z))) + 0.5); + + + // If this is the back, offset in the atlas + if ( calcBack ) + lmCoord.x += 1.0; + + // Atlasing front and back maps, so scale + lmCoord.x *= 0.5; + + return texture(paraboloidLightMap, lmCoord); +} + + +uniform float alphaFactor; +uniform float alphaScale; + +out vec4 OUT_col; + +void main() +{ + float softBlend = 1; + + #ifdef SOFTPARTICLES + vec2 tc = IN_pos.xy * vec2(1.0, -1.0) / IN_pos.w; + tc = viewportCoordToRenderTarget(saturate( ( tc + 1.0 ) * 0.5 ), deferredTargetParams); + + float sceneDepth = deferredUncondition( deferredTex, tc ).w; + float depth = IN_pos.w * oneOverFar; + float diff = sceneDepth - depth; + #ifdef CLIP_Z + // If drawing offscreen, this acts as the depth test, since we don't line up with the z-buffer + // When drawing high-res, though, we want to be able to take advantage of hi-z + // so this is #ifdef'd out + //clip(diff); + #endif + softBlend = saturate( diff * oneOverSoftness ); + #endif + + vec4 diffuse = texture( diffuseMap, IN_uv0 ); + + //OUT_col = vec4( lmSample(vec3(0, 0, -1)).rgb, IN_color.a * diffuse.a * softBlend * alphaScale); + + // Scale output color by the alpha factor (turn LerpAlpha into pre-multiplied alpha) + vec3 colorScale = ( alphaFactor < 0.0 ? IN_color.rgb * diffuse.rgb : vec3( alphaFactor > 0.0 ? IN_color.a * diffuse.a * alphaFactor * softBlend : softBlend ) ); + + OUT_col = hdrEncode( vec4( IN_color.rgb * diffuse.rgb * colorScale, + IN_color.a * diffuse.a * softBlend * alphaScale ) ); +} + diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/particlesV.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/particlesV.glsl new file mode 100644 index 000000000..3d75a6fb6 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/particlesV.glsl @@ -0,0 +1,54 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "hlslCompat.glsl" + +in vec4 vPosition; +in vec4 vColor; +in vec2 vTexCoord0; + +#define In_pos vPosition +#define In_color vColor +#define In_uv0 vTexCoord0 + +out vec4 color; +out vec2 uv0; +out vec4 pos; + +#define OUT_hpos gl_Position +#define OUT_color color +#define OUT_uv0 uv0 +#define OUT_pos pos + +uniform mat4 modelViewProj; +uniform mat4 fsModelViewProj; + +void main() +{ + OUT_hpos = tMul( modelViewProj, In_pos ); + OUT_pos = tMul( fsModelViewProj, In_pos ); + OUT_color = In_color; + OUT_uv0 = In_uv0; + + correctSSP(gl_Position); +} + diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/planarReflectBumpP.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/planarReflectBumpP.glsl new file mode 100644 index 000000000..db4250487 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/planarReflectBumpP.glsl @@ -0,0 +1,70 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Data +//----------------------------------------------------------------------------- +uniform sampler2D diffuseMap, refractMap, bumpMap; +uniform vec4 shadeColor; + +in vec2 TEX0; +in vec4 TEX1; + +out vec4 OUT_col; + +//----------------------------------------------------------------------------- +// Fade edges of axis for texcoord passed in +//----------------------------------------------------------------------------- +float fadeAxis( float val ) +{ + // Fades from 1.0 to 0.0 when less than 0.1 + float fadeLow = clamp( val * 10.0, 0.0, 1.0 ); + + // Fades from 1.0 to 0.0 when greater than 0.9 + float fadeHigh = 1.0 - clamp( (val - 0.9) * 10.0, 0.0, 1.0 ); + + return fadeLow * fadeHigh; +} + + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +void main() +{ + vec3 bumpNorm = texture( bumpMap, TEX0 ).rgb * 2.0 - 1.0; + vec2 offset = vec2( bumpNorm.x, bumpNorm.y ); + vec4 texIndex = TEX1; + + // The fadeVal is used to "fade" the distortion at the edges of the screen. + // This is done so it won't sample the reflection texture out-of-bounds and create artifacts + // Note - this can be done more efficiently with a texture lookup + float fadeVal = fadeAxis( texIndex.x / texIndex.w ) * fadeAxis( texIndex.y / texIndex.w ); + + const float distortion = 0.2; + texIndex.xy += offset * distortion * fadeVal; + + vec4 diffuseColor = texture( diffuseMap, TEX0 ); + vec4 reflectColor = textureProj( refractMap, texIndex ); + + OUT_col = diffuseColor + reflectColor * diffuseColor.a; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/planarReflectBumpV.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/planarReflectBumpV.glsl new file mode 100644 index 000000000..90bcd27d8 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/planarReflectBumpV.glsl @@ -0,0 +1,51 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Data +//----------------------------------------------------------------------------- +in vec4 vPosition; +in vec2 vTexCoord0; + +uniform mat4 modelview; + +out vec2 TEX0; +out vec4 TEX1; + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +void main() +{ + mat4 texGenTest = mat4(0.5, 0.0, 0.0, 0.0, + 0.0, -0.5, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.5, 0.5, 0.0, 1.0); + + gl_Position = modelview * vPosition; + + TEX0 = vTexCoord0.st; + + TEX1 = texGenTest * gl_Position; + TEX1.y = -TEX1.y; + gl_Position.y *= -1; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/planarReflectP.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/planarReflectP.glsl new file mode 100644 index 000000000..384c16188 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/planarReflectP.glsl @@ -0,0 +1,43 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Data +//----------------------------------------------------------------------------- +uniform sampler2D diffuseMap, refractMap; +uniform vec4 shadeColor; + +in vec2 TEX0; +in vec4 TEX1; + +out vec4 OUT_col; + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +void main() +{ + vec4 diffuseColor = texture( diffuseMap, TEX0 ); + vec4 reflectColor = textureProj( refractMap, TEX1 ); + + OUT_col = diffuseColor + reflectColor * diffuseColor.a; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/planarReflectV.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/planarReflectV.glsl new file mode 100644 index 000000000..ba2484f66 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/planarReflectV.glsl @@ -0,0 +1,51 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Data +//----------------------------------------------------------------------------- +in vec4 vPosition; +in vec2 vTexCoord0; + +uniform mat4 modelview; + +out vec2 TEX0; +out vec4 TEX1; + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +void main() +{ + mat4 texGenTest = mat4(0.5, 0.0, 0.0, 0.0, + 0.0, -0.5, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.5, 0.5, 0.0, 1.0); + + gl_Position = modelview * vPosition; + + TEX0 = vTexCoord0; + + TEX1 = texGenTest * gl_Position; + TEX1.y = -TEX1.y; + +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/precipP.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/precipP.glsl new file mode 100644 index 000000000..102d0b0aa --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/precipP.glsl @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Data +//----------------------------------------------------------------------------- +uniform sampler2D diffuseMap; + +in vec4 color; +in vec2 texCoord; + +out vec4 OUT_col; + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +void main() +{ + OUT_col = texture(diffuseMap, texCoord) * color; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/precipV.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/precipV.glsl new file mode 100644 index 000000000..29f921630 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/precipV.glsl @@ -0,0 +1,54 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Data +//----------------------------------------------------------------------------- +in vec4 vPosition; +in vec2 vTexCoord0; + +uniform mat4 modelview; +uniform vec3 cameraPos, ambient; +uniform vec2 fadeStartEnd; + +out vec4 color; +out vec2 texCoord; + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +void main() +{ + gl_Position = modelview * vPosition; + texCoord = vTexCoord0.st; + color = vec4( ambient.r, ambient.g, ambient.b, 1.0 ); + + // Do we need to do a distance fade? + if ( fadeStartEnd.x < fadeStartEnd.y ) + { + + float distance = length( cameraPos - vPosition.xyz ); + color.a = abs( clamp( ( distance - fadeStartEnd.x ) / ( fadeStartEnd.y - fadeStartEnd.x ), 0.0, 1.0 ) - 1.0 ); + } + gl_Position.y *= -1; +} + diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/projectedShadowP.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/projectedShadowP.glsl new file mode 100644 index 000000000..9b0ff0d0b --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/projectedShadowP.glsl @@ -0,0 +1,37 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +in vec2 texCoord; +in vec4 color; +in float fade; + +out vec4 OUT_col; + +uniform sampler2D inputTex; +uniform vec4 ambient; + + +void main() +{ + float shadow = texture( inputTex, texCoord ).a * color.a; + OUT_col = ( ambient * shadow ) + ( 1 - shadow ); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/projectedShadowV.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/projectedShadowV.glsl new file mode 100644 index 000000000..c8b6d2a92 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/projectedShadowV.glsl @@ -0,0 +1,49 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "hlslCompat.glsl" + +in vec4 vPosition; +in vec4 vColor; +in vec2 vTexCoord0; +in vec2 vTexCoord1; + +out vec2 texCoord; +out vec4 color; +out float fade; + +uniform mat4 modelview; +uniform float shadowLength; +uniform vec3 shadowCasterPosition; + +void main() +{ + gl_Position = modelview * vec4(vPosition.xyz, 1.0); + + color = vColor; + texCoord = vTexCoord0.st; + + float fromCasterDist = length(vPosition.xyz - shadowCasterPosition) - shadowLength; + fade = 1.0 - clamp( fromCasterDist / shadowLength , 0.0, 1.0 ); + + correctSSP(gl_Position); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/scatterSkyP.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/scatterSkyP.glsl new file mode 100644 index 000000000..6d4e3ea75 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/scatterSkyP.glsl @@ -0,0 +1,72 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "torque.glsl" +#include "hlslCompat.glsl" + + +// Conn +in vec4 rayleighColor; +#define IN_rayleighColor rayleighColor +in vec4 mieColor; +#define IN_mieColor mieColor +in vec3 v3Direction; +#define IN_v3Direction v3Direction +in vec3 pos; +#define IN_pos pos + +uniform samplerCube nightSky ; +uniform vec4 nightColor; +uniform vec2 nightInterpAndExposure; +uniform float useCubemap; +uniform vec3 lightDir; +uniform vec3 sunDir; + +out vec4 OUT_col; + +void main() +{ + + float fCos = dot( lightDir, IN_v3Direction ) / length(IN_v3Direction); + float fCos2 = fCos*fCos; + + float g = -0.991; + float g2 = -0.991 * -0.991; + + float fMiePhase = 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos2) / pow(abs(1.0 + g2 - 2.0*g*fCos), 1.5); + + vec4 color = IN_rayleighColor + fMiePhase * IN_mieColor; + color.a = color.b; + + vec4 nightSkyColor = texture(nightSky, -v3Direction); + nightSkyColor = mix(nightColor, nightSkyColor, useCubemap); + + float fac = dot( normalize( pos ), sunDir ); + fac = max( nightInterpAndExposure.y, pow( clamp( fac, 0.0, 1.0 ), 2 ) ); + OUT_col = mix( color, nightSkyColor, nightInterpAndExposure.y ); + + OUT_col.a = 1; + + OUT_col = clamp(OUT_col, 0.0, 1.0); + + OUT_col = hdrEncode( OUT_col ); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/scatterSkyV.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/scatterSkyV.glsl new file mode 100644 index 000000000..5780d2df9 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/scatterSkyV.glsl @@ -0,0 +1,154 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "hlslCompat.glsl" + +// The scale equation calculated by Vernier's Graphical Analysis +float vernierScale(float fCos) +{ + float x = 1.0 - fCos; + float x5 = x * 5.25; + float x5p6 = (-6.80 + x5); + float xnew = (3.83 + x * x5p6); + float xfinal = (0.459 + x * xnew); + float xfinal2 = -0.00287 + x * xfinal; + float outx = exp( xfinal2 ); + return 0.25 * outx; +} + +in vec4 vPosition; + +// This is the shader input vertex structure. +#define IN_position vPosition + +// This is the shader output data. +out vec4 rayleighColor; +#define OUT_rayleighColor rayleighColor +out vec4 mieColor; +#define OUT_mieColor mieColor +out vec3 v3Direction; +#define OUT_v3Direction v3Direction +out vec3 pos; +#define OUT_pos pos + +uniform mat4 modelView; +uniform vec4 misc; +uniform vec4 sphereRadii; +uniform vec4 scatteringCoeffs; +uniform vec3 camPos; +uniform vec3 lightDir; +uniform vec4 invWaveLength; +uniform vec4 colorize; + +vec3 desaturate(const vec3 color, const float desaturation) +{ + const vec3 gray_conv = vec3 (0.30, 0.59, 0.11); + return mix(color, vec3(dot(gray_conv , color)), desaturation); +} + +void main() +{ + // Pull some variables out: + float camHeight = misc.x; + float camHeightSqr = misc.y; + + float scale = misc.z; + float scaleOverScaleDepth = misc.w; + + float outerRadius = sphereRadii.x; + float outerRadiusSqr = sphereRadii.y; + + float innerRadius = sphereRadii.z; + float innerRadiusSqr = sphereRadii.w; + + float rayleighBrightness = scatteringCoeffs.x; // Kr * ESun + float rayleigh4PI = scatteringCoeffs.y; // Kr * 4 * PI + + float mieBrightness = scatteringCoeffs.z; // Km * ESun + float mie4PI = scatteringCoeffs.w; // Km * 4 * PI + + // Get the ray from the camera to the vertex, + // and its length (which is the far point of the ray + // passing through the atmosphere). + vec3 v3Pos = vec3(IN_position / 6378000.0);// / outerRadius; + vec3 newCamPos = vec3( 0, 0, camHeight ); + v3Pos.z += innerRadius; + vec3 v3Ray = v3Pos.xyz - newCamPos; + float fFar = length(v3Ray); + v3Ray /= fFar; + + // Calculate the ray's starting position, + // then calculate its scattering offset. + vec3 v3Start = newCamPos; + float fHeight = length(v3Start); + float fDepth = exp(scaleOverScaleDepth * (innerRadius - camHeight)); + float fStartAngle = dot(v3Ray, v3Start) / fHeight; + + float fStartOffset = fDepth * vernierScale( fStartAngle ); + + // Initialize the scattering loop variables. + float fSampleLength = fFar / 2.0; + float fScaledLength = fSampleLength * scale; + vec3 v3SampleRay = v3Ray * fSampleLength; + vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5; + + // Now loop through the sample rays + vec3 v3FrontColor = vec3(0.0, 0.0, 0.0); + for(int i=0; i<2; i++) + { + float fHeight = length(v3SamplePoint); + float fDepth = exp(scaleOverScaleDepth * (innerRadius - fHeight)); + float fLightAngle = dot(lightDir, v3SamplePoint) / fHeight; + float fCameraAngle = dot(v3Ray, v3SamplePoint) / fHeight; + + float vscale3 = vernierScale( fCameraAngle ); + float vscale2 = vernierScale( fLightAngle ); + + float fScatter = (fStartOffset + fDepth*(vscale2 - vscale3)); + vec3 v3Attenuate = exp(-fScatter * (invWaveLength.xyz * rayleigh4PI + mie4PI)); + v3FrontColor += v3Attenuate * (fDepth * fScaledLength); + v3SamplePoint += v3SampleRay; + } + + // Finally, scale the Mie and Rayleigh colors + // and set up the varying variables for the pixel shader. + gl_Position = modelView * IN_position; + OUT_mieColor.rgb = v3FrontColor * mieBrightness; + OUT_mieColor.a = 1.0; + OUT_rayleighColor.rgb = v3FrontColor * (invWaveLength.xyz * rayleighBrightness); + OUT_rayleighColor.a = 1.0; + OUT_v3Direction = newCamPos - v3Pos.xyz; + OUT_pos = IN_position.xyz; + +#ifdef USE_COLORIZE + + OUT_rayleighColor.rgb = desaturate(OUT_rayleighColor.rgb, 1) * colorize.a; + + OUT_rayleighColor.r *= colorize.r; + OUT_rayleighColor.g *= colorize.g; + OUT_rayleighColor.b *= colorize.b; + +#endif + + correctSSP(gl_Position); +} + diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/torque.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/torque.glsl new file mode 100644 index 000000000..6e369bd5e --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/torque.glsl @@ -0,0 +1,339 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _TORQUE_GLSL_ +#define _TORQUE_GLSL_ + + +float M_HALFPI_F = 1.57079632679489661923; +float M_PI_F = 3.14159265358979323846; +float M_2PI_F = 6.28318530717958647692; + +/// Calculate fog based on a start and end positions in worldSpace. +float computeSceneFog( vec3 startPos, + vec3 endPos, + float fogDensity, + float fogDensityOffset, + float fogHeightFalloff ) +{ + float f = length( startPos - endPos ) - fogDensityOffset; + float h = 1.0 - ( endPos.z * fogHeightFalloff ); + return exp( -fogDensity * f * h ); +} + + +/// Calculate fog based on a start and end position and a height. +/// Positions do not need to be in worldSpace but height does. +float computeSceneFog( vec3 startPos, + vec3 endPos, + float height, + float fogDensity, + float fogDensityOffset, + float fogHeightFalloff ) +{ + float f = length( startPos - endPos ) - fogDensityOffset; + float h = 1.0 - ( height * fogHeightFalloff ); + return exp( -fogDensity * f * h ); +} + + +/// Calculate fog based on a distance, height is not used. +float computeSceneFog( float dist, float fogDensity, float fogDensityOffset ) +{ + float f = dist - fogDensityOffset; + return exp( -fogDensity * f ); +} + + +/// Convert a vec4 uv in viewport space to render target space. +vec2 viewportCoordToRenderTarget( vec4 inCoord, vec4 rtParams ) +{ + vec2 outCoord = inCoord.xy / inCoord.w; + outCoord = ( outCoord * rtParams.zw ) + rtParams.xy; + return outCoord; +} + + +/// Convert a vec2 uv in viewport space to render target space. +vec2 viewportCoordToRenderTarget( vec2 inCoord, vec4 rtParams ) +{ + vec2 outCoord = ( inCoord * rtParams.zw ) + rtParams.xy; + return outCoord; +} + + +/// Convert a vec4 quaternion into a 3x3 matrix. +mat3x3 quatToMat( vec4 quat ) +{ + float xs = quat.x * 2.0; + float ys = quat.y * 2.0; + float zs = quat.z * 2.0; + + float wx = quat.w * xs; + float wy = quat.w * ys; + float wz = quat.w * zs; + + float xx = quat.x * xs; + float xy = quat.x * ys; + float xz = quat.x * zs; + + float yy = quat.y * ys; + float yz = quat.y * zs; + float zz = quat.z * zs; + + mat3x3 mat; + + mat[0][0] = 1.0 - (yy + zz); + mat[1][0] = xy - wz; + mat[2][0] = xz + wy; + + mat[0][1] = xy + wz; + mat[1][1] = 1.0 - (xx + zz); + mat[2][1] = yz - wx; + + mat[0][2] = xz - wy; + mat[1][2] = yz + wx; + mat[2][2] = 1.0 - (xx + yy); + + return mat; +} + + +/// The number of additional substeps we take when refining +/// the results of the offset parallax mapping function below. +/// +/// You should turn down the number of steps if your needing +/// more performance out of your parallax surfaces. Increasing +/// the number doesn't yeild much better results and is rarely +/// worth the additional cost. +/// +#define PARALLAX_REFINE_STEPS 3 + +/// Performs fast parallax offset mapping using +/// multiple refinement steps. +/// +/// @param texMap The texture map whos alpha channel we sample the parallax depth. +/// @param texCoord The incoming texture coordinate for sampling the parallax depth. +/// @param negViewTS The negative view vector in tangent space. +/// @param depthScale The parallax factor used to scale the depth result. +/// +vec2 parallaxOffset( sampler2D texMap, vec2 texCoord, vec3 negViewTS, float depthScale ) +{ + float depth = texture( texMap, texCoord ).a/(PARALLAX_REFINE_STEPS*2); + vec2 offset = negViewTS.xy * vec2( depth * depthScale )/vec2(PARALLAX_REFINE_STEPS*2); + + for ( int i=0; i < PARALLAX_REFINE_STEPS; i++ ) + { + depth = ( depth + texture( texMap, texCoord + offset ).a )/(PARALLAX_REFINE_STEPS*2); + offset = negViewTS.xy * vec2( depth * depthScale )/vec2(PARALLAX_REFINE_STEPS*2); + } + + return offset; +} + +/// Same as parallaxOffset but for dxtnm where depth is stored in the red channel instead of the alpha +vec2 parallaxOffsetDxtnm(sampler2D texMap, vec2 texCoord, vec3 negViewTS, float depthScale) +{ + float depth = texture(texMap, texCoord).r/(PARALLAX_REFINE_STEPS*2); + vec2 offset = negViewTS.xy * vec2(depth * depthScale)/vec2(PARALLAX_REFINE_STEPS*2); + + for (int i = 0; i < PARALLAX_REFINE_STEPS; i++) + { + depth = (depth + texture(texMap, texCoord + offset).r)/(PARALLAX_REFINE_STEPS*2); + offset = negViewTS.xy * vec2(depth * depthScale)/vec2(PARALLAX_REFINE_STEPS*2); + } + + return offset; +} + + +/// The maximum value for 16bit per component integer HDR encoding. +const float HDR_RGB16_MAX = 100.0; +/// The maximum value for 10bit per component integer HDR encoding. +const float HDR_RGB10_MAX = 4.0; + +/// Encodes an HDR color for storage into a target. +vec3 hdrEncode( vec3 _sample ) +{ + #if defined( TORQUE_HDR_RGB16 ) + + return _sample / HDR_RGB16_MAX; + + #elif defined( TORQUE_HDR_RGB10 ) + + return _sample / HDR_RGB10_MAX; + + #else + + // No encoding. + return _sample; + + #endif +} + +/// Encodes an HDR color for storage into a target. +vec4 hdrEncode( vec4 _sample ) +{ + return vec4( hdrEncode( _sample.rgb ), _sample.a ); +} + +/// Decodes an HDR color from a target. +vec3 hdrDecode( vec3 _sample ) +{ + #if defined( TORQUE_HDR_RGB16 ) + + return _sample * HDR_RGB16_MAX; + + #elif defined( TORQUE_HDR_RGB10 ) + + return _sample * HDR_RGB10_MAX; + + #else + + // No encoding. + return _sample; + + #endif +} + +/// Decodes an HDR color from a target. +vec4 hdrDecode( vec4 _sample ) +{ + return vec4( hdrDecode( _sample.rgb ), _sample.a ); +} + +/// Returns the luminance for an HDR pixel. +float hdrLuminance( vec3 _sample ) +{ + // There are quite a few different ways to + // calculate luminance from an rgb value. + // + // If you want to use a different technique + // then plug it in here. + // + + //////////////////////////////////////////////////////////////////////////// + // + // Max component luminance. + // + //float lum = max( _sample.r, max( _sample.g, _sample.b ) ); + + //////////////////////////////////////////////////////////////////////////// + // The perceptual relative luminance. + // + // See http://en.wikipedia.org/wiki/Luminance_(relative) + // + const vec3 RELATIVE_LUMINANCE = vec3( 0.2126, 0.7152, 0.0722 ); + float lum = dot( _sample, RELATIVE_LUMINANCE ); + + //////////////////////////////////////////////////////////////////////////// + // + // The average component luminance. + // + //const vec3 AVERAGE_LUMINANCE = vec3( 0.3333, 0.3333, 0.3333 ); + //float lum = dot( _sample, AVERAGE_LUMINANCE ); + + return lum; +} + +#ifdef TORQUE_PIXEL_SHADER +/// Called from the visibility feature to do screen +/// door transparency for fading of objects. +void fizzle(vec2 vpos, float visibility) +{ + // NOTE: The magic values below are what give us + // the nice even pattern during the fizzle. + // + // These values can be changed to get different + // patterns... some better than others. + // + // Horizontal Blinds - { vpos.x, 0.916, vpos.y, 0 } + // Vertical Lines - { vpos.x, 12.9898, vpos.y, 78.233 } + // + // I'm sure there are many more patterns here to + // discover for different effects. + + mat2x2 m = mat2x2( vpos.x, vpos.y, 0.916, 0.350 ); + if( (visibility - fract( determinant( m ) )) < 0 ) //if(a < 0) discard; + discard; +} +#endif //TORQUE_PIXEL_SHADER + +/// Basic assert macro. If the condition fails, then the shader will output color. +/// @param condition This should be a bvec[2-4]. If any items is false, condition is considered to fail. +/// @param color The color that should be outputted if the condition fails. +/// @note This macro will only work in the void main() method of a pixel shader. +#define assert(condition, color) { if(!any(condition)) { OUT_col = color; return; } } + +// Deferred Shading: Material Info Flag Check +bool getFlag(float flags, float num) +{ + float process = round(flags * 255); + float squareNum = pow(2.0, num); + return (mod(process, pow(2.0, squareNum)) >= squareNum); +} + +// #define TORQUE_STOCK_GAMMA +#ifdef TORQUE_STOCK_GAMMA +// Sample in linear space. Decodes gamma. +vec4 toLinear(vec4 tex) +{ + return tex; +} +// Encodes gamma. +vec4 toGamma(vec4 tex) +{ + return tex; +} +vec3 toLinear(vec3 tex) +{ + return tex; +} +// Encodes gamma. +vec3 toGamma(vec3 tex) +{ + return tex; +} +#else +// Sample in linear space. Decodes gamma. +vec4 toLinear(vec4 tex) +{ + return vec4(pow(abs(tex.rgb), vec3(2.2)), tex.a); +} +// Encodes gamma. +vec4 toGamma(vec4 tex) +{ + return vec4(pow(abs(tex.rgb), vec3(1.0/2.2)), tex.a); +} +// Sample in linear space. Decodes gamma. +vec3 toLinear(vec3 tex) +{ + return pow(abs(tex), vec3(2.2)); +} +// Encodes gamma. +vec3 toGamma(vec3 tex) +{ + return pow(abs(tex), vec3(1.0/2.2)); +} +#endif // + +#endif // _TORQUE_GLSL_ diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/wavesP.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/wavesP.glsl new file mode 100644 index 000000000..06c8a1a28 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/wavesP.glsl @@ -0,0 +1,57 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +uniform sampler2D diffMap; +uniform sampler2D bumpMap; +uniform samplerCube cubeMap; +uniform vec4 specularColor; +uniform float specularPower; +uniform vec4 ambient; +uniform float accumTime; + +in vec2 TEX0; +in vec4 outLightVec; +in vec3 outPos; +in vec3 outEyePos; + +out vec4 OUT_col; + +void main() +{ + vec2 texOffset; + float sinOffset1 = sin( accumTime * 1.5 + TEX0.y * 6.28319 * 3.0 ) * 0.03; + float sinOffset2 = sin( accumTime * 3.0 + TEX0.y * 6.28319 ) * 0.04; + + texOffset.x = TEX0.x + sinOffset1 + sinOffset2; + texOffset.y = TEX0.y + cos( accumTime * 3.0 + TEX0.x * 6.28319 * 2.0 ) * 0.05; + + vec4 bumpNorm = texture(bumpMap, texOffset) * 2.0 - 1.0; + vec4 diffuse = texture(diffMap, texOffset); + + OUT_col = diffuse * (clamp(dot(outLightVec.xyz, bumpNorm.xyz), 0.0, 1.0) + ambient); + + vec3 eyeVec = normalize(outEyePos - outPos); + vec3 halfAng = normalize(eyeVec + outLightVec.xyz); + float specular = clamp(dot(bumpNorm.xyz, halfAng), 0.0, 1.0) * outLightVec.w; + specular = pow(specular, specularPower); + OUT_col += specularColor * specular; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/wind.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/wind.glsl new file mode 100644 index 000000000..0ddb492b9 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/wind.glsl @@ -0,0 +1,101 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// +// A tip of the hat.... +// +// The following wind effects were derived from the GPU Gems +// 3 chapter "Vegetation Procedural Animation and Shading in Crysis" +// by Tiago Sousa of Crytek. +// + +vec4 smoothCurve( vec4 x ) +{ + return x * x * ( 3.0 - 2.0 * x ); +} + +vec4 triangleWave( vec4 x ) +{ + return abs( fract( x + 0.5 ) * 2.0 - 1.0 ); +} + +vec4 smoothTriangleWave( vec4 x ) +{ + return smoothCurve( triangleWave( x ) ); +} + +vec3 windTrunkBending( vec3 vPos, vec2 vWind, float fBendFactor ) +{ + // Smooth the bending factor and increase + // the near by height limit. + fBendFactor += 1.0; + fBendFactor *= fBendFactor; + fBendFactor = fBendFactor * fBendFactor - fBendFactor; + + // Displace the vert. + vec3 vNewPos = vPos; + vNewPos.xy += vWind * fBendFactor; + + // Limit the length which makes the bend more + // spherical and prevents stretching. + float fLength = length( vPos ); + vPos = normalize( vNewPos ) * fLength; + + return vPos; +} + +vec3 windBranchBending( vec3 vPos, + vec3 vNormal, + + float fTime, + float fWindSpeed, + + float fBranchPhase, + float fBranchAmp, + float fBranchAtten, + + float fDetailPhase, + float fDetailAmp, + float fDetailFreq, + + float fEdgeAtten ) +{ + float fVertPhase = dot( vPos, vec3( fDetailPhase + fBranchPhase ) ); + + vec2 vWavesIn = fTime + vec2( fVertPhase, fBranchPhase ); + + vec4 vWaves = ( fract( vWavesIn.xxyy * + vec4( 1.975, 0.793, 0.375, 0.193 ) ) * + 2.0 - 1.0 ) * fWindSpeed * fDetailFreq; + + vWaves = smoothTriangleWave( vWaves ); + + vec2 vWavesSum = vWaves.xz + vWaves.yw; + + // We want the branches to bend both up and down. + vWavesSum.y = 1.0 - ( vWavesSum.y * 2.0 ); + + vPos += vWavesSum.xxy * vec3( fEdgeAtten * fDetailAmp * vNormal.xy, + fBranchAtten * fBranchAmp ); + + return vPos; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/guiMaterialV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/guiMaterialV.hlsl new file mode 100644 index 000000000..5d725338f --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/guiMaterialV.hlsl @@ -0,0 +1,45 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "hlslStructs.hlsl" +#include "shaderModel.hlsl" + +struct MaterialDecoratorConnectV +{ + float4 hpos : TORQUE_POSITION; + float2 uv0 : TEXCOORD0; +}; + +uniform float4x4 modelview : register(C0); + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +MaterialDecoratorConnectV main( VertexIn_PCT IN ) +{ + MaterialDecoratorConnectV OUT; + + OUT.hpos = mul(modelview, float4(IN.pos,1.0)); + OUT.uv0 = IN.uv0; + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/hlslStructs.h b/Templates/BaseGame/game/core/rendering/shaders/hlslStructs.h new file mode 100644 index 000000000..6a57e4db7 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/hlslStructs.h @@ -0,0 +1,116 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// The purpose of this file is to get all of our HLSL structures into one place. +// Please use the structures here instead of redefining input and output structures +// in each shader file. If structures are added, please adhere to the naming convention. + +//------------------------------------------------------------------------------ +// Vertex Input Structures +// +// These structures map to FVFs/Vertex Declarations in Torque. See gfxStructs.h +//------------------------------------------------------------------------------ + +// Notes +// +// Position should be specified as a float4. Right now our vertex structures in +// the engine output float3s for position. This does NOT mean that the POSITION +// binding should be float3, because it will assign 0 to the w coordinate, which +// results in the vertex not getting translated when it is transformed. + +struct VertexIn_P +{ + float4 pos : POSITION; +}; + +struct VertexIn_PT +{ + float4 pos : POSITION; + float2 uv0 : TEXCOORD0; +}; + +struct VertexIn_PTTT +{ + float4 pos : POSITION; + float2 uv0 : TEXCOORD0; + float2 uv1 : TEXCOORD1; + float2 uv2 : TEXCOORD2; +}; + +struct VertexIn_PC +{ + float4 pos : POSITION; + float4 color : DIFFUSE; +}; + +struct VertexIn_PNC +{ + float4 pos : POSITION; + float3 normal : NORMAL; + float4 color : DIFFUSE; +}; + +struct VertexIn_PCT +{ + float4 pos : POSITION; + float4 color : DIFFUSE; + float2 uv0 : TEXCOORD0; +}; + +struct VertexIn_PN +{ + float4 pos : POSITION; + float3 normal : NORMAL; +}; + +struct VertexIn_PNT +{ + float4 pos : POSITION; + float3 normal : NORMAL; + float2 uv0 : TEXCOORD0; +}; + +struct VertexIn_PNTT +{ + float4 pos : POSITION; + float3 normal : NORMAL; + float3 tangent : TANGENT; + float2 uv0 : TEXCOORD0; +}; + +struct VertexIn_PNCT +{ + float4 pos : POSITION; + float3 normal : NORMAL; + float4 color : DIFFUSE; + float2 uv0 : TEXCOORD0; +}; + +struct VertexIn_PNTTTB +{ + float4 pos : POSITION; + float3 normal : NORMAL; + float2 uv0 : TEXCOORD0; + float2 uv1 : TEXCOORD1; + float3 T : TEXCOORD2; + float3 B : TEXCOORD3; +}; \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/hlslStructs.hlsl b/Templates/BaseGame/game/core/rendering/shaders/hlslStructs.hlsl new file mode 100644 index 000000000..ce0ca305c --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/hlslStructs.hlsl @@ -0,0 +1,114 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// The purpose of this file is to get all of our HLSL structures into one place. +// Please use the structures here instead of redefining input and output structures +// in each shader file. If structures are added, please adhere to the naming convention. + +//------------------------------------------------------------------------------ +// Vertex Input Structures +// +// These structures map to FVFs/Vertex Declarations in Torque. See gfxStructs.h +//------------------------------------------------------------------------------ + +// Notes +// +// Position should be specified as a float3 as our vertex structures in +// the engine output float3s for position. + +struct VertexIn_P +{ + float3 pos : POSITION; +}; + +struct VertexIn_PT +{ + float3 pos : POSITION; + float2 uv0 : TEXCOORD0; +}; + +struct VertexIn_PTTT +{ + float3 pos : POSITION; + float2 uv0 : TEXCOORD0; + float2 uv1 : TEXCOORD1; + float2 uv2 : TEXCOORD2; +}; + +struct VertexIn_PC +{ + float3 pos : POSITION; + float4 color : DIFFUSE; +}; + +struct VertexIn_PNC +{ + float3 pos : POSITION; + float3 normal : NORMAL; + float4 color : DIFFUSE; +}; + +struct VertexIn_PCT +{ + float3 pos : POSITION; + float4 color : DIFFUSE; + float2 uv0 : TEXCOORD0; +}; + +struct VertexIn_PN +{ + float3 pos : POSITION; + float3 normal : NORMAL; +}; + +struct VertexIn_PNT +{ + float3 pos : POSITION; + float3 normal : NORMAL; + float2 uv0 : TEXCOORD0; +}; + +struct VertexIn_PNTT +{ + float3 pos : POSITION; + float3 normal : NORMAL; + float3 tangent : TANGENT; + float2 uv0 : TEXCOORD0; +}; + +struct VertexIn_PNCT +{ + float3 pos : POSITION; + float3 normal : NORMAL; + float4 color : DIFFUSE; + float2 uv0 : TEXCOORD0; +}; + +struct VertexIn_PNTTTB +{ + float3 pos : POSITION; + float3 normal : NORMAL; + float2 uv0 : TEXCOORD0; + float2 uv1 : TEXCOORD1; + float3 T : TEXCOORD2; + float3 B : TEXCOORD3; +}; \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/imposter.hlsl b/Templates/BaseGame/game/core/rendering/shaders/imposter.hlsl new file mode 100644 index 000000000..bc700ba03 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/imposter.hlsl @@ -0,0 +1,149 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "torque.hlsl" + + +static float sCornerRight[4] = { -1, 1, 1, -1 }; +static float sCornerUp[4] = { -1, -1, 1, 1 }; +static float2 sUVCornerExtent[4] = +{ + float2( 0, 1 ), + float2( 1, 1 ), + float2( 1, 0 ), + float2( 0, 0 ) +}; + +#define IMPOSTER_MAX_UVS 64 + + +void imposter_v( + // These parameters usually come from the vertex. + float3 center, + int corner, + float halfSize, + float3 imposterUp, + float3 imposterRight, + + // These are from the imposter shader constant. + int numEquatorSteps, + int numPolarSteps, + float polarAngle, + bool includePoles, + + // Other shader constants. + float3 camPos, + float4 uvs[IMPOSTER_MAX_UVS], + + // The outputs of this function. + out float3 outWsPosition, + out float2 outTexCoord, + out float3x3 outWorldToTangent + ) +{ + // TODO: This could all be calculated on the CPU. + float equatorStepSize = M_2PI_F / numEquatorSteps; + float equatorHalfStep = ( equatorStepSize / 2.0 ) - 0.0001; + float polarStepSize = M_PI_F / numPolarSteps; + float polarHalfStep = ( polarStepSize / 2.0 ) - 0.0001; + + // The vector between the camera and the billboard. + float3 lookVec = normalize( camPos - center ); + + // Generate the camera up and right vectors from + // the object transform and camera forward. + float3 camUp = imposterUp; + float3 camRight = normalize( cross( -lookVec, camUp ) ); + + // The billboarding is based on the camera directions. + float3 rightVec = camRight * sCornerRight[corner]; + float3 upVec = camUp * sCornerUp[corner]; + + float lookPitch = acos( dot( imposterUp, lookVec ) ); + + // First check to see if we need to render the top billboard. + int index; + /* + if ( includePoles && ( lookPitch < polarAngle || lookPitch > sPi - polarAngle ) ) + { + index = numEquatorSteps * 3; + + // When we render the top/bottom billboard we always use + // a fixed vector that matches the rotation of the object. + rightVec = float3( 1, 0, 0 ) * sCornerRight[corner]; + upVec = float3( 0, 1, 0 ) * sCornerUp[corner]; + + if ( lookPitch > sPi - polarAngle ) + { + upVec = -upVec; + index++; + } + } + else + */ + { + // Calculate the rotation around the z axis then add the + // equator half step. This gets the images to switch a + // half step before the captured angle is met. + float lookAzimuth = atan2( lookVec.y, lookVec.x ); + float azimuth = atan2( imposterRight.y, imposterRight.x ); + float rotZ = ( lookAzimuth - azimuth ) + equatorHalfStep; + + // The y rotation is calculated from the look vector and + // the object up vector. + float rotY = lookPitch - polarHalfStep; + + // TODO: How can we do this without conditionals? + // Normalize the result to 0 to 2PI. + if ( rotZ < 0 ) + rotZ += M_2PI_F; + if ( rotZ > M_2PI_F ) + rotZ -= M_2PI_F; + if ( rotY < 0 ) + rotY += M_2PI_F; + if ( rotY > M_PI_F ) // Not M_2PI_F? + rotY -= M_2PI_F; + + float polarIdx = round( abs( rotY ) / polarStepSize ); + + // Get the index to the start of the right polar + // images for this viewing angle. + int numPolarOffset = numEquatorSteps * polarIdx; + + // Calculate the final image index for lookup + // of the texture coords. + index = ( rotZ / equatorStepSize ) + numPolarOffset; + } + + // Generate the final world space position. + outWsPosition = center + ( upVec * halfSize ) + ( rightVec * halfSize ); + + // Grab the uv set and setup the texture coord. + float4 uvSet = uvs[index]; + outTexCoord.x = uvSet.x + ( uvSet.z * sUVCornerExtent[corner].x ); + outTexCoord.y = uvSet.y + ( uvSet.w * sUVCornerExtent[corner].y ); + + // Needed for normal mapping and lighting. + outWorldToTangent[0] = float3( 1, 0, 0 ); + outWorldToTangent[1] = float3( 0, 1, 0 ); + outWorldToTangent[2] = float3( 0, 0, -1 ); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting.hlsl new file mode 100644 index 000000000..a41b8a873 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting.hlsl @@ -0,0 +1,249 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "./torque.hlsl" + +#ifndef TORQUE_SHADERGEN + +// These are the uniforms used by most lighting shaders. + +uniform float4 inLightPos[3]; +uniform float4 inLightInvRadiusSq; +uniform float4 inLightColor[4]; + +#ifndef TORQUE_BL_NOSPOTLIGHT + uniform float4 inLightSpotDir[3]; + uniform float4 inLightSpotAngle; + uniform float4 inLightSpotFalloff; +#endif + +uniform float4 ambient; +#define ambientCameraFactor 0.3 +uniform float specularPower; +uniform float4 specularColor; + +#endif // !TORQUE_SHADERGEN + + +void compute4Lights( float3 wsView, + float3 wsPosition, + float3 wsNormal, + float4 shadowMask, + + #ifdef TORQUE_SHADERGEN + + float4 inLightPos[3], + float4 inLightInvRadiusSq, + float4 inLightColor[4], + float4 inLightSpotDir[3], + float4 inLightSpotAngle, + float4 inLightSpotFalloff, + float specularPower, + float4 specularColor, + + #endif // TORQUE_SHADERGEN + + out float4 outDiffuse, + out float4 outSpecular ) +{ + // NOTE: The light positions and spotlight directions + // are stored in SoA order, so inLightPos[0] is the + // x coord for all 4 lights... inLightPos[1] is y... etc. + // + // This is the key to fully utilizing the vector units and + // saving a huge amount of instructions. + // + // For example this change saved more than 10 instructions + // over a simple for loop for each light. + + int i; + + float4 lightVectors[3]; + for ( i = 0; i < 3; i++ ) + lightVectors[i] = wsPosition[i] - inLightPos[i]; + + float4 squareDists = 0; + for ( i = 0; i < 3; i++ ) + squareDists += lightVectors[i] * lightVectors[i]; + + // Accumulate the dot product between the light + // vector and the normal. + // + // The normal is negated because it faces away from + // the surface and the light faces towards the + // surface... this keeps us from needing to flip + // the light vector direction which complicates + // the spot light calculations. + // + // We normalize the result a little later. + // + float4 nDotL = 0; + for ( i = 0; i < 3; i++ ) + nDotL += lightVectors[i] * -wsNormal[i]; + + float4 rDotL = 0; + #ifndef TORQUE_BL_NOSPECULAR + + // We're using the Phong specular reflection model + // here where traditionally Torque has used Blinn-Phong + // which has proven to be more accurate to real materials. + // + // We do so because its cheaper as do not need to + // calculate the half angle for all 4 lights. + // + // Advanced Lighting still uses Blinn-Phong, but the + // specular reconstruction it does looks fairly similar + // to this. + // + float3 R = reflect( wsView, -wsNormal ); + + for ( i = 0; i < 3; i++ ) + rDotL += lightVectors[i] * R[i]; + + #endif + + // Normalize the dots. + // + // Notice we're using the half type here to get a + // much faster sqrt via the rsq_pp instruction at + // the loss of some precision. + // + // Unless we have some extremely large point lights + // i don't believe the precision loss will matter. + // + half4 correction = (half4)rsqrt( squareDists ); + nDotL = saturate( nDotL * correction ); + rDotL = clamp( rDotL * correction, 0.00001, 1.0 ); + + // First calculate a simple point light linear + // attenuation factor. + // + // If this is a directional light the inverse + // radius should be greater than the distance + // causing the attenuation to have no affect. + // + float4 atten = saturate( 1.0 - ( squareDists * inLightInvRadiusSq ) ); + + #ifndef TORQUE_BL_NOSPOTLIGHT + + // The spotlight attenuation factor. This is really + // fast for what it does... 6 instructions for 4 spots. + + float4 spotAtten = 0; + for ( i = 0; i < 3; i++ ) + spotAtten += lightVectors[i] * inLightSpotDir[i]; + + float4 cosAngle = ( spotAtten * correction ) - inLightSpotAngle; + atten *= saturate( cosAngle * inLightSpotFalloff ); + + #endif + + // Finally apply the shadow masking on the attenuation. + atten *= shadowMask; + + // Get the final light intensity. + float4 intensity = nDotL * atten; + + // Combine the light colors for output. + outDiffuse = 0; + for ( i = 0; i < 4; i++ ) + outDiffuse += intensity[i] * inLightColor[i]; + + // Output the specular power. + float4 specularIntensity = pow( rDotL, specularPower.xxxx ) * atten; + + // Apply the per-light specular attenuation. + float4 specular = float4(0,0,0,1); + for ( i = 0; i < 4; i++ ) + specular += float4( inLightColor[i].rgb * inLightColor[i].a * specularIntensity[i], 1 ); + + // Add the final specular intensity values together + // using a single dot product operation then get the + // final specular lighting color. + outSpecular = specularColor * specular; +} + + +// This value is used in AL as a constant power to raise specular values +// to, before storing them into the light info buffer. The per-material +// specular value is then computer by using the integer identity of +// exponentiation: +// +// (a^m)^n = a^(m*n) +// +// or +// +// (specular^constSpecular)^(matSpecular/constSpecular) = specular^(matSpecular*constSpecular) +// +#define AL_ConstantSpecularPower 12.0f + +/// The specular calculation used in Advanced Lighting. +/// +/// @param toLight Normalized vector representing direction from the pixel +/// being lit, to the light source, in world space. +/// +/// @param normal Normalized surface normal. +/// +/// @param toEye The normalized vector representing direction from the pixel +/// being lit to the camera. +/// +float AL_CalcSpecular( float3 toLight, float3 normal, float3 toEye ) +{ + // (R.V)^c + float specVal = dot( normalize( -reflect( toLight, normal ) ), toEye ); + + // Return the specular factor. + return pow( max( specVal, 0.00001f ), AL_ConstantSpecularPower ); +} + +/// The output for Deferred Lighting +/// +/// @param toLight Normalized vector representing direction from the pixel +/// being lit, to the light source, in world space. +/// +/// @param normal Normalized surface normal. +/// +/// @param toEye The normalized vector representing direction from the pixel +/// being lit to the camera. +/// +float4 AL_DeferredOutput( + float3 lightColor, + float3 diffuseColor, + float4 matInfo, + float4 ambient, + float specular, + float shadowAttenuation) +{ + float3 specularColor = float3(specular, specular, specular); + bool metalness = getFlag(matInfo.r, 3); + if ( metalness ) + { + specularColor = 0.04 * (1 - specular) + diffuseColor * specular; + } + + //specular = color * map * spec^gloss + float specularOut = (specularColor * matInfo.b * min(pow(abs(specular), max(( matInfo.a/ AL_ConstantSpecularPower),1.0f)),matInfo.a)).r; + + lightColor *= shadowAttenuation; + lightColor += ambient.rgb; + return float4(lightColor.rgb, specularOut); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/convexGeometryV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/convexGeometryV.hlsl new file mode 100644 index 000000000..064fcffa6 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/convexGeometryV.hlsl @@ -0,0 +1,54 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../hlslStructs.hlsl" +#include "../../shaderModel.hlsl" + +struct VertData +{ + float3 pos : POSITION; + float4 color : COLOR; +}; + +struct ConvexConnectV +{ + float4 hpos : TORQUE_POSITION; + float4 wsEyeDir : TEXCOORD0; + float4 ssPos : TEXCOORD1; + float4 vsEyeDir : TEXCOORD2; +}; + +ConvexConnectV main( VertData IN, + uniform float4x4 modelview, + uniform float4x4 objTrans, + uniform float4x4 worldViewOnly, + uniform float3 eyePosWorld ) +{ + ConvexConnectV OUT; + + OUT.hpos = mul( modelview, float4(IN.pos,1.0) ); + OUT.wsEyeDir = mul(objTrans, float4(IN.pos, 1.0)) - float4(eyePosWorld, 0.0); + OUT.vsEyeDir = mul(worldViewOnly, float4(IN.pos, 1.0)); + OUT.ssPos = OUT.hpos; + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/deferredClearGBufferP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/deferredClearGBufferP.hlsl new file mode 100644 index 000000000..5ae05896e --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/deferredClearGBufferP.hlsl @@ -0,0 +1,54 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../shaderModel.hlsl" + +struct Conn +{ + float4 hpos : TORQUE_POSITION; +}; + +struct Fragout +{ + float4 col : TORQUE_TARGET0; + float4 col1 : TORQUE_TARGET1; + float4 col2 : TORQUE_TARGET2; +}; + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +Fragout main( Conn IN ) +{ + Fragout OUT; + + // Clear Deferred Buffer ( Normals/Depth ); + OUT.col = float4(1.0, 1.0, 1.0, 1.0); + + // Clear Color Buffer. + OUT.col1 = float4(0.0, 0.0, 0.0, 1.0); + + // Clear Material Info Buffer. + OUT.col2 = float4(0.0, 0.0, 0.0, 1.0); + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/deferredClearGBufferV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/deferredClearGBufferV.hlsl new file mode 100644 index 000000000..20ba4d509 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/deferredClearGBufferV.hlsl @@ -0,0 +1,43 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../shaderModel.hlsl" + +struct Appdata +{ + float3 pos : POSITION; + float4 color : COLOR; +}; + +struct Conn +{ + float4 hpos : TORQUE_POSITION; +}; + +uniform float4x4 modelview; + +Conn main( Appdata In ) +{ + Conn Out; + Out.hpos = float4(In.pos,1.0); + return Out; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/deferredColorShaderP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/deferredColorShaderP.hlsl new file mode 100644 index 000000000..d91d2eb38 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/deferredColorShaderP.hlsl @@ -0,0 +1,46 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../shaderModel.hlsl" + +struct Fragout +{ + float4 col : TORQUE_TARGET0; + float4 col1 : TORQUE_TARGET1; + float4 col2 : TORQUE_TARGET2; +}; + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +Fragout main( ) +{ + Fragout OUT; + + OUT.col = float4(0.0, 0.0, 0.0, 0.0); + OUT.col1 = float4(1.0, 1.0, 1.0, 1.0); + + // Draw on color buffer. + OUT.col2 = float4(1.0, 0.0, 0.0, 1.0); + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/deferredShadingP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/deferredShadingP.hlsl new file mode 100644 index 000000000..ebd9ed72b --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/deferredShadingP.hlsl @@ -0,0 +1,54 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../shaderModelAutoGen.hlsl" +#include "../../postfx/postFx.hlsl" +#include "../../torque.hlsl" + +TORQUE_UNIFORM_SAMPLER2D(colorBufferTex,0); +TORQUE_UNIFORM_SAMPLER2D(lightDeferredTex,1); +TORQUE_UNIFORM_SAMPLER2D(matInfoTex,2); +TORQUE_UNIFORM_SAMPLER2D(deferredTex,3); + +float4 main( PFXVertToPix IN ) : TORQUE_TARGET0 +{ + float4 lightBuffer = TORQUE_TEX2D( lightDeferredTex, IN.uv0 ); + float4 colorBuffer = TORQUE_TEX2D( colorBufferTex, IN.uv0 ); + float4 matInfo = TORQUE_TEX2D( matInfoTex, IN.uv0 ); + float specular = saturate(lightBuffer.a); + float depth = TORQUE_DEFERRED_UNCONDITION( deferredTex, IN.uv0 ).w; + + if (depth>0.9999) + return float4(0,0,0,0); + + // Diffuse Color Altered by Metalness + bool metalness = getFlag(matInfo.r, 3); + if ( metalness ) + { + colorBuffer *= (1.0 - colorBuffer.a); + } + + colorBuffer += float4(specular, specular, specular, 1.0); + colorBuffer *= float4(lightBuffer.rgb, 1.0); + + return hdrEncode( float4(colorBuffer.rgb, 1.0) ); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/farFrustumQuad.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/farFrustumQuad.hlsl new file mode 100644 index 000000000..543e21677 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/farFrustumQuad.hlsl @@ -0,0 +1,47 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- +#include "../../shaderModel.hlsl" + +struct FarFrustumQuadConnectV +{ + float4 hpos : TORQUE_POSITION; + float2 uv0 : TEXCOORD0; + float3 wsEyeRay : TEXCOORD1; + float3 vsEyeRay : TEXCOORD2; +}; + +struct FarFrustumQuadConnectP +{ + float4 hpos : TORQUE_POSITION; + float2 uv0 : TEXCOORD0; + float3 wsEyeRay : TEXCOORD1; + float3 vsEyeRay : TEXCOORD2; +}; + + +float2 getUVFromSSPos( float3 ssPos, float4 rtParams ) +{ + float2 outPos = ( ssPos.xy + 1.0 ) / 2.0; + outPos.y = 1.0 - outPos.y; + outPos = ( outPos * rtParams.zw ) + rtParams.xy; + return outPos; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/farFrustumQuadV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/farFrustumQuadV.hlsl new file mode 100644 index 000000000..0167d901a --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/farFrustumQuadV.hlsl @@ -0,0 +1,43 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../hlslStructs.hlsl" +#include "farFrustumQuad.hlsl" + + +FarFrustumQuadConnectV main( VertexIn_PNTT IN, + uniform float4 rtParams0 ) +{ + FarFrustumQuadConnectV OUT; + + OUT.hpos = float4( IN.uv0, 0, 1 ); + + // Get a RT-corrected UV from the SS coord + OUT.uv0 = getUVFromSSPos( OUT.hpos.xyz, rtParams0 ); + + // Interpolators will generate eye rays the + // from far-frustum corners. + OUT.wsEyeRay = IN.tangent; + OUT.vsEyeRay = IN.normal; + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/convexGeometryV.glsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/convexGeometryV.glsl new file mode 100644 index 000000000..1807ac43f --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/convexGeometryV.glsl @@ -0,0 +1,52 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" + +in vec4 vPosition; + +#define IN_pos vPosition + +out vec4 wsEyeDir; +out vec4 ssPos; +out vec4 vsEyeDir; + +#define OUT_hpos gl_Position +#define OUT_wsEyeDir wsEyeDir +#define OUT_ssPos ssPos +#define OUT_vsEyeDir vsEyeDir + +uniform mat4 modelview; +uniform mat4 objTrans; +uniform mat4 worldViewOnly; +uniform vec3 eyePosWorld; + +void main() +{ + OUT_hpos = tMul( modelview, IN_pos ); + OUT_wsEyeDir = tMul( objTrans, IN_pos ) - vec4( eyePosWorld, 0.0 ); + OUT_vsEyeDir = tMul( worldViewOnly, IN_pos ); + OUT_ssPos = OUT_hpos; + + correctSSP(gl_Position); +} + diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/deferredClearGBufferP.glsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/deferredClearGBufferP.glsl new file mode 100644 index 000000000..b58f347bb --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/deferredClearGBufferP.glsl @@ -0,0 +1,40 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +out vec4 OUT_col; +out vec4 OUT_col1; +out vec4 OUT_col2; + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +void main() +{ + // Clear Deferred Buffer ( Normals/Depth ); + OUT_col = vec4(1.0, 1.0, 1.0, 1.0); + + // Clear Color Buffer. + OUT_col1 = vec4(0.0, 0.0, 0.0, 1.0); + + // Clear Material Info Buffer. + OUT_col2 = vec4(0.0, 0.0, 0.0, 1.0); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/deferredColorShaderP.glsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/deferredColorShaderP.glsl new file mode 100644 index 000000000..85c553089 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/deferredColorShaderP.glsl @@ -0,0 +1,37 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +layout (location = 0) out vec4 col; +layout (location = 1) out vec4 col1; +layout (location = 2) out vec4 col2; + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +void main() +{ + col = vec4(0.0, 0.0, 0.0, 0.0); + col1 = vec4(1.0, 1.0, 1.0, 1.0); + + // Draw on color buffer. + col2 = vec4(1.0, 0.0, 0.0, 1.0); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/deferredShadingP.glsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/deferredShadingP.glsl new file mode 100644 index 000000000..0234d5fd1 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/deferredShadingP.glsl @@ -0,0 +1,59 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" +#include "shadergen:/autogenConditioners.h" +#include "../../../postFx/gl/postFX.glsl" +#include "../../../gl/torque.glsl" + +uniform sampler2D colorBufferTex; +uniform sampler2D lightDeferredTex; +uniform sampler2D matInfoTex; +uniform sampler2D deferredTex; + +out vec4 OUT_col; + +void main() +{ + float depth = deferredUncondition( deferredTex, uv0 ).w; + if (depth>0.9999) + { + OUT_col = vec4(0.0); + return; + } + vec4 lightBuffer = texture( lightDeferredTex, uv0 ); + vec4 colorBuffer = texture( colorBufferTex, uv0 ); + vec4 matInfo = texture( matInfoTex, uv0 ); + float specular = clamp(lightBuffer.a,0.0,1.0); + + // Diffuse Color Altered by Metalness + bool metalness = getFlag(matInfo.r, 3); + if ( metalness ) + { + colorBuffer *= (1.0 - colorBuffer.a); + } + + colorBuffer += vec4(specular, specular, specular, 1.0); + colorBuffer *= vec4(lightBuffer.rgb, 1.0); + + OUT_col = hdrEncode( vec4(colorBuffer.rgb, 1.0) ); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/farFrustumQuad.glsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/farFrustumQuad.glsl new file mode 100644 index 000000000..76054eb09 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/farFrustumQuad.glsl @@ -0,0 +1,30 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + + +vec2 getUVFromSSPos( vec3 ssPos, vec4 rtParams ) +{ + vec2 outPos = ( ssPos.xy + 1.0 ) / 2.0; + outPos.y = 1.0 - outPos.y; + outPos = ( outPos * rtParams.zw ) + rtParams.xy; + return outPos; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/farFrustumQuadV.glsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/farFrustumQuadV.glsl new file mode 100644 index 000000000..a80e856ed --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/farFrustumQuadV.glsl @@ -0,0 +1,51 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" +#include "farFrustumQuad.glsl" + +in vec4 vPosition; +in vec3 vNormal; +in vec3 vTangent; +in vec2 vTexCoord0; + +uniform vec4 rtParams0; +out vec4 hpos; +out vec2 uv0; +out vec3 wsEyeRay; +out vec3 vsEyeRay; + +void main() +{ + hpos = vec4( vTexCoord0, 0, 1 ); + + // Get a RT-corrected UV from the SS coord + uv0 = getUVFromSSPos( hpos.xyz, rtParams0 ); + gl_Position = hpos; + + // Interpolators will generate eye rays the + // from far-frustum corners. + wsEyeRay = vTangent; + vsEyeRay = vNormal; + + correctSSP(gl_Position); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/lightingUtils.glsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/lightingUtils.glsl new file mode 100644 index 000000000..08af9231b --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/lightingUtils.glsl @@ -0,0 +1,79 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + + +float attenuate( vec4 lightColor, vec2 attParams, float dist ) +{ + // We're summing the results of a scaled constant, + // linear, and quadratic attenuation. + + #ifdef ACCUMULATE_LUV + return lightColor.w * ( 1.0 - dot( attParams, vec2( dist, dist * dist ) ) ); + #else + return 1.0 - dot( attParams, vec2( dist, dist * dist ) ); + #endif +} + +// Calculate the specular coefficent +// +// pxlToLight - Normalized vector representing direction from the pixel being lit, to the light source, in world space +// normal - Normalized surface normal +// pxlToEye - Normalized vector representing direction from pixel being lit, to the camera, in world space +// specPwr - Specular exponent +// specularScale - A scalar on the specular output used in RGB accumulation. +// +float calcSpecular( vec3 pxlToLight, vec3 normal, vec3 pxlToEye, float specPwr, float specularScale ) +{ +#ifdef PHONG_SPECULAR + // (R.V)^c + float specVal = dot( normalize( -reflect( pxlToLight, normal ) ), pxlToEye ); +#else + // (N.H)^c [Blinn-Phong, TGEA style, default] + float specVal = dot( normal, normalize( pxlToLight + pxlToEye ) ); +#endif + +#ifdef ACCUMULATE_LUV + return pow( max( specVal, 0.00001f ), specPwr ); +#else + // If this is RGB accumulation, than there is no facility for the luminance + // of the light to play in to the specular intensity. In LUV, the luminance + // of the light color gets rolled into N.L * Attenuation + return specularScale * pow( max( specVal, 0.00001f ), specPwr ); +#endif +} + +vec3 getDistanceVectorToPlane( vec3 origin, vec3 direction, vec4 plane ) +{ + float denum = dot( plane.xyz, direction.xyz ); + float num = dot( plane, vec4( origin, 1.0 ) ); + float t = -num / denum; + + return direction.xyz * t; +} + +vec3 getDistanceVectorToPlane( float negFarPlaneDotEye, vec3 direction, vec4 plane ) +{ + float denum = dot( plane.xyz, direction.xyz ); + float t = negFarPlaneDotEye / denum; + + return direction.xyz * t; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/pointLightP.glsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/pointLightP.glsl new file mode 100644 index 000000000..80869de25 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/pointLightP.glsl @@ -0,0 +1,273 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" +#include "shadergen:/autogenConditioners.h" + +#include "farFrustumQuad.glsl" +#include "lightingUtils.glsl" +#include "../../../gl/lighting.glsl" +#include "../../shadowMap/shadowMapIO_GLSL.h" +#include "softShadow.glsl" +#include "../../../gl/torque.glsl" + +in vec4 wsEyeDir; +in vec4 ssPos; +in vec4 vsEyeDir; +in vec4 color; + +#ifdef USE_COOKIE_TEX + +/// The texture for cookie rendering. +uniform samplerCube cookieMap ; + +#endif + + +#ifdef SHADOW_CUBE + + vec3 decodeShadowCoord( vec3 shadowCoord ) + { + return shadowCoord; + } + + vec4 shadowSample( samplerCube shadowMap, vec3 shadowCoord ) + { + return texture( shadowMap, shadowCoord ); + } + +#else + + vec3 decodeShadowCoord( vec3 paraVec ) + { + // Flip y and z + paraVec = paraVec.xzy; + + #ifndef SHADOW_PARABOLOID + + bool calcBack = (paraVec.z < 0.0); + if ( calcBack ) + { + paraVec.z = paraVec.z * -1.0; + + #ifdef SHADOW_DUALPARABOLOID + paraVec.x = -paraVec.x; + #endif + } + + #endif + + vec3 shadowCoord; + shadowCoord.x = (paraVec.x / (2*(1 + paraVec.z))) + 0.5; + shadowCoord.y = 1-((paraVec.y / (2*(1 + paraVec.z))) + 0.5); + shadowCoord.z = 0; + + // adjust the co-ordinate slightly if it is near the extent of the paraboloid + // this value was found via experementation + // NOTE: this is wrong, it only biases in one direction, not towards the uv + // center ( 0.5 0.5 ). + //shadowCoord.xy *= 0.997; + + #ifndef SHADOW_PARABOLOID + + // If this is the back, offset in the atlas + if ( calcBack ) + shadowCoord.x += 1.0; + + // Atlasing front and back maps, so scale + shadowCoord.x *= 0.5; + + #endif + + return shadowCoord; + } + +#endif + +uniform sampler2D deferredBuffer; + +#ifdef SHADOW_CUBE + uniform samplerCube shadowMap; +#else + uniform sampler2D shadowMap; + uniform sampler2D dynamicShadowMap; +#endif + +uniform sampler2D lightBuffer; +uniform sampler2D colorBuffer; +uniform sampler2D matInfoBuffer; + +uniform vec4 rtParams0; + +uniform vec3 lightPosition; +uniform vec4 lightColor; +uniform float lightBrightness; +uniform float lightRange; +uniform vec2 lightAttenuation; +uniform vec4 lightMapParams; +uniform vec4 vsFarPlane; +uniform mat3 viewToLightProj; +uniform mat3 dynamicViewToLightProj; +uniform vec4 lightParams; +uniform float shadowSoftness; + +out vec4 OUT_col; + +void main() +{ + // Compute scene UV + vec3 ssPos = ssPos.xyz / ssPos.w; + vec2 uvScene = getUVFromSSPos( ssPos, rtParams0 ); + + // Emissive. + vec4 matInfo = texture( matInfoBuffer, uvScene ); + bool emissive = getFlag( matInfo.r, 0 ); + if ( emissive ) + { + OUT_col = vec4(0.0, 0.0, 0.0, 0.0); + return; + } + + vec4 colorSample = texture( colorBuffer, uvScene ); + vec3 subsurface = vec3(0.0,0.0,0.0); + if (getFlag( matInfo.r, 1 )) + { + subsurface = colorSample.rgb; + if (colorSample.r>colorSample.g) + subsurface = vec3(0.772549, 0.337255, 0.262745); + else + subsurface = vec3(0.337255, 0.772549, 0.262745); + } + + // Sample/unpack the normal/z data + vec4 deferredSample = deferredUncondition( deferredBuffer, uvScene ); + vec3 normal = deferredSample.rgb; + float depth = deferredSample.a; + + // Eye ray - Eye -> Pixel + vec3 eyeRay = getDistanceVectorToPlane( -vsFarPlane.w, vsEyeDir.xyz, vsFarPlane ); + vec3 viewSpacePos = eyeRay * depth; + + // Build light vec, get length, clip pixel if needed + vec3 lightVec = lightPosition - viewSpacePos; + float lenLightV = length( lightVec ); + clip( lightRange - lenLightV ); + + // Get the attenuated falloff. + float atten = attenuate( lightColor, lightAttenuation, lenLightV ); + clip( atten - 1e-6 ); + + // Normalize lightVec + lightVec /= lenLightV; + + // If we can do dynamic branching then avoid wasting + // fillrate on pixels that are backfacing to the light. + float nDotL = dot( lightVec, normal ); + //DB_CLIP( nDotL < 0 ); + + #ifdef NO_SHADOW + + float shadowed = 1.0; + + #else + + // Get a linear depth from the light source. + float distToLight = lenLightV / lightRange; + + #ifdef SHADOW_CUBE + + // TODO: We need to fix shadow cube to handle soft shadows! + float occ = texture( shadowMap, tMul( viewToLightProj, -lightVec ) ).r; + float shadowed = saturate( exp( lightParams.y * ( occ - distToLight ) ) ); + + #else + + vec2 shadowCoord = decodeShadowCoord( tMul( viewToLightProj, -lightVec ) ).xy; + + float static_shadowed = softShadow_filter( shadowMap, + ssPos.xy, + shadowCoord, + shadowSoftness, + distToLight, + nDotL, + lightParams.y ); + + vec2 dynamicShadowCoord = decodeShadowCoord( tMul( dynamicViewToLightProj, -lightVec ) ).xy; + float dynamic_shadowed = softShadow_filter( dynamicShadowMap, + ssPos.xy, + dynamicShadowCoord, + shadowSoftness, + distToLight, + nDotL, + lightParams.y ); + + float shadowed = min(static_shadowed, dynamic_shadowed); + #endif + + #endif // !NO_SHADOW + + vec3 lightcol = lightColor.rgb; + #ifdef USE_COOKIE_TEX + + // Lookup the cookie sample. + vec4 cookie = texture( cookieMap, tMul( viewToLightProj, -lightVec ) ); + + // Multiply the light with the cookie tex. + lightcol *= cookie.rgb; + + // Use a maximum channel luminance to attenuate + // the lighting else we get specular in the dark + // regions of the cookie texture. + atten *= max( cookie.r, max( cookie.g, cookie.b ) ); + + #endif + + // NOTE: Do not clip on fully shadowed pixels as it would + // cause the hardware occlusion query to disable the shadow. + + // Specular term + float specular = AL_CalcSpecular( lightVec, + normal, + normalize( -eyeRay ) ) * lightBrightness * atten * shadowed; + + float Sat_NL_Att = saturate( nDotL * atten * shadowed ) * lightBrightness; + vec3 lightColorOut = lightMapParams.rgb * lightcol; + vec4 addToResult = vec4(0.0); + + // TODO: This needs to be removed when lightmapping is disabled + // as its extra work per-pixel on dynamic lit scenes. + // + // Special lightmapping pass. + if ( lightMapParams.a < 0.0 ) + { + // This disables shadows on the backsides of objects. + shadowed = nDotL < 0.0f ? 1.0f : shadowed; + + Sat_NL_Att = 1.0f; + shadowed = mix( 1.0f, shadowed, atten ); + lightColorOut = vec3(shadowed); + specular *= lightBrightness; + addToResult = ( 1.0 - shadowed ) * abs(lightMapParams); + } + + OUT_col = AL_DeferredOutput(lightColorOut+subsurface*(1.0-Sat_NL_Att), colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/softShadow.glsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/softShadow.glsl new file mode 100644 index 000000000..a14213946 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/softShadow.glsl @@ -0,0 +1,159 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + + +#if defined( SOFTSHADOW ) && defined( SOFTSHADOW_HIGH_QUALITY ) + +#define NUM_PRE_TAPS 4 +#define NUM_TAPS 12 + +/// The non-uniform poisson disk used in the +/// high quality shadow filtering. +vec2 sNonUniformTaps[NUM_TAPS] = vec2[] +( + // These first 4 taps are located around the edges + // of the disk and are used to predict fully shadowed + // or unshadowed areas. + vec2( 0.992833, 0.979309 ), + vec2( -0.998585, 0.985853 ), + vec2( 0.949299, -0.882562 ), + vec2( -0.941358, -0.893924 ), + + // The rest of the samples. + vec2( 0.545055, -0.589072 ), + vec2( 0.346526, 0.385821 ), + vec2( -0.260183, 0.334412 ), + vec2( 0.248676, -0.679605 ), + vec2( -0.569502, -0.390637 ), + vec2( -0.614096, 0.212577 ), + vec2( -0.259178, 0.876272 ), + vec2( 0.649526, 0.864333 ) +); + +#else + +#define NUM_PRE_TAPS 5 + +/// The non-uniform poisson disk used in the +/// high quality shadow filtering. +vec2 sNonUniformTaps[NUM_PRE_TAPS] = vec2[] +( + vec2( 0.892833, 0.959309 ), + vec2( -0.941358, -0.873924 ), + vec2( -0.260183, 0.334412 ), + vec2( 0.348676, -0.679605 ), + vec2( -0.569502, -0.390637 ) +); + +#endif + + +/// The texture used to do per-pixel pseudorandom +/// rotations of the filter taps. +uniform sampler2D gTapRotationTex ; + + +float softShadow_sampleTaps( sampler2D shadowMap, + vec2 sinCos, + vec2 shadowPos, + float filterRadius, + float distToLight, + float esmFactor, + int startTap, + int endTap ) +{ + float shadow = 0; + + vec2 tap = vec2(0); + for ( int t = startTap; t < endTap; t++ ) + { + tap.x = ( sNonUniformTaps[t].x * sinCos.y - sNonUniformTaps[t].y * sinCos.x ) * filterRadius; + tap.y = ( sNonUniformTaps[t].y * sinCos.y + sNonUniformTaps[t].x * sinCos.x ) * filterRadius; + float occluder = tex2Dlod( shadowMap, vec4( shadowPos + tap, 0, 0 ) ).r; + + float esm = saturate( exp( esmFactor * ( occluder - distToLight ) ) ); + shadow += esm / float( endTap - startTap ); + } + + return shadow; +} + + +float softShadow_filter( sampler2D shadowMap, + vec2 vpos, + vec2 shadowPos, + float filterRadius, + float distToLight, + float dotNL, + float esmFactor ) +{ + #ifndef SOFTSHADOW + + // If softshadow is undefined then we skip any complex + // filtering... just do a single sample ESM. + + float occluder = tex2Dlod( shadowMap, vec4( shadowPos, 0, 0 ) ).r; + float shadow = saturate( exp( esmFactor * ( occluder - distToLight ) ) ); + + #else + + // Lookup the random rotation for this screen pixel. + vec2 sinCos = ( tex2Dlod( gTapRotationTex, vec4( vpos * 16, 0, 0 ) ).rg - 0.5 ) * 2; + + // Do the prediction taps first. + float shadow = softShadow_sampleTaps( shadowMap, + sinCos, + shadowPos, + filterRadius, + distToLight, + esmFactor, + 0, + NUM_PRE_TAPS ); + + // We live with only the pretap results if we don't + // have high quality shadow filtering enabled. + #ifdef SOFTSHADOW_HIGH_QUALITY + + // Only do the expensive filtering if we're really + // in a partially shadowed area. + if ( shadow * ( 1.0 - shadow ) * max( dotNL, 0 ) > 0.06 ) + { + shadow += softShadow_sampleTaps( shadowMap, + sinCos, + shadowPos, + filterRadius, + distToLight, + esmFactor, + NUM_PRE_TAPS, + NUM_TAPS ); + + // This averages the taps above with the results + // of the prediction samples. + shadow *= 0.5; + } + + #endif // SOFTSHADOW_HIGH_QUALITY + + #endif // SOFTSHADOW + + return shadow; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/spotLightP.glsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/spotLightP.glsl new file mode 100644 index 000000000..5fcf1b19c --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/spotLightP.glsl @@ -0,0 +1,210 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" +#include "farFrustumQuad.glsl" +#include "lightingUtils.glsl" +#include "../../shadowMap/shadowMapIO_GLSL.h" +#include "shadergen:/autogenConditioners.h" +#include "softShadow.glsl" +#include "../../../gl/lighting.glsl" +#include "../../../gl/torque.glsl" + +in vec4 wsEyeDir; +in vec4 ssPos; +in vec4 vsEyeDir; +in vec4 color; + +#define IN_wsEyeDir wsEyeDir +#define IN_ssPos ssPos +#define IN_vsEyeDir vsEyeDir +#define IN_color color + +#ifdef USE_COOKIE_TEX + +/// The texture for cookie rendering. +uniform sampler2D cookieMap; + +#endif + +uniform sampler2D deferredBuffer; +uniform sampler2D shadowMap; +uniform sampler2D dynamicShadowMap; + +uniform sampler2D lightBuffer; +uniform sampler2D colorBuffer; +uniform sampler2D matInfoBuffer; + +uniform vec4 rtParams0; + +uniform vec3 lightPosition; +uniform vec4 lightColor; +uniform float lightBrightness; +uniform float lightRange; +uniform vec2 lightAttenuation; +uniform vec3 lightDirection; +uniform vec4 lightSpotParams; +uniform vec4 lightMapParams; + +uniform vec4 vsFarPlane; +uniform mat4 viewToLightProj; +uniform mat4 dynamicViewToLightProj; + +uniform vec4 lightParams; +uniform float shadowSoftness; + +out vec4 OUT_col; + +void main() +{ + // Compute scene UV + vec3 ssPos = IN_ssPos.xyz / IN_ssPos.w; + vec2 uvScene = getUVFromSSPos( ssPos, rtParams0 ); + + // Emissive. + vec4 matInfo = texture( matInfoBuffer, uvScene ); + bool emissive = getFlag( matInfo.r, 0 ); + if ( emissive ) + { + OUT_col = vec4(0.0, 0.0, 0.0, 0.0); + return; + } + + vec4 colorSample = texture( colorBuffer, uvScene ); + vec3 subsurface = vec3(0.0,0.0,0.0); + if (getFlag( matInfo.r, 1 )) + { + subsurface = colorSample.rgb; + if (colorSample.r>colorSample.g) + subsurface = vec3(0.772549, 0.337255, 0.262745); + else + subsurface = vec3(0.337255, 0.772549, 0.262745); + } + + // Sample/unpack the normal/z data + vec4 deferredSample = deferredUncondition( deferredBuffer, uvScene ); + vec3 normal = deferredSample.rgb; + float depth = deferredSample.a; + + // Eye ray - Eye -> Pixel + vec3 eyeRay = getDistanceVectorToPlane( -vsFarPlane.w, IN_vsEyeDir.xyz, vsFarPlane ); + vec3 viewSpacePos = eyeRay * depth; + + // Build light vec, get length, clip pixel if needed + vec3 lightToPxlVec = viewSpacePos - lightPosition; + float lenLightV = length( lightToPxlVec ); + lightToPxlVec /= lenLightV; + + //lightDirection = vec3( -lightDirection.xy, lightDirection.z ); //vec3( 0, 0, -1 ); + float cosAlpha = dot( lightDirection, lightToPxlVec ); + clip( cosAlpha - lightSpotParams.x ); + clip( lightRange - lenLightV ); + + float atten = attenuate( lightColor, lightAttenuation, lenLightV ); + atten *= ( cosAlpha - lightSpotParams.x ) / lightSpotParams.y; + clip( atten - 1e-6 ); + atten = saturate( atten ); + + float nDotL = dot( normal, -lightToPxlVec ); + + // Get the shadow texture coordinate + vec4 pxlPosLightProj = tMul( viewToLightProj, vec4( viewSpacePos, 1 ) ); + vec2 shadowCoord = ( ( pxlPosLightProj.xy / pxlPosLightProj.w ) * 0.5 ) + vec2( 0.5, 0.5 ); + shadowCoord.y = 1.0f - shadowCoord.y; + + // Get the dynamic shadow texture coordinate + vec4 dynpxlPosLightProj = tMul( dynamicViewToLightProj, vec4( viewSpacePos, 1 ) ); + vec2 dynshadowCoord = ( ( dynpxlPosLightProj.xy / dynpxlPosLightProj.w ) * 0.5 ) + vec2( 0.5, 0.5 ); + dynshadowCoord.y = 1.0f - dynshadowCoord.y; + #ifdef NO_SHADOW + + float shadowed = 1.0; + + #else + + // Get a linear depth from the light source. + float distToLight = pxlPosLightProj.z / lightRange; + + float static_shadowed = softShadow_filter( shadowMap, + ssPos.xy, + shadowCoord, + shadowSoftness, + distToLight, + nDotL, + lightParams.y ); + + float dynamic_shadowed = softShadow_filter( dynamicShadowMap, + ssPos.xy, + dynshadowCoord, + shadowSoftness, + distToLight, + nDotL, + lightParams.y ); + float shadowed = min(static_shadowed, dynamic_shadowed); + #endif // !NO_SHADOW + + vec3 lightcol = lightColor.rgb; + #ifdef USE_COOKIE_TEX + + // Lookup the cookie sample. + vec4 cookie = texture( cookieMap, shadowCoord ); + + // Multiply the light with the cookie tex. + lightcol *= cookie.rgb; + + // Use a maximum channel luminance to attenuate + // the lighting else we get specular in the dark + // regions of the cookie texture. + atten *= max( cookie.r, max( cookie.g, cookie.b ) ); + + #endif + + // NOTE: Do not clip on fully shadowed pixels as it would + // cause the hardware occlusion query to disable the shadow. + + // Specular term + float specular = AL_CalcSpecular( -lightToPxlVec, + normal, + normalize( -eyeRay ) ) * lightBrightness * atten * shadowed; + + float Sat_NL_Att = saturate( nDotL * atten * shadowed ) * lightBrightness; + vec3 lightColorOut = lightMapParams.rgb * lightcol; + vec4 addToResult = vec4(0.0); + + // TODO: This needs to be removed when lightmapping is disabled + // as its extra work per-pixel on dynamic lit scenes. + // + // Special lightmapping pass. + if ( lightMapParams.a < 0.0 ) + { + // This disables shadows on the backsides of objects. + shadowed = nDotL < 0.0f ? 1.0f : shadowed; + + Sat_NL_Att = 1.0f; + shadowed = mix( 1.0f, shadowed, atten ); + lightColorOut = vec3(shadowed); + specular *= lightBrightness; + addToResult = ( 1.0 - shadowed ) * abs(lightMapParams); + } + + OUT_col = AL_DeferredOutput(lightColorOut+subsurface*(1.0-Sat_NL_Att), colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/vectorLightP.glsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/vectorLightP.glsl new file mode 100644 index 000000000..142e58b10 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/vectorLightP.glsl @@ -0,0 +1,327 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" +#include "shadergen:/autogenConditioners.h" +#include "farFrustumQuad.glsl" +#include "../../../gl/torque.glsl" +#include "../../../gl/lighting.glsl" +#include "lightingUtils.glsl" +#include "../../shadowMap/shadowMapIO_GLSL.h" +#include "softShadow.glsl" + +in vec4 hpos; +in vec2 uv0; +in vec3 wsEyeRay; +in vec3 vsEyeRay; + +uniform sampler2D shadowMap; +uniform sampler2D dynamicShadowMap; + +#ifdef USE_SSAO_MASK +uniform sampler2D ssaoMask ; +uniform vec4 rtParams3; +#endif + +uniform sampler2D deferredBuffer; +uniform sampler2D lightBuffer; +uniform sampler2D colorBuffer; +uniform sampler2D matInfoBuffer; +uniform vec3 lightDirection; +uniform vec4 lightColor; +uniform float lightBrightness; +uniform vec4 lightAmbient; +uniform vec3 eyePosWorld; +uniform mat4x4 eyeMat; +uniform vec4 atlasXOffset; +uniform vec4 atlasYOffset; +uniform vec2 atlasScale; +uniform vec4 zNearFarInvNearFar; +uniform vec4 lightMapParams; +uniform vec2 fadeStartLength; +uniform vec4 overDarkPSSM; +uniform float shadowSoftness; + +//static shadowMap +uniform mat4x4 worldToLightProj; +uniform vec4 scaleX; +uniform vec4 scaleY; +uniform vec4 offsetX; +uniform vec4 offsetY; +uniform vec4 farPlaneScalePSSM; + +//dynamic shadowMap +uniform mat4x4 dynamicWorldToLightProj; +uniform vec4 dynamicScaleX; +uniform vec4 dynamicScaleY; +uniform vec4 dynamicOffsetX; +uniform vec4 dynamicOffsetY; +uniform vec4 dynamicFarPlaneScalePSSM; + +vec4 AL_VectorLightShadowCast( sampler2D _sourceshadowMap, + vec2 _texCoord, + mat4 _worldToLightProj, + vec4 _worldPos, + vec4 _scaleX, vec4 _scaleY, + vec4 _offsetX, vec4 _offsetY, + vec4 _farPlaneScalePSSM, + vec4 _atlasXOffset, vec4 _atlasYOffset, + vec2 _atlasScale, + float _shadowSoftness, + float _dotNL , + vec4 _overDarkPSSM +) +{ + + // Compute shadow map coordinate + vec4 pxlPosLightProj = tMul(_worldToLightProj, _worldPos); + vec2 baseShadowCoord = pxlPosLightProj.xy / pxlPosLightProj.w; + + // Distance to light, in shadowMap space + float distToLight = pxlPosLightProj.z / pxlPosLightProj.w; + + // Figure out which split to sample from. Basically, we compute the shadowMap sample coord + // for all of the splits and then check if its valid. + vec4 shadowCoordX = vec4( baseShadowCoord.x ); + vec4 shadowCoordY = vec4( baseShadowCoord.y ); + vec4 farPlaneDists = vec4( distToLight ); + shadowCoordX *= _scaleX; + shadowCoordY *= _scaleY; + shadowCoordX += _offsetX; + shadowCoordY += _offsetY; + farPlaneDists *= _farPlaneScalePSSM; + + // If the shadow sample is within -1..1 and the distance + // to the light for this pixel is less than the far plane + // of the split, use it. + vec4 finalMask; + if ( shadowCoordX.x > -0.99 && shadowCoordX.x < 0.99 && + shadowCoordY.x > -0.99 && shadowCoordY.x < 0.99 && + farPlaneDists.x < 1.0 ) + finalMask = vec4(1, 0, 0, 0); + + else if ( shadowCoordX.y > -0.99 && shadowCoordX.y < 0.99 && + shadowCoordY.y > -0.99 && shadowCoordY.y < 0.99 && + farPlaneDists.y < 1.0 ) + finalMask = vec4(0, 1, 0, 0); + + else if ( shadowCoordX.z > -0.99 && shadowCoordX.z < 0.99 && + shadowCoordY.z > -0.99 && shadowCoordY.z < 0.99 && + farPlaneDists.z < 1.0 ) + finalMask = vec4(0, 0, 1, 0); + + else + finalMask = vec4(0, 0, 0, 1); + + vec3 debugColor = vec3(0); + + #ifdef NO_SHADOW + debugColor = vec3(1.0); + #endif + + #ifdef PSSM_DEBUG_RENDER + if ( finalMask.x > 0 ) + debugColor += vec3( 1, 0, 0 ); + else if ( finalMask.y > 0 ) + debugColor += vec3( 0, 1, 0 ); + else if ( finalMask.z > 0 ) + debugColor += vec3( 0, 0, 1 ); + else if ( finalMask.w > 0 ) + debugColor += vec3( 1, 1, 0 ); + #endif + + // Here we know what split we're sampling from, so recompute the _texCoord location + // Yes, we could just use the result from above, but doing it this way actually saves + // shader instructions. + vec2 finalScale; + finalScale.x = dot(finalMask, _scaleX); + finalScale.y = dot(finalMask, _scaleY); + + vec2 finalOffset; + finalOffset.x = dot(finalMask, _offsetX); + finalOffset.y = dot(finalMask, _offsetY); + + vec2 shadowCoord; + shadowCoord = baseShadowCoord * finalScale; + shadowCoord += finalOffset; + + // Convert to _texCoord space + shadowCoord = 0.5 * shadowCoord + vec2(0.5, 0.5); + shadowCoord.y = 1.0f - shadowCoord.y; + + // Move around inside of atlas + vec2 aOffset; + aOffset.x = dot(finalMask, _atlasXOffset); + aOffset.y = dot(finalMask, _atlasYOffset); + + shadowCoord *= _atlasScale; + shadowCoord += aOffset; + + // Each split has a different far plane, take this into account. + float farPlaneScale = dot( _farPlaneScalePSSM, finalMask ); + distToLight *= farPlaneScale; + + return vec4(debugColor, + softShadow_filter( _sourceshadowMap, + _texCoord, + shadowCoord, + farPlaneScale * _shadowSoftness, + distToLight, + _dotNL, + dot( finalMask, _overDarkPSSM ) ) ); +} + +out vec4 OUT_col; +void main() +{ + // Emissive. + float4 matInfo = texture( matInfoBuffer, uv0 ); + bool emissive = getFlag( matInfo.r, 0 ); + if ( emissive ) + { + OUT_col = vec4(1.0, 1.0, 1.0, 0.0); + return; + } + + vec4 colorSample = texture( colorBuffer, uv0 ); + vec3 subsurface = vec3(0.0,0.0,0.0); + if (getFlag( matInfo.r, 1 )) + { + subsurface = colorSample.rgb; + if (colorSample.r>colorSample.g) + subsurface = vec3(0.772549, 0.337255, 0.262745); + else + subsurface = vec3(0.337255, 0.772549, 0.262745); + } + + // Sample/unpack the normal/z data + vec4 deferredSample = deferredUncondition( deferredBuffer, uv0 ); + vec3 normal = deferredSample.rgb; + float depth = deferredSample.a; + + // Use eye ray to get ws pos + vec4 worldPos = vec4(eyePosWorld + wsEyeRay * depth, 1.0f); + + // Get the light attenuation. + float dotNL = dot(-lightDirection, normal); + + #ifdef PSSM_DEBUG_RENDER + vec3 debugColor = vec3(0); + #endif + + #ifdef NO_SHADOW + + // Fully unshadowed. + float shadowed = 1.0; + + #ifdef PSSM_DEBUG_RENDER + debugColor = vec3(1.0); + #endif + + #else + + vec4 static_shadowed_colors = AL_VectorLightShadowCast( shadowMap, + uv0.xy, + worldToLightProj, + worldPos, + scaleX, scaleY, + offsetX, offsetY, + farPlaneScalePSSM, + atlasXOffset, atlasYOffset, + atlasScale, + shadowSoftness, + dotNL, + overDarkPSSM); + vec4 dynamic_shadowed_colors = AL_VectorLightShadowCast( dynamicShadowMap, + uv0.xy, + dynamicWorldToLightProj, + worldPos, + dynamicScaleX, dynamicScaleY, + dynamicOffsetX, dynamicOffsetY, + dynamicFarPlaneScalePSSM, + atlasXOffset, atlasYOffset, + atlasScale, + shadowSoftness, + dotNL, + overDarkPSSM); + float static_shadowed = static_shadowed_colors.a; + float dynamic_shadowed = dynamic_shadowed_colors.a; + + #ifdef PSSM_DEBUG_RENDER + debugColor = static_shadowed_colors.rgb*0.5+dynamic_shadowed_colors.rgb*0.5; + #endif + + // Fade out the shadow at the end of the range. + vec4 zDist = vec4(zNearFarInvNearFar.x + zNearFarInvNearFar.y * depth); + float fadeOutAmt = ( zDist.x - fadeStartLength.x ) * fadeStartLength.y; + + static_shadowed = mix( static_shadowed, 1.0, saturate( fadeOutAmt ) ); + dynamic_shadowed = mix( dynamic_shadowed, 1.0, saturate( fadeOutAmt ) ); + + // temp for debugging. uncomment one or the other. + //float shadowed = static_shadowed; + //float shadowed = dynamic_shadowed; + float shadowed = min(static_shadowed, dynamic_shadowed); + + #ifdef PSSM_DEBUG_RENDER + if ( fadeOutAmt > 1.0 ) + debugColor = vec3(1.0); + #endif + + #endif // !NO_SHADOW + + // Specular term + float specular = AL_CalcSpecular( -lightDirection, + normal, + normalize(-vsEyeRay) ) * lightBrightness * shadowed; + + float Sat_NL_Att = saturate( dotNL * shadowed ) * lightBrightness; + vec3 lightColorOut = lightMapParams.rgb * lightColor.rgb; + vec4 addToResult = (lightAmbient * (1 - ambientCameraFactor)) + ( lightAmbient * ambientCameraFactor * saturate(dot(normalize(-vsEyeRay), normal)) ); + + // TODO: This needs to be removed when lightmapping is disabled + // as its extra work per-pixel on dynamic lit scenes. + // + // Special lightmapping pass. + if ( lightMapParams.a < 0.0 ) + { + // This disables shadows on the backsides of objects. + shadowed = dotNL < 0.0f ? 1.0f : shadowed; + + Sat_NL_Att = 1.0f; + lightColorOut = vec3(shadowed); + specular *= lightBrightness; + addToResult = ( 1.0 - shadowed ) * abs(lightMapParams); + } + + // Sample the AO texture. + #ifdef USE_SSAO_MASK + float ao = 1.0 - texture( ssaoMask, viewportCoordToRenderTarget( uv0.xy, rtParams3 ) ).r; + addToResult *= ao; + #endif + + #ifdef PSSM_DEBUG_RENDER + lightColorOut = debugColor; + #endif + + OUT_col = AL_DeferredOutput(lightColorOut+subsurface*(1.0-Sat_NL_Att), colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/lightingUtils.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/lightingUtils.hlsl new file mode 100644 index 000000000..2bff18999 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/lightingUtils.hlsl @@ -0,0 +1,51 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + + +float attenuate( float4 lightColor, float2 attParams, float dist ) +{ + // We're summing the results of a scaled constant, + // linear, and quadratic attenuation. + + #ifdef ACCUMULATE_LUV + return lightColor.w * ( 1.0 - dot( attParams, float2( dist, dist * dist ) ) ); + #else + return 1.0 - dot( attParams, float2( dist, dist * dist ) ); + #endif +} + +float3 getDistanceVectorToPlane( float3 origin, float3 direction, float4 plane ) +{ + float denum = dot( plane.xyz, direction.xyz ); + float num = dot( plane, float4( origin, 1.0 ) ); + float t = -num / denum; + + return direction.xyz * t; +} + +float3 getDistanceVectorToPlane( float negFarPlaneDotEye, float3 direction, float4 plane ) +{ + float denum = dot( plane.xyz, direction.xyz ); + float t = negFarPlaneDotEye / denum; + + return direction.xyz * t; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/particlePointLightP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/particlePointLightP.hlsl new file mode 100644 index 000000000..a0156eb85 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/particlePointLightP.hlsl @@ -0,0 +1,76 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "farFrustumQuad.hlsl" +#include "lightingUtils.hlsl" +#include "../../lighting.hlsl" +#include "../../shaderModel.hlsl" +#include "../../shaderModelAutoGen.hlsl" + + +struct ConvexConnectP +{ + float4 pos : TORQUE_POSITION; + float4 ssPos : TEXCOORD0; + float3 vsEyeDir : TEXCOORD1; +}; + +TORQUE_UNIFORM_SAMPLER2D(deferredBuffer, 0); + +uniform float4 lightPosition; +uniform float4 lightColor; +uniform float lightRange; +uniform float4 vsFarPlane; +uniform float4 rtParams0; + +float4 main( ConvexConnectP IN ) : TORQUE_TARGET0 +{ + // Compute scene UV + float3 ssPos = IN.ssPos.xyz / IN.ssPos.w; + float2 uvScene = getUVFromSSPos(ssPos, rtParams0); + + // Sample/unpack the normal/z data + float4 deferredSample = TORQUE_DEFERRED_UNCONDITION(deferredBuffer, uvScene); + float3 normal = deferredSample.rgb; + float depth = deferredSample.a; + + // Eye ray - Eye -> Pixel + float3 eyeRay = getDistanceVectorToPlane(-vsFarPlane.w, IN.vsEyeDir, vsFarPlane); + float3 viewSpacePos = eyeRay * depth; + + // Build light vec, get length, clip pixel if needed + float3 lightVec = lightPosition.xyz - viewSpacePos; + float lenLightV = length(lightVec); + clip(lightRange - lenLightV); + + // Do a very simple falloff instead of real attenuation + float atten = 1.0 - saturate(lenLightV / lightRange); + + // Normalize lightVec + lightVec /= lenLightV; + + // N.L * Attenuation + float Sat_NL_Att = saturate(dot(lightVec, normal)) * atten; + + // Output, no specular + return lightinfoCondition(lightColor.rgb, Sat_NL_Att, 0.0, 0.0); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/particlePointLightV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/particlePointLightV.hlsl new file mode 100644 index 000000000..faa2ec115 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/particlePointLightV.hlsl @@ -0,0 +1,48 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../hlslStructs.hlsl" +#include "../../shaderModel.hlsl" + +struct ConvexConnectV +{ + float4 hpos : TORQUE_POSITION; + float4 ssPos : TEXCOORD0; + float3 vsEyeDir : TEXCOORD1; +}; + +uniform float4x4 viewProj; +uniform float4x4 view; +uniform float3 particlePosWorld; +uniform float lightRange; + +ConvexConnectV main( VertexIn_P IN ) +{ + ConvexConnectV OUT; + float4 pos = float4(IN.pos, 0.0); + float4 vPosWorld = pos + float4(particlePosWorld, 0.0) + pos * lightRange; + OUT.hpos = mul(viewProj, vPosWorld); + OUT.vsEyeDir = mul(view, vPosWorld); + OUT.ssPos = OUT.hpos; + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/pointLightP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/pointLightP.hlsl new file mode 100644 index 000000000..317feb0b3 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/pointLightP.hlsl @@ -0,0 +1,277 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../shaderModelAutoGen.hlsl" + +#include "farFrustumQuad.hlsl" +#include "lightingUtils.hlsl" +#include "../../lighting.hlsl" +#include "../shadowMap/shadowMapIO_HLSL.h" +#include "softShadow.hlsl" +#include "../../torque.hlsl" + +struct ConvexConnectP +{ + float4 pos : TORQUE_POSITION; + float4 wsEyeDir : TEXCOORD0; + float4 ssPos : TEXCOORD1; + float4 vsEyeDir : TEXCOORD2; +}; + + +#ifdef USE_COOKIE_TEX + +/// The texture for cookie rendering. +TORQUE_UNIFORM_SAMPLERCUBE(cookieMap, 3); + +#endif + + +#ifdef SHADOW_CUBE + + float3 decodeShadowCoord( float3 shadowCoord ) + { + return shadowCoord; + } + + float4 shadowSample( TORQUE_SAMPLERCUBE(shadowMap), float3 shadowCoord ) + { + return TORQUE_TEXCUBE( shadowMap, shadowCoord ); + } + +#else + + float3 decodeShadowCoord( float3 paraVec ) + { + // Flip y and z + paraVec = paraVec.xzy; + + #ifndef SHADOW_PARABOLOID + + bool calcBack = (paraVec.z < 0.0); + if ( calcBack ) + { + paraVec.z = paraVec.z * -1.0; + + #ifdef SHADOW_DUALPARABOLOID + paraVec.x = -paraVec.x; + #endif + } + + #endif + + float3 shadowCoord; + shadowCoord.x = (paraVec.x / (2*(1 + paraVec.z))) + 0.5; + shadowCoord.y = 1-((paraVec.y / (2*(1 + paraVec.z))) + 0.5); + shadowCoord.z = 0; + + // adjust the co-ordinate slightly if it is near the extent of the paraboloid + // this value was found via experementation + // NOTE: this is wrong, it only biases in one direction, not towards the uv + // center ( 0.5 0.5 ). + //shadowCoord.xy *= 0.997; + + #ifndef SHADOW_PARABOLOID + + // If this is the back, offset in the atlas + if ( calcBack ) + shadowCoord.x += 1.0; + + // Atlasing front and back maps, so scale + shadowCoord.x *= 0.5; + + #endif + + return shadowCoord; + } + +#endif + +TORQUE_UNIFORM_SAMPLER2D(deferredBuffer, 0); + +#ifdef SHADOW_CUBE +TORQUE_UNIFORM_SAMPLERCUBE(shadowMap, 1); +#else +TORQUE_UNIFORM_SAMPLER2D(shadowMap, 1); +TORQUE_UNIFORM_SAMPLER2D(dynamicShadowMap, 2); +#endif + +TORQUE_UNIFORM_SAMPLER2D(lightBuffer, 5); +TORQUE_UNIFORM_SAMPLER2D(colorBuffer, 6); +TORQUE_UNIFORM_SAMPLER2D(matInfoBuffer, 7); + +uniform float4 rtParams0; +uniform float4 lightColor; + +uniform float lightBrightness; +uniform float3 lightPosition; + +uniform float4 lightMapParams; +uniform float4 vsFarPlane; +uniform float4 lightParams; + +uniform float lightRange; +uniform float shadowSoftness; +uniform float2 lightAttenuation; + +uniform float3x3 viewToLightProj; +uniform float3x3 dynamicViewToLightProj; + +float4 main( ConvexConnectP IN ) : TORQUE_TARGET0 +{ + // Compute scene UV + float3 ssPos = IN.ssPos.xyz / IN.ssPos.w; + float2 uvScene = getUVFromSSPos( ssPos, rtParams0 ); + + // Emissive. + float4 matInfo = TORQUE_TEX2D( matInfoBuffer, uvScene ); + bool emissive = getFlag( matInfo.r, 0 ); + if ( emissive ) + { + return float4(0.0, 0.0, 0.0, 0.0); + } + float4 colorSample = TORQUE_TEX2D( colorBuffer, uvScene ); + float3 subsurface = float3(0.0,0.0,0.0); + if (getFlag( matInfo.r, 1 )) + { + subsurface = colorSample.rgb; + if (colorSample.r>colorSample.g) + subsurface = float3(0.772549, 0.337255, 0.262745); + else + subsurface = float3(0.337255, 0.772549, 0.262745); + } + + // Sample/unpack the normal/z data + float4 deferredSample = TORQUE_DEFERRED_UNCONDITION( deferredBuffer, uvScene ); + float3 normal = deferredSample.rgb; + float depth = deferredSample.a; + + // Eye ray - Eye -> Pixel + float3 eyeRay = getDistanceVectorToPlane( -vsFarPlane.w, IN.vsEyeDir.xyz, vsFarPlane ); + float3 viewSpacePos = eyeRay * depth; + + // Build light vec, get length, clip pixel if needed + float3 lightVec = lightPosition - viewSpacePos; + float lenLightV = length( lightVec ); + clip( lightRange - lenLightV ); + + // Get the attenuated falloff. + float atten = attenuate( lightColor, lightAttenuation, lenLightV ); + clip( atten - 1e-6 ); + + // Normalize lightVec + lightVec /= lenLightV; + + // If we can do dynamic branching then avoid wasting + // fillrate on pixels that are backfacing to the light. + float nDotL = dot( lightVec, normal ); + //DB_CLIP( nDotL < 0 ); + + #ifdef NO_SHADOW + + float shadowed = 1.0; + + #else + + // Get a linear depth from the light source. + float distToLight = lenLightV / lightRange; + + #ifdef SHADOW_CUBE + + // TODO: We need to fix shadow cube to handle soft shadows! + float occ = TORQUE_TEXCUBE( shadowMap, mul( viewToLightProj, -lightVec ) ).r; + float shadowed = saturate( exp( lightParams.y * ( occ - distToLight ) ) ); + + #else + + // Static + float2 shadowCoord = decodeShadowCoord( mul( viewToLightProj, -lightVec ) ).xy; + float static_shadowed = softShadow_filter( TORQUE_SAMPLER2D_MAKEARG(shadowMap), + ssPos.xy, + shadowCoord, + shadowSoftness, + distToLight, + nDotL, + lightParams.y ); + + // Dynamic + float2 dynamicShadowCoord = decodeShadowCoord( mul( dynamicViewToLightProj, -lightVec ) ).xy; + float dynamic_shadowed = softShadow_filter( TORQUE_SAMPLER2D_MAKEARG(dynamicShadowMap), + ssPos.xy, + dynamicShadowCoord, + shadowSoftness, + distToLight, + nDotL, + lightParams.y ); + + float shadowed = min(static_shadowed, dynamic_shadowed); + + #endif + + #endif // !NO_SHADOW + + float3 lightcol = lightColor.rgb; + #ifdef USE_COOKIE_TEX + + // Lookup the cookie sample. + float4 cookie = TORQUE_TEXCUBE( cookieMap, mul( viewToLightProj, -lightVec ) ); + + // Multiply the light with the cookie tex. + lightcol *= cookie.rgb; + + // Use a maximum channel luminance to attenuate + // the lighting else we get specular in the dark + // regions of the cookie texture. + atten *= max( cookie.r, max( cookie.g, cookie.b ) ); + + #endif + + // NOTE: Do not clip on fully shadowed pixels as it would + // cause the hardware occlusion query to disable the shadow. + + // Specular term + float specular = AL_CalcSpecular( lightVec, + normal, + normalize( -eyeRay ) ) * lightBrightness * atten * shadowed; + + float Sat_NL_Att = saturate( nDotL * atten * shadowed ) * lightBrightness; + float3 lightColorOut = lightMapParams.rgb * lightcol; + float4 addToResult = 0.0; + + // TODO: This needs to be removed when lightmapping is disabled + // as its extra work per-pixel on dynamic lit scenes. + // + // Special lightmapping pass. + if ( lightMapParams.a < 0.0 ) + { + // This disables shadows on the backsides of objects. + shadowed = nDotL < 0.0f ? 1.0f : shadowed; + + Sat_NL_Att = 1.0f; + shadowed = lerp( 1.0f, shadowed, atten ); + lightColorOut = shadowed; + specular *= lightBrightness; + addToResult = ( 1.0 - shadowed ) * abs(lightMapParams); + } + + return AL_DeferredOutput(lightColorOut+subsurface*(1.0-Sat_NL_Att), colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/softShadow.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/softShadow.hlsl new file mode 100644 index 000000000..0faf3e1fb --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/softShadow.hlsl @@ -0,0 +1,158 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../shaderModel.hlsl" + +#if defined( SOFTSHADOW ) && defined( SOFTSHADOW_HIGH_QUALITY ) + +#define NUM_PRE_TAPS 4 +#define NUM_TAPS 12 + +/// The non-uniform poisson disk used in the +/// high quality shadow filtering. +static float2 sNonUniformTaps[NUM_TAPS] = +{ + // These first 4 taps are located around the edges + // of the disk and are used to predict fully shadowed + // or unshadowed areas. + { 0.992833, 0.979309 }, + { -0.998585, 0.985853 }, + { 0.949299, -0.882562 }, + { -0.941358, -0.893924 }, + + // The rest of the samples. + { 0.545055, -0.589072 }, + { 0.346526, 0.385821 }, + { -0.260183, 0.334412 }, + { 0.248676, -0.679605 }, + { -0.569502, -0.390637 }, + { -0.614096, 0.212577 }, + { -0.259178, 0.876272 }, + { 0.649526, 0.864333 }, +}; + +#else + +#define NUM_PRE_TAPS 5 + +/// The non-uniform poisson disk used in the +/// high quality shadow filtering. +static float2 sNonUniformTaps[NUM_PRE_TAPS] = +{ + { 0.892833, 0.959309 }, + { -0.941358, -0.873924 }, + { -0.260183, 0.334412 }, + { 0.348676, -0.679605 }, + { -0.569502, -0.390637 }, +}; + +#endif + + +/// The texture used to do per-pixel pseudorandom +/// rotations of the filter taps. +TORQUE_UNIFORM_SAMPLER2D(gTapRotationTex, 4); + +float softShadow_sampleTaps( TORQUE_SAMPLER2D(shadowMap1), + float2 sinCos, + float2 shadowPos, + float filterRadius, + float distToLight, + float esmFactor, + int startTap, + int endTap ) +{ + float shadow = 0; + + float2 tap = 0; + for ( int t = startTap; t < endTap; t++ ) + { + tap.x = ( sNonUniformTaps[t].x * sinCos.y - sNonUniformTaps[t].y * sinCos.x ) * filterRadius; + tap.y = ( sNonUniformTaps[t].y * sinCos.y + sNonUniformTaps[t].x * sinCos.x ) * filterRadius; + float occluder = TORQUE_TEX2DLOD( shadowMap1, float4( shadowPos + tap, 0, 0 ) ).r; + + float esm = saturate( exp( esmFactor * ( occluder - distToLight ) ) ); + shadow += esm / float( endTap - startTap ); + } + + return shadow; +} + + +float softShadow_filter( TORQUE_SAMPLER2D(shadowMap), + float2 vpos, + float2 shadowPos, + float filterRadius, + float distToLight, + float dotNL, + float esmFactor ) +{ + #ifndef SOFTSHADOW + + // If softshadow is undefined then we skip any complex + // filtering... just do a single sample ESM. + + float occluder = TORQUE_TEX2DLOD(shadowMap, float4(shadowPos, 0, 0)).r; + float shadow = saturate( exp( esmFactor * ( occluder - distToLight ) ) ); + + #else + // Lookup the random rotation for this screen pixel. + float2 sinCos = ( TORQUE_TEX2DLOD(gTapRotationTex, float4(vpos * 16, 0, 0)).rg - 0.5) * 2; + + // Do the prediction taps first. + float shadow = softShadow_sampleTaps( TORQUE_SAMPLER2D_MAKEARG(shadowMap), + sinCos, + shadowPos, + filterRadius, + distToLight, + esmFactor, + 0, + NUM_PRE_TAPS ); + + // We live with only the pretap results if we don't + // have high quality shadow filtering enabled. + #ifdef SOFTSHADOW_HIGH_QUALITY + + // Only do the expensive filtering if we're really + // in a partially shadowed area. + if ( shadow * ( 1.0 - shadow ) * max( dotNL, 0 ) > 0.06 ) + { + shadow += softShadow_sampleTaps( TORQUE_SAMPLER2D_MAKEARG(shadowMap), + sinCos, + shadowPos, + filterRadius, + distToLight, + esmFactor, + NUM_PRE_TAPS, + NUM_TAPS ); + + // This averages the taps above with the results + // of the prediction samples. + shadow *= 0.5; + } + + #endif // SOFTSHADOW_HIGH_QUALITY + + #endif // SOFTSHADOW + + return shadow; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl new file mode 100644 index 000000000..196286dc2 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl @@ -0,0 +1,209 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../shaderModel.hlsl" +#include "../../shaderModelAutoGen.hlsl" + +#include "farFrustumQuad.hlsl" +#include "lightingUtils.hlsl" +#include "../../lighting.hlsl" +#include "../shadowMap/shadowMapIO_HLSL.h" +#include "softShadow.hlsl" +#include "../../torque.hlsl" + +struct ConvexConnectP +{ + float4 pos : TORQUE_POSITION; + float4 wsEyeDir : TEXCOORD0; + float4 ssPos : TEXCOORD1; + float4 vsEyeDir : TEXCOORD2; +}; + +TORQUE_UNIFORM_SAMPLER2D(deferredBuffer, 0); +TORQUE_UNIFORM_SAMPLER2D(shadowMap, 1); +TORQUE_UNIFORM_SAMPLER2D(dynamicShadowMap,2); + +#ifdef USE_COOKIE_TEX + +/// The texture for cookie rendering. +TORQUE_UNIFORM_SAMPLER2D(cookieMap, 3); + +#endif + +TORQUE_UNIFORM_SAMPLER2D(lightBuffer, 5); +TORQUE_UNIFORM_SAMPLER2D(colorBuffer, 6); +TORQUE_UNIFORM_SAMPLER2D(matInfoBuffer, 7); + +uniform float4 rtParams0; + +uniform float lightBrightness; +uniform float3 lightPosition; + +uniform float4 lightColor; + +uniform float lightRange; +uniform float3 lightDirection; + +uniform float4 lightSpotParams; +uniform float4 lightMapParams; +uniform float4 vsFarPlane; +uniform float4x4 viewToLightProj; +uniform float4 lightParams; +uniform float4x4 dynamicViewToLightProj; + +uniform float2 lightAttenuation; +uniform float shadowSoftness; + +float4 main( ConvexConnectP IN ) : TORQUE_TARGET0 +{ + // Compute scene UV + float3 ssPos = IN.ssPos.xyz / IN.ssPos.w; + float2 uvScene = getUVFromSSPos( ssPos, rtParams0 ); + + // Emissive. + float4 matInfo = TORQUE_TEX2D( matInfoBuffer, uvScene ); + bool emissive = getFlag( matInfo.r, 0 ); + if ( emissive ) + { + return float4(0.0, 0.0, 0.0, 0.0); + } + + float4 colorSample = TORQUE_TEX2D( colorBuffer, uvScene ); + float3 subsurface = float3(0.0,0.0,0.0); + if (getFlag( matInfo.r, 1 )) + { + subsurface = colorSample.rgb; + if (colorSample.r>colorSample.g) + subsurface = float3(0.772549, 0.337255, 0.262745); + else + subsurface = float3(0.337255, 0.772549, 0.262745); + } + + // Sample/unpack the normal/z data + float4 deferredSample = TORQUE_DEFERRED_UNCONDITION( deferredBuffer, uvScene ); + float3 normal = deferredSample.rgb; + float depth = deferredSample.a; + + // Eye ray - Eye -> Pixel + float3 eyeRay = getDistanceVectorToPlane( -vsFarPlane.w, IN.vsEyeDir.xyz, vsFarPlane ); + float3 viewSpacePos = eyeRay * depth; + + // Build light vec, get length, clip pixel if needed + float3 lightToPxlVec = viewSpacePos - lightPosition; + float lenLightV = length( lightToPxlVec ); + lightToPxlVec /= lenLightV; + + //lightDirection = float3( -lightDirection.xy, lightDirection.z ); //float3( 0, 0, -1 ); + float cosAlpha = dot( lightDirection, lightToPxlVec ); + clip( cosAlpha - lightSpotParams.x ); + clip( lightRange - lenLightV ); + + float atten = attenuate( lightColor, lightAttenuation, lenLightV ); + atten *= ( cosAlpha - lightSpotParams.x ) / lightSpotParams.y; + clip( atten - 1e-6 ); + atten = saturate( atten ); + + float nDotL = dot( normal, -lightToPxlVec ); + + // Get the shadow texture coordinate + float4 pxlPosLightProj = mul( viewToLightProj, float4( viewSpacePos, 1 ) ); + float2 shadowCoord = ( ( pxlPosLightProj.xy / pxlPosLightProj.w ) * 0.5 ) + float2( 0.5, 0.5 ); + shadowCoord.y = 1.0f - shadowCoord.y; + + // Get the dynamic shadow texture coordinate + float4 dynpxlPosLightProj = mul( dynamicViewToLightProj, float4( viewSpacePos, 1 ) ); + float2 dynshadowCoord = ( ( dynpxlPosLightProj.xy / dynpxlPosLightProj.w ) * 0.5 ) + float2( 0.5, 0.5 ); + dynshadowCoord.y = 1.0f - dynshadowCoord.y; + + #ifdef NO_SHADOW + + float shadowed = 1.0; + + #else + + // Get a linear depth from the light source. + float distToLight = pxlPosLightProj.z / lightRange; + + float static_shadowed = softShadow_filter( TORQUE_SAMPLER2D_MAKEARG(shadowMap), + ssPos.xy, + shadowCoord, + shadowSoftness, + distToLight, + nDotL, + lightParams.y ); + + float dynamic_shadowed = softShadow_filter( TORQUE_SAMPLER2D_MAKEARG(dynamicShadowMap), + ssPos.xy, + dynshadowCoord, + shadowSoftness, + distToLight, + nDotL, + lightParams.y ); + float shadowed = min(static_shadowed, dynamic_shadowed); + #endif // !NO_SHADOW + + float3 lightcol = lightColor.rgb; + #ifdef USE_COOKIE_TEX + + // Lookup the cookie sample. + float4 cookie = TORQUE_TEX2D( cookieMap, shadowCoord ); + + // Multiply the light with the cookie tex. + lightcol *= cookie.rgb; + + // Use a maximum channel luminance to attenuate + // the lighting else we get specular in the dark + // regions of the cookie texture. + atten *= max( cookie.r, max( cookie.g, cookie.b ) ); + + #endif + + // NOTE: Do not clip on fully shadowed pixels as it would + // cause the hardware occlusion query to disable the shadow. + + // Specular term + float specular = AL_CalcSpecular( -lightToPxlVec, + normal, + normalize( -eyeRay ) ) * lightBrightness * atten * shadowed; + + float Sat_NL_Att = saturate( nDotL * atten * shadowed ) * lightBrightness; + float3 lightColorOut = lightMapParams.rgb * lightcol; + float4 addToResult = 0.0; + + // TODO: This needs to be removed when lightmapping is disabled + // as its extra work per-pixel on dynamic lit scenes. + // + // Special lightmapping pass. + if ( lightMapParams.a < 0.0 ) + { + // This disables shadows on the backsides of objects. + shadowed = nDotL < 0.0f ? 1.0f : shadowed; + + Sat_NL_Att = 1.0f; + shadowed = lerp( 1.0f, shadowed, atten ); + lightColorOut = shadowed; + specular *= lightBrightness; + addToResult = ( 1.0 - shadowed ) * abs(lightMapParams); + } + + return AL_DeferredOutput(lightColorOut+subsurface*(1.0-Sat_NL_Att), colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/vectorLightP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/vectorLightP.hlsl new file mode 100644 index 000000000..c5efde242 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/vectorLightP.hlsl @@ -0,0 +1,328 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../shaderModel.hlsl" +#include "../../shaderModelAutoGen.hlsl" + +#include "farFrustumQuad.hlsl" +#include "../../torque.hlsl" +#include "../../lighting.hlsl" +#include "lightingUtils.hlsl" +#include "../shadowMap/shadowMapIO_HLSL.h" +#include "softShadow.hlsl" + +TORQUE_UNIFORM_SAMPLER2D(deferredBuffer, 0); +TORQUE_UNIFORM_SAMPLER2D(shadowMap, 1); +TORQUE_UNIFORM_SAMPLER2D(dynamicShadowMap, 2); + +#ifdef USE_SSAO_MASK +TORQUE_UNIFORM_SAMPLER2D(ssaoMask, 3); +uniform float4 rtParams3; +#endif +//register 4? +TORQUE_UNIFORM_SAMPLER2D(lightBuffer, 5); +TORQUE_UNIFORM_SAMPLER2D(colorBuffer, 6); +TORQUE_UNIFORM_SAMPLER2D(matInfoBuffer, 7); + +uniform float lightBrightness; +uniform float3 lightDirection; + +uniform float4 lightColor; +uniform float4 lightAmbient; + +uniform float shadowSoftness; +uniform float3 eyePosWorld; + +uniform float4 atlasXOffset; +uniform float4 atlasYOffset; +uniform float4 zNearFarInvNearFar; +uniform float4 lightMapParams; +uniform float4 farPlaneScalePSSM; +uniform float4 overDarkPSSM; + +uniform float2 fadeStartLength; +uniform float2 atlasScale; + +uniform float4x4 eyeMat; + +// Static Shadows +uniform float4x4 worldToLightProj; +uniform float4 scaleX; +uniform float4 scaleY; +uniform float4 offsetX; +uniform float4 offsetY; +// Dynamic Shadows +uniform float4x4 dynamicWorldToLightProj; +uniform float4 dynamicScaleX; +uniform float4 dynamicScaleY; +uniform float4 dynamicOffsetX; +uniform float4 dynamicOffsetY; +uniform float4 dynamicFarPlaneScalePSSM; + +float4 AL_VectorLightShadowCast( TORQUE_SAMPLER2D(sourceShadowMap), + float2 texCoord, + float4x4 worldToLightProj, + float4 worldPos, + float4 scaleX, + float4 scaleY, + float4 offsetX, + float4 offsetY, + float4 farPlaneScalePSSM, + float4 atlasXOffset, + float4 atlasYOffset, + float2 atlasScale, + float shadowSoftness, + float dotNL , + float4 overDarkPSSM) +{ + // Compute shadow map coordinate + float4 pxlPosLightProj = mul(worldToLightProj, worldPos); + float2 baseShadowCoord = pxlPosLightProj.xy / pxlPosLightProj.w; + + // Distance to light, in shadowmap space + float distToLight = pxlPosLightProj.z / pxlPosLightProj.w; + + // Figure out which split to sample from. Basically, we compute the shadowmap sample coord + // for all of the splits and then check if its valid. + float4 shadowCoordX = baseShadowCoord.xxxx; + float4 shadowCoordY = baseShadowCoord.yyyy; + float4 farPlaneDists = distToLight.xxxx; + shadowCoordX *= scaleX; + shadowCoordY *= scaleY; + shadowCoordX += offsetX; + shadowCoordY += offsetY; + farPlaneDists *= farPlaneScalePSSM; + + // If the shadow sample is within -1..1 and the distance + // to the light for this pixel is less than the far plane + // of the split, use it. + float4 finalMask; + if ( shadowCoordX.x > -0.99 && shadowCoordX.x < 0.99 && + shadowCoordY.x > -0.99 && shadowCoordY.x < 0.99 && + farPlaneDists.x < 1.0 ) + finalMask = float4(1, 0, 0, 0); + + else if ( shadowCoordX.y > -0.99 && shadowCoordX.y < 0.99 && + shadowCoordY.y > -0.99 && shadowCoordY.y < 0.99 && + farPlaneDists.y < 1.0 ) + finalMask = float4(0, 1, 0, 0); + + else if ( shadowCoordX.z > -0.99 && shadowCoordX.z < 0.99 && + shadowCoordY.z > -0.99 && shadowCoordY.z < 0.99 && + farPlaneDists.z < 1.0 ) + finalMask = float4(0, 0, 1, 0); + + else + finalMask = float4(0, 0, 0, 1); + + float3 debugColor = float3(0,0,0); + + #ifdef NO_SHADOW + debugColor = float3(1.0,1.0,1.0); + #endif + + #ifdef PSSM_DEBUG_RENDER + if ( finalMask.x > 0 ) + debugColor += float3( 1, 0, 0 ); + else if ( finalMask.y > 0 ) + debugColor += float3( 0, 1, 0 ); + else if ( finalMask.z > 0 ) + debugColor += float3( 0, 0, 1 ); + else if ( finalMask.w > 0 ) + debugColor += float3( 1, 1, 0 ); + #endif + + // Here we know what split we're sampling from, so recompute the texcoord location + // Yes, we could just use the result from above, but doing it this way actually saves + // shader instructions. + float2 finalScale; + finalScale.x = dot(finalMask, scaleX); + finalScale.y = dot(finalMask, scaleY); + + float2 finalOffset; + finalOffset.x = dot(finalMask, offsetX); + finalOffset.y = dot(finalMask, offsetY); + + float2 shadowCoord; + shadowCoord = baseShadowCoord * finalScale; + shadowCoord += finalOffset; + + // Convert to texcoord space + shadowCoord = 0.5 * shadowCoord + float2(0.5, 0.5); + shadowCoord.y = 1.0f - shadowCoord.y; + + // Move around inside of atlas + float2 aOffset; + aOffset.x = dot(finalMask, atlasXOffset); + aOffset.y = dot(finalMask, atlasYOffset); + + shadowCoord *= atlasScale; + shadowCoord += aOffset; + + // Each split has a different far plane, take this into account. + float farPlaneScale = dot( farPlaneScalePSSM, finalMask ); + distToLight *= farPlaneScale; + + return float4(debugColor, + softShadow_filter( TORQUE_SAMPLER2D_MAKEARG(sourceShadowMap), + texCoord, + shadowCoord, + farPlaneScale * shadowSoftness, + distToLight, + dotNL, + dot( finalMask, overDarkPSSM ) ) ); +}; + +float4 main( FarFrustumQuadConnectP IN ) : TORQUE_TARGET0 +{ + // Emissive. + float4 matInfo = TORQUE_TEX2D( matInfoBuffer, IN.uv0 ); + bool emissive = getFlag( matInfo.r, 0 ); + if ( emissive ) + { + return float4(1.0, 1.0, 1.0, 0.0); + } + + float4 colorSample = TORQUE_TEX2D( colorBuffer, IN.uv0 ); + float3 subsurface = float3(0.0,0.0,0.0); + if (getFlag( matInfo.r, 1 )) + { + subsurface = colorSample.rgb; + if (colorSample.r>colorSample.g) + subsurface = float3(0.772549, 0.337255, 0.262745); + else + subsurface = float3(0.337255, 0.772549, 0.262745); + } + // Sample/unpack the normal/z data + float4 deferredSample = TORQUE_DEFERRED_UNCONDITION( deferredBuffer, IN.uv0 ); + float3 normal = deferredSample.rgb; + float depth = deferredSample.a; + + // Use eye ray to get ws pos + float4 worldPos = float4(eyePosWorld + IN.wsEyeRay * depth, 1.0f); + + // Get the light attenuation. + float dotNL = dot(-lightDirection, normal); + + #ifdef PSSM_DEBUG_RENDER + float3 debugColor = float3(0,0,0); + #endif + + #ifdef NO_SHADOW + + // Fully unshadowed. + float shadowed = 1.0; + + #ifdef PSSM_DEBUG_RENDER + debugColor = float3(1.0,1.0,1.0); + #endif + + #else + + float4 static_shadowed_colors = AL_VectorLightShadowCast( TORQUE_SAMPLER2D_MAKEARG(shadowMap), + IN.uv0.xy, + worldToLightProj, + worldPos, + scaleX, scaleY, + offsetX, offsetY, + farPlaneScalePSSM, + atlasXOffset, atlasYOffset, + atlasScale, + shadowSoftness, + dotNL, + overDarkPSSM); + float4 dynamic_shadowed_colors = AL_VectorLightShadowCast( TORQUE_SAMPLER2D_MAKEARG(dynamicShadowMap), + IN.uv0.xy, + dynamicWorldToLightProj, + worldPos, + dynamicScaleX, dynamicScaleY, + dynamicOffsetX, dynamicOffsetY, + dynamicFarPlaneScalePSSM, + atlasXOffset, atlasYOffset, + atlasScale, + shadowSoftness, + dotNL, + overDarkPSSM); + + float static_shadowed = static_shadowed_colors.a; + float dynamic_shadowed = dynamic_shadowed_colors.a; + + #ifdef PSSM_DEBUG_RENDER + debugColor = static_shadowed_colors.rgb*0.5+dynamic_shadowed_colors.rgb*0.5; + #endif + + // Fade out the shadow at the end of the range. + float4 zDist = (zNearFarInvNearFar.x + zNearFarInvNearFar.y * depth); + float fadeOutAmt = ( zDist.x - fadeStartLength.x ) * fadeStartLength.y; + + static_shadowed = lerp( static_shadowed, 1.0, saturate( fadeOutAmt ) ); + dynamic_shadowed = lerp( dynamic_shadowed, 1.0, saturate( fadeOutAmt ) ); + + // temp for debugging. uncomment one or the other. + //float shadowed = static_shadowed; + //float shadowed = dynamic_shadowed; + float shadowed = min(static_shadowed, dynamic_shadowed); + + #ifdef PSSM_DEBUG_RENDER + if ( fadeOutAmt > 1.0 ) + debugColor = 1.0; + #endif + + #endif // !NO_SHADOW + + // Specular term + float specular = AL_CalcSpecular( -lightDirection, + normal, + normalize(-IN.vsEyeRay) ) * lightBrightness * shadowed; + + float Sat_NL_Att = saturate( dotNL * shadowed ) * lightBrightness; + float3 lightColorOut = lightMapParams.rgb * lightColor.rgb; + + float4 addToResult = (lightAmbient * (1 - ambientCameraFactor)) + ( lightAmbient * ambientCameraFactor * saturate(dot(normalize(-IN.vsEyeRay), normal)) ); + + // TODO: This needs to be removed when lightmapping is disabled + // as its extra work per-pixel on dynamic lit scenes. + // + // Special lightmapping pass. + if ( lightMapParams.a < 0.0 ) + { + // This disables shadows on the backsides of objects. + shadowed = dotNL < 0.0f ? 1.0f : shadowed; + + Sat_NL_Att = 1.0f; + lightColorOut = shadowed; + specular *= lightBrightness; + addToResult = ( 1.0 - shadowed ) * abs(lightMapParams); + } + + // Sample the AO texture. + #ifdef USE_SSAO_MASK + float ao = 1.0 - TORQUE_TEX2D( ssaoMask, viewportCoordToRenderTarget( IN.uv0.xy, rtParams3 ) ).r; + addToResult *= ao; + #endif + + #ifdef PSSM_DEBUG_RENDER + lightColorOut = debugColor; + #endif + + return AL_DeferredOutput(lightColorOut+subsurface*(1.0-Sat_NL_Att), colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/basic/gl/shadowFilterP.glsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/basic/gl/shadowFilterP.glsl new file mode 100644 index 000000000..9b510e0cf --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/basic/gl/shadowFilterP.glsl @@ -0,0 +1,46 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" + +uniform sampler2D diffuseMap; + +in vec2 uv; + +uniform vec2 oneOverTargetSize; + +const float offset[3] = float[]( 0.0, 1.3846153846, 3.2307692308 ); +const float weight[3] = float[]( 0.2270270270, 0.3162162162, 0.0702702703 ); + +out vec4 OUT_col; + +void main() +{ + OUT_col = texture( diffuseMap, uv ) * weight[0]; + + for ( int i=1; i < 3; i++ ) + { + vec2 _sample = (BLUR_DIR * offset[i]) * oneOverTargetSize; + OUT_col += texture( diffuseMap, uv + _sample ) * weight[i]; + OUT_col += texture( diffuseMap, uv - _sample ) * weight[i]; + } +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/basic/gl/shadowFilterV.glsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/basic/gl/shadowFilterV.glsl new file mode 100644 index 000000000..67b5f1378 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/basic/gl/shadowFilterV.glsl @@ -0,0 +1,37 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/torque.glsl" + +in vec4 vPosition; +in vec2 vTexCoord0; + +uniform vec4 rtParams0; + +out vec2 uv; + +void main() +{ + gl_Position = vPosition; + uv = viewportCoordToRenderTarget( vTexCoord0.st, rtParams0 ); + gl_Position.y *= -1; //correct ssp +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/basic/shadowFilterP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/basic/shadowFilterP.hlsl new file mode 100644 index 000000000..cf819eed3 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/basic/shadowFilterP.hlsl @@ -0,0 +1,50 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../postFx/postFx.hlsl" + +TORQUE_UNIFORM_SAMPLER2D(diffuseMap, 0); + +struct VertToPix +{ + float4 hpos : TORQUE_POSITION; + float2 uv : TEXCOORD0; +}; + +static float offset[3] = { 0.0, 1.3846153846, 3.2307692308 }; +static float weight[3] = { 0.2270270270, 0.3162162162, 0.0702702703 }; + +uniform float2 oneOverTargetSize; + +float4 main( VertToPix IN ) : TORQUE_TARGET0 +{ + float4 OUT = TORQUE_TEX2D( diffuseMap, IN.uv ) * weight[0]; + + for ( int i=1; i < 3; i++ ) + { + float2 sample = (BLUR_DIR * offset[i]) * oneOverTargetSize; + OUT += TORQUE_TEX2D( diffuseMap, IN.uv + sample ) * weight[i]; + OUT += TORQUE_TEX2D(diffuseMap, IN.uv - sample) * weight[i]; + } + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/basic/shadowFilterV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/basic/shadowFilterV.hlsl new file mode 100644 index 000000000..d0838016b --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/basic/shadowFilterV.hlsl @@ -0,0 +1,42 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../postFx/postFx.hlsl" +#include "../../torque.hlsl" + +float4 rtParams0; + +struct VertToPix +{ + float4 hpos : TORQUE_POSITION; + float2 uv : TEXCOORD0; +}; + +VertToPix main( PFXVert IN ) +{ + VertToPix OUT; + + OUT.hpos = float4(IN.pos,1.0); + OUT.uv = viewportCoordToRenderTarget( IN.uv, rtParams0 ); + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/shadowMap/boxFilterP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/shadowMap/boxFilterP.hlsl new file mode 100644 index 000000000..a187c3c63 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/shadowMap/boxFilterP.hlsl @@ -0,0 +1,82 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//***************************************************************************** +// Box Filter +//***************************************************************************** +#include "../ShaderModel.hlsl" + +struct ConnectData +{ + float4 hpos : TORQUE_POSITION; + float2 tex0 : TEXCOORD0; +}; + +// If not defined from ShaderData then define +// the default blur kernel size here. +//#ifndef blurSamples +// #define blurSamples 4 +//#endif + +float log_conv ( float x0, float X, float y0, float Y ) +{ + return (X + log(x0 + (y0 * exp(Y - X)))); +} + +TORQUE_UNIFORM_SAMPLER2D(diffuseMap0, 0); +uniform float texSize : register(C0); +uniform float2 blurDimension : register(C2); +uniform float2 blurBoundaries : register(C3); + +float4 main( ConnectData IN ) : TORQUE_TARGET0 +{ + // 5x5 + if (IN.tex0.x <= blurBoundaries.x) + { + float texelSize = 1.2f / texSize; + float2 sampleOffset = texelSize * blurDimension; + //float2 offset = 0.5 * float( blurSamples ) * sampleOffset; + + float2 texCoord = IN.tex0; + + float accum = log_conv(0.3125, TORQUE_TEX2D(diffuseMap0, texCoord - sampleOffset), 0.375, tex2D(diffuseMap0, texCoord)); + accum = log_conv(1, accum, 0.3125, TORQUE_TEX2D(diffuseMap0, texCoord + sampleOffset)); + + return accum; + } else { + // 3x3 + if (IN.tex0.x <= blurBoundaries.y) + { + float texelSize = 1.3f / texSize; + float2 sampleOffset = texelSize * blurDimension; + //float2 offset = 0.5 * float( blurSamples ) * sampleOffset; + + float2 texCoord = IN.tex0; + float accum = log_conv(0.5, tex2D(diffuseMap0, texCoord - sampleOffset), 0.5, tex2D(diffuseMap0, texCoord + sampleOffset)); + + return accum; + } else { + return TORQUE_TEX2D(diffuseMap0, IN.tex0); + } + } +} + diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/shadowMap/boxFilterV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/shadowMap/boxFilterV.hlsl new file mode 100644 index 000000000..3679e41bb --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/shadowMap/boxFilterV.hlsl @@ -0,0 +1,57 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//***************************************************************************** +// Box Filter +//***************************************************************************** +//----------------------------------------------------------------------------- +// Structures +//----------------------------------------------------------------------------- + +#include "../ShaderModel.hlsl" + +struct VertData +{ + float3 position : POSITION; + float2 texCoord : TEXCOORD0; +}; + +struct ConnectData +{ + float4 hpos : TORQUE_POSITION; + float2 tex0 : TEXCOORD0; +}; + + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +ConnectData main( VertData IN, + uniform float4x4 modelview : register(C0)) +{ + ConnectData OUT; + + OUT.hpos = mul(modelview, float4(IN.position,1.0)); + OUT.tex0 = IN.texCoord; + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/shadowMap/gl/boxFilterP.glsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/shadowMap/gl/boxFilterP.glsl new file mode 100644 index 000000000..d4e05132b --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/shadowMap/gl/boxFilterP.glsl @@ -0,0 +1,49 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#define blurSamples 4.0 + +uniform sampler2D diffuseMap0; +uniform float texSize; +uniform vec2 blurDimension; + +in vec2 tex0; + +out vec4 OUT_col; + +void main() +{ + // Preshader + float TexelSize = 1.0 / texSize; + vec2 SampleOffset = TexelSize * blurDimension; + vec2 Offset = 0.5 * float(blurSamples - 1.0) * SampleOffset; + + vec2 BaseTexCoord = tex0 - Offset; + + vec4 accum = vec4(0.0, 0.0, 0.0, 0.0); + for(int i = 0; i < int(blurSamples); i++) + { + accum += texture(diffuseMap0, BaseTexCoord + float(i) * SampleOffset); + } + accum /= blurSamples; + OUT_col = accum; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/shadowMap/gl/boxFilterV.glsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/shadowMap/gl/boxFilterV.glsl new file mode 100644 index 000000000..9fc436f6c --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/shadowMap/gl/boxFilterV.glsl @@ -0,0 +1,34 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +in vec4 vPosition; +in vec2 vTexCoord0; + +uniform mat4 modelview; + +out vec2 tex0; + +void main() +{ + gl_Position = modelview * vPosition; + tex0 = vTexCoord0.st; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/shadowMap/shadowMapIO.h b/Templates/BaseGame/game/core/rendering/shaders/lighting/shadowMap/shadowMapIO.h new file mode 100644 index 000000000..84ef6b6a8 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/shadowMap/shadowMapIO.h @@ -0,0 +1,50 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//#define SM_Fmt_R8G8B8A8 + +#define pkDepthBitShft 65536.0 +#define pkDepthChanMax 256.0 +#define bias -0.5/255.0 +#define coeff 0.9999991 +//#define coeff 1.0 + +float4 encodeShadowMap( float depth ) +{ +#if defined(SM_Fmt_R8G8B8A8) + return frac( float4(1.0, 255.0, 65025.0, 160581375.0) * depth ) + bias; + + //float4 packedValue = frac((depth / coeff) * float4(16777216.0, 65536.0, 256.0, 1.0)); + //return (packedValue - packedValue.xxyz * float4(0, 1.0 / 256, 1.0 / 256, 1.0 / 256)); +#else + return depth; +#endif +} + +float decodeShadowMap( float4 smSample ) +{ +#if defined(SM_Fmt_R8G8B8A8) + return dot( smSample, float4(1.0, 1/255.0, 1/65025.0, 1/160581375.0) ); +#else + return smSample.x; +#endif +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/shadowMap/shadowMapIO_GLSL.h b/Templates/BaseGame/game/core/rendering/shaders/lighting/shadowMap/shadowMapIO_GLSL.h new file mode 100644 index 000000000..10d69b834 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/shadowMap/shadowMapIO_GLSL.h @@ -0,0 +1,50 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//#define SM_Fmt_R8G8B8A8 + +#define pkDepthBitShft 65536.0 +#define pkDepthChanMax 256.0 +#define bias -0.5/255.0 +#define coeff 0.9999991 +//#define coeff 1.0 + +vec4 encodeShadowMap( float depth ) +{ +#if defined(SM_Fmt_R8G8B8A8) + return frac( vec4(1.0, 255.0, 65025.0, 160581375.0) * depth ) + vec4(bias); + + //float4 packedValue = frac((depth / coeff) * float4(16777216.0, 65536.0, 256.0, 1.0)); + //return (packedValue - packedValue.xxyz * float4(0, 1.0 / 256, 1.0 / 256, 1.0 / 256)); +#else + return vec4(depth); +#endif +} + +float decodeShadowMap( vec4 smSample ) +{ +#if defined(SM_Fmt_R8G8B8A8) + return dot( smSample, vec4(1.0, 1/255.0, 1/65025.0, 1/160581375.0) ); +#else + return smSample.x; +#endif +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/shadowMap/shadowMapIO_HLSL.h b/Templates/BaseGame/game/core/rendering/shaders/lighting/shadowMap/shadowMapIO_HLSL.h new file mode 100644 index 000000000..84ef6b6a8 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/shadowMap/shadowMapIO_HLSL.h @@ -0,0 +1,50 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//#define SM_Fmt_R8G8B8A8 + +#define pkDepthBitShft 65536.0 +#define pkDepthChanMax 256.0 +#define bias -0.5/255.0 +#define coeff 0.9999991 +//#define coeff 1.0 + +float4 encodeShadowMap( float depth ) +{ +#if defined(SM_Fmt_R8G8B8A8) + return frac( float4(1.0, 255.0, 65025.0, 160581375.0) * depth ) + bias; + + //float4 packedValue = frac((depth / coeff) * float4(16777216.0, 65536.0, 256.0, 1.0)); + //return (packedValue - packedValue.xxyz * float4(0, 1.0 / 256, 1.0 / 256, 1.0 / 256)); +#else + return depth; +#endif +} + +float decodeShadowMap( float4 smSample ) +{ +#if defined(SM_Fmt_R8G8B8A8) + return dot( smSample, float4(1.0, 1/255.0, 1/65025.0, 1/160581375.0) ); +#else + return smSample.x; +#endif +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/particleCompositeP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/particleCompositeP.hlsl new file mode 100644 index 000000000..6e26ddbdb --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/particleCompositeP.hlsl @@ -0,0 +1,61 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- +#include "torque.hlsl" +#include "shaderModel.hlsl" + +TORQUE_UNIFORM_SAMPLER2D(colorSource, 0); +uniform float4 offscreenTargetParams; + +#ifdef TORQUE_LINEAR_DEPTH +#define REJECT_EDGES +TORQUE_UNIFORM_SAMPLER2D(edgeSource, 1); +uniform float4 edgeTargetParams; +#endif + +struct Conn +{ + float4 hpos : TORQUE_POSITION; + float4 offscreenPos : TEXCOORD0; + float4 backbufferPos : TEXCOORD1; +}; + + +float4 main(Conn IN) : TORQUE_TARGET0 +{ + // Off-screen particle source screenspace position in XY + // Back-buffer screenspace position in ZW + float4 ssPos = float4(IN.offscreenPos.xy / IN.offscreenPos.w, IN.backbufferPos.xy / IN.backbufferPos.w); + + float4 uvScene = ( ssPos + 1.0 ) / 2.0; + uvScene.yw = 1.0 - uvScene.yw; + uvScene.xy = viewportCoordToRenderTarget(uvScene.xy, offscreenTargetParams); + +#ifdef REJECT_EDGES + // Cut out particles along the edges, this will create the stencil mask + uvScene.zw = viewportCoordToRenderTarget(uvScene.zw, edgeTargetParams); + float edge = TORQUE_TEX2D( edgeSource, uvScene.zw ).r; + clip( -edge ); +#endif + + // Sample offscreen target and return + return TORQUE_TEX2D( colorSource, uvScene.xy ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/particleCompositeV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/particleCompositeV.hlsl new file mode 100644 index 000000000..c4c51204a --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/particleCompositeV.hlsl @@ -0,0 +1,53 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "shaderModel.hlsl" + +struct Vertex +{ + float3 pos : POSITION; + float4 uvCoord : COLOR0; +}; + +struct Conn +{ + float4 hpos : TORQUE_POSITION; + float4 offscreenPos : TEXCOORD0; + float4 backbufferPos : TEXCOORD1; +}; + +uniform float4 screenRect; // point, extent + +Conn main(Vertex IN) +{ + Conn OUT; + + OUT.hpos = float4(IN.uvCoord.xy, 1.0, 1.0); + OUT.hpos.xy *= screenRect.zw; + OUT.hpos.xy += screenRect.xy; + + OUT.backbufferPos = OUT.hpos; + OUT.offscreenPos = OUT.hpos; + + return OUT; +} + diff --git a/Templates/BaseGame/game/core/rendering/shaders/particlesP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/particlesP.hlsl new file mode 100644 index 000000000..155107d8b --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/particlesP.hlsl @@ -0,0 +1,109 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "torque.hlsl" +#include "shaderModel.hlsl" +// With advanced lighting we get soft particles. +#ifdef TORQUE_LINEAR_DEPTH + #define SOFTPARTICLES +#endif + +#ifdef SOFTPARTICLES + + #include "shaderModelAutoGen.hlsl" + + uniform float oneOverSoftness; + uniform float oneOverFar; + TORQUE_UNIFORM_SAMPLER2D(deferredTex, 1); + //uniform float3 vEye; + uniform float4 deferredTargetParams; +#endif + +#define CLIP_Z // TODO: Make this a proper macro + +struct Conn +{ + float4 hpos : TORQUE_POSITION; + float4 color : TEXCOORD0; + float2 uv0 : TEXCOORD1; + float4 pos : TEXCOORD2; +}; + +TORQUE_UNIFORM_SAMPLER2D(diffuseMap, 0); +TORQUE_UNIFORM_SAMPLER2D(paraboloidLightMap, 2); + +float4 lmSample( float3 nrm ) +{ + bool calcBack = (nrm.z < 0.0); + if ( calcBack ) + nrm.z = nrm.z * -1.0; + + float2 lmCoord; + lmCoord.x = (nrm.x / (2*(1 + nrm.z))) + 0.5; + lmCoord.y = 1-((nrm.y / (2*(1 + nrm.z))) + 0.5); + + + // If this is the back, offset in the atlas + if ( calcBack ) + lmCoord.x += 1.0; + + // Atlasing front and back maps, so scale + lmCoord.x *= 0.5; + + return TORQUE_TEX2D(paraboloidLightMap, lmCoord); +} + + +uniform float alphaFactor; +uniform float alphaScale; + +float4 main( Conn IN ) : TORQUE_TARGET0 +{ + float softBlend = 1; + + #ifdef SOFTPARTICLES + float2 tc = IN.pos.xy * float2(1.0, -1.0) / IN.pos.w; + tc = viewportCoordToRenderTarget(saturate( ( tc + 1.0 ) * 0.5 ), deferredTargetParams); + + float sceneDepth = TORQUE_DEFERRED_UNCONDITION(deferredTex, tc).w; + float depth = IN.pos.w * oneOverFar; + float diff = sceneDepth - depth; + #ifdef CLIP_Z + // If drawing offscreen, this acts as the depth test, since we don't line up with the z-buffer + // When drawing high-res, though, we want to be able to take advantage of hi-z + // so this is #ifdef'd out + //clip(diff); + #endif + softBlend = saturate( diff * oneOverSoftness ); + #endif + + float4 diffuse = TORQUE_TEX2D( diffuseMap, IN.uv0 ); + + //return float4( lmSample(float3(0, 0, -1)).rgb, IN.color.a * diffuse.a * softBlend * alphaScale); + + // Scale output color by the alpha factor (turn LerpAlpha into pre-multiplied alpha) + float3 colorScale = ( alphaFactor < 0.0 ? IN.color.rgb * diffuse.rgb : ( alphaFactor > 0.0 ? IN.color.a * diffuse.a * alphaFactor * softBlend : softBlend ) ); + + return hdrEncode( float4( IN.color.rgb * diffuse.rgb * colorScale, + IN.color.a * diffuse.a * softBlend * alphaScale ) ); +} + diff --git a/Templates/BaseGame/game/core/rendering/shaders/particlesV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/particlesV.hlsl new file mode 100644 index 000000000..dbeff0cc2 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/particlesV.hlsl @@ -0,0 +1,55 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "shaderModel.hlsl" + +struct Vertex +{ + float3 pos : POSITION; + float4 color : COLOR0; + float2 uv0 : TEXCOORD0; +}; + +struct Conn +{ + float4 hpos : TORQUE_POSITION; + float4 color : TEXCOORD0; + float2 uv0 : TEXCOORD1; + float4 pos : TEXCOORD2; +}; + + +uniform float4x4 modelViewProj; +uniform float4x4 fsModelViewProj; + +Conn main( Vertex In ) +{ + Conn Out; + + Out.hpos = mul( modelViewProj, float4(In.pos,1.0) ); + Out.pos = mul(fsModelViewProj, float4(In.pos, 1.0) ); + Out.color = In.color; + Out.uv0 = In.uv0; + + return Out; +} + diff --git a/Templates/BaseGame/game/core/rendering/shaders/planarReflectBumpP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/planarReflectBumpP.hlsl new file mode 100644 index 000000000..d18331fb6 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/planarReflectBumpP.hlsl @@ -0,0 +1,87 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Structures +//----------------------------------------------------------------------------- + +#include "shaderModel.hlsl" + +struct ConnectData +{ + float4 hpos : TORQUE_POSITION; + float2 texCoord : TEXCOORD0; + float4 tex2 : TEXCOORD1; +}; + + +struct Fragout +{ + float4 col : TORQUE_TARGET0; +}; + +TORQUE_UNIFORM_SAMPLER2D(texMap, 0); +TORQUE_UNIFORM_SAMPLER2D(refractMap, 1); +TORQUE_UNIFORM_SAMPLER2D(bumpMap, 2); + + +//----------------------------------------------------------------------------- +// Fade edges of axis for texcoord passed in +//----------------------------------------------------------------------------- +float fadeAxis( float val ) +{ + // Fades from 1.0 to 0.0 when less than 0.1 + float fadeLow = saturate( val * 10.0 ); + + // Fades from 1.0 to 0.0 when greater than 0.9 + float fadeHigh = 1.0 - saturate( (val - 0.9) * 10.0 ); + + return fadeLow * fadeHigh; +} + + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +Fragout main( ConnectData IN ) +{ + Fragout OUT; + + float3 bumpNorm = TORQUE_TEX2D( bumpMap, IN.tex2 ) * 2.0 - 1.0; + float2 offset = float2( bumpNorm.x, bumpNorm.y ); + float4 texIndex = IN.texCoord; + + // The fadeVal is used to "fade" the distortion at the edges of the screen. + // This is done so it won't sample the reflection texture out-of-bounds and create artifacts + // Note - this can be done more efficiently with a texture lookup + float fadeVal = fadeAxis( texIndex.x / texIndex.w ) * fadeAxis( texIndex.y / texIndex.w ); + + const float distortion = 0.2; + texIndex.xy += offset * distortion * fadeVal; + + float4 reflectColor = TORQUE_TEX2DPROJ( refractMap, texIndex ); + float4 diffuseColor = TORQUE_TEX2D( texMap, IN.tex2 ); + + OUT.col = diffuseColor + reflectColor * diffuseColor.a; + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/planarReflectBumpV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/planarReflectBumpV.hlsl new file mode 100644 index 000000000..d45adb574 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/planarReflectBumpV.hlsl @@ -0,0 +1,67 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#define IN_HLSL +#include "shdrConsts.h" +#include "shaderModel.hlsl" + +//----------------------------------------------------------------------------- +// Structures +//----------------------------------------------------------------------------- +struct VertData +{ + float3 position : POSITION; + float3 normal : NORMAL; + float2 texCoord : TEXCOORD0; + float2 lmCoord : TEXCOORD1; + float3 T : TEXCOORD2; + float3 B : TEXCOORD3; +}; + + +struct ConnectData +{ + float4 hpos : TORQUE_POSITION; + float4 texCoord : TEXCOORD0; + float2 tex2 : TEXCOORD1; +}; + +uniform float4x4 modelview; +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +ConnectData main( VertData IN ) +{ + ConnectData OUT; + OUT.hpos = mul(modelview, float4(IN.position,1.0)); + + float4x4 texGenTest = { 0.5, 0.0, 0.0, 0.5, + 0.0, -0.5, 0.0, 0.5, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0 }; + + OUT.texCoord = mul( texGenTest, OUT.hpos ); + + OUT.tex2 = IN.texCoord; + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/planarReflectP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/planarReflectP.hlsl new file mode 100644 index 000000000..43b420544 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/planarReflectP.hlsl @@ -0,0 +1,58 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Structures +//----------------------------------------------------------------------------- + +#include "shaderModel.hlsl" + +struct ConnectData +{ + float4 hpos : TORQUE_POSITION; + float2 texCoord : TEXCOORD0; + float4 tex2 : TEXCOORD1; +}; + + +struct Fragout +{ + float4 col : TORQUE_TARGET0; +}; + +TORQUE_UNIFORM_SAMPLER2D(texMap, 0); +TORQUE_UNIFORM_SAMPLER2D(refractMap, 1); + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +Fragout main( ConnectData IN ) +{ + Fragout OUT; + + float4 diffuseColor = TORQUE_TEX2D( texMap, IN.texCoord ); + float4 reflectColor = TORQUE_TEX2DPROJ(refractMap, IN.tex2); + + OUT.col = diffuseColor + reflectColor * diffuseColor.a; + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/planarReflectV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/planarReflectV.hlsl new file mode 100644 index 000000000..1f2ca9d4f --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/planarReflectV.hlsl @@ -0,0 +1,57 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#define IN_HLSL +#include "hlslStructs.hlsl" +#include "shaderModel.hlsl" + +//----------------------------------------------------------------------------- +// Structures +//----------------------------------------------------------------------------- + +struct ConnectData +{ + float4 hpos : TORQUE_POSITION; + float2 texCoord : TEXCOORD0; + float4 tex2 : TEXCOORD1; +}; + +uniform float4x4 modelview; + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +ConnectData main( VertexIn_PNTTTB IN ) +{ + ConnectData OUT; + OUT.hpos = mul(modelview, float4(IN.pos,1.0)); + + float4x4 texGenTest = { 0.5, 0.0, 0.0, 0.5, + 0.0, -0.5, 0.0, 0.5, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0 }; + + OUT.texCoord = IN.uv0; + OUT.tex2 = mul( texGenTest, OUT.hpos ); + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/VolFogGlowP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/VolFogGlowP.hlsl new file mode 100644 index 000000000..c3adb3b55 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/VolFogGlowP.hlsl @@ -0,0 +1,74 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 R.G.S. - Richards Game Studio, the Netherlands +// http://www.richardsgamestudio.com/ +// +// If you find this code useful or you are feeling particularly generous I +// would ask that you please go to http://www.richardsgamestudio.com/ then +// choose Donations from the menu on the left side and make a donation to +// Richards Game Studio. It will be highly appreciated. +// +// The MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// Volumetric Fog Glow postFx pixel shader V1.00 + +#include "./postFx.hlsl" + +TORQUE_UNIFORM_SAMPLER2D(diffuseMap, 0); +uniform float strength; + +struct VertToPix +{ + float4 hpos : TORQUE_POSITION; + + float2 uv0 : TEXCOORD0; + float2 uv1 : TEXCOORD1; + float2 uv2 : TEXCOORD2; + float2 uv3 : TEXCOORD3; + + float2 uv4 : TEXCOORD4; + float2 uv5 : TEXCOORD5; + float2 uv6 : TEXCOORD6; + float2 uv7 : TEXCOORD7; +}; + +float4 main( VertToPix IN ) : TORQUE_TARGET0 +{ + float4 kernel = float4( 0.175, 0.275, 0.375, 0.475 ) * strength; + + float4 OUT = 0; + OUT += TORQUE_TEX2D( diffuseMap, IN.uv0 ) * kernel.x; + OUT += TORQUE_TEX2D( diffuseMap, IN.uv1 ) * kernel.y; + OUT += TORQUE_TEX2D( diffuseMap, IN.uv2 ) * kernel.z; + OUT += TORQUE_TEX2D( diffuseMap, IN.uv3 ) * kernel.w; + + OUT += TORQUE_TEX2D( diffuseMap, IN.uv4 ) * kernel.x; + OUT += TORQUE_TEX2D( diffuseMap, IN.uv5 ) * kernel.y; + OUT += TORQUE_TEX2D( diffuseMap, IN.uv6 ) * kernel.z; + OUT += TORQUE_TEX2D( diffuseMap, IN.uv7 ) * kernel.w; + + // Calculate a lumenance value in the alpha so we + // can use alpha test to save fillrate. + float3 rgb2lum = float3( 0.30, 0.59, 0.11 ); + OUT.a = dot( OUT.rgb, rgb2lum ); + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/caustics/causticsP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/caustics/causticsP.hlsl new file mode 100644 index 000000000..8c8abd480 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/caustics/causticsP.hlsl @@ -0,0 +1,77 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../postFx.hlsl" +#include "../../shaderModelAutoGen.hlsl" + +uniform float accumTime; +uniform float3 eyePosWorld; +uniform float4 rtParams0; +uniform float4 waterFogPlane; + +TORQUE_UNIFORM_SAMPLER2D(deferredTex, 0); +TORQUE_UNIFORM_SAMPLER2D(causticsTex0, 1); +TORQUE_UNIFORM_SAMPLER2D(causticsTex1, 2); + +float distanceToPlane(float4 plane, float3 pos) +{ + return (plane.x * pos.x + plane.y * pos.y + plane.z * pos.z) + plane.w; +} + +float4 main( PFXVertToPix IN ) : TORQUE_TARGET0 +{ + //Sample the pre-pass + float4 deferred = TORQUE_DEFERRED_UNCONDITION( deferredTex, IN.uv0 ); + + //Get depth + float depth = deferred.w; + if(depth > 0.9999) + return float4(0,0,0,0); + + //Get world position + float3 pos = eyePosWorld + IN.wsEyeRay * depth; + + // Check the water depth + float waterDepth = -distanceToPlane(waterFogPlane, pos); + if(waterDepth < 0) + return float4(0,0,0,0); + waterDepth = saturate(waterDepth); + + //Use world position X and Y to calculate caustics UV + float2 causticsUV0 = (abs(pos.xy * 0.25) % float2(1, 1)); + float2 causticsUV1 = (abs(pos.xy * 0.2) % float2(1, 1)); + + //Animate uvs + float timeSin = sin(accumTime); + causticsUV0.xy += float2(accumTime*0.1, timeSin*0.2); + causticsUV1.xy -= float2(accumTime*0.15, timeSin*0.15); + + //Sample caustics texture + float4 caustics = TORQUE_TEX2D(causticsTex0, causticsUV0); + caustics *= TORQUE_TEX2D(causticsTex1, causticsUV1); + + //Use normal Z to modulate caustics + //float waterDepth = 1 - saturate(pos.z + waterFogPlane.w + 1); + caustics *= saturate(deferred.z) * pow(abs(1-depth), 64) * waterDepth; + + return caustics; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/caustics/gl/causticsP.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/caustics/gl/causticsP.glsl new file mode 100644 index 000000000..d002fd7e1 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/caustics/gl/causticsP.glsl @@ -0,0 +1,87 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" +#include "../../gl/postFX.glsl" +#include "shadergen:/autogenConditioners.h" + +uniform vec3 eyePosWorld; +uniform vec4 rtParams0; +uniform vec4 waterFogPlane; +uniform float accumTime; + +uniform sampler2D deferredTex; +uniform sampler2D causticsTex0; +uniform sampler2D causticsTex1; +uniform vec2 targetSize; + +out vec4 OUT_col; + +float distanceToPlane(vec4 plane, vec3 pos) +{ + return (plane.x * pos.x + plane.y * pos.y + plane.z * pos.z) + plane.w; +} + +void main() +{ + //Sample the pre-pass + vec4 deferred = deferredUncondition( deferredTex, IN_uv0 ); + + //Get depth + float depth = deferred.w; + if(depth > 0.9999) + { + OUT_col = vec4(0,0,0,0); + return; + } + + //Get world position + vec3 pos = eyePosWorld + IN_wsEyeRay * depth; + + // Check the water depth + float waterDepth = -distanceToPlane(waterFogPlane, pos); + if(waterDepth < 0) + { + OUT_col = vec4(0,0,0,0); + return; + } + waterDepth = saturate(waterDepth); + + //Use world position X and Y to calculate caustics UV + vec2 causticsUV0 = mod(abs(pos.xy * 0.25), vec2(1, 1)); + vec2 causticsUV1 = mod(abs(pos.xy * 0.2), vec2(1, 1)); + + //Animate uvs + float timeSin = sin(accumTime); + causticsUV0.xy += vec2(accumTime*0.1, timeSin*0.2); + causticsUV1.xy -= vec2(accumTime*0.15, timeSin*0.15); + + //Sample caustics texture + vec4 caustics = texture(causticsTex0, causticsUV0); + caustics *= texture(causticsTex1, causticsUV1); + + //Use normal Z to modulate caustics + //float waterDepth = 1 - saturate(pos.z + waterFogPlane.w + 1); + caustics *= saturate(deferred.z) * pow(1-depth, 64) * waterDepth; + + OUT_col = caustics; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/chromaticLens.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/chromaticLens.hlsl new file mode 100644 index 000000000..8fdca72b7 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/chromaticLens.hlsl @@ -0,0 +1,60 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// Based on 'Cubic Lens Distortion HLSL Shader' by François Tarlier +// www.francois-tarlier.com/blog/index.php/2009/11/cubic-lens-distortion-shader + +#include "./postFx.hlsl" +#include "./../torque.hlsl" + +TORQUE_UNIFORM_SAMPLER2D(backBuffer, 0); +uniform float distCoeff; +uniform float cubeDistort; +uniform float3 colorDistort; + + +float4 main( PFXVertToPix IN ) : TORQUE_TARGET0 +{ + float2 tex = IN.uv0; + + float f = 0; + float r2 = (tex.x - 0.5) * (tex.x - 0.5) + (tex.y - 0.5) * (tex.y - 0.5); + + // Only compute the cubic distortion if necessary. + if ( cubeDistort == 0.0 ) + f = 1 + r2 * distCoeff; + else + f = 1 + r2 * (distCoeff + cubeDistort * sqrt(r2)); + + // Distort each color channel seperately to get a chromatic distortion effect. + float3 outColor; + float3 distort = f.xxx + colorDistort; + + for ( int i=0; i < 3; i++ ) + { + float x = distort[i] * ( tex.x - 0.5 ) + 0.5; + float y = distort[i] * ( tex.y - 0.5 ) + 0.5; + outColor[i] = TORQUE_TEX2DLOD( backBuffer, float4(x,y,0,0) )[i]; + } + + return float4( outColor.rgb, 1 ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_CalcCoC_P.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_CalcCoC_P.hlsl new file mode 100644 index 000000000..2f5835fc2 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_CalcCoC_P.hlsl @@ -0,0 +1,53 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "./../postFx.hlsl" + +// These are set by the game engine. +TORQUE_UNIFORM_SAMPLER2D(shrunkSampler, 0); // Output of DofDownsample() +TORQUE_UNIFORM_SAMPLER2D(blurredSampler, 1); // Blurred version of the shrunk sampler + + +// This is the pixel shader function that calculates the actual +// value used for the near circle of confusion. +// "texCoords" are 0 at the bottom left pixel and 1 at the top right. +float4 main( PFXVertToPix IN ) : TORQUE_TARGET0 +{ + float3 color; + float coc; + half4 blurred; + half4 shrunk; + + shrunk = half4(TORQUE_TEX2D( shrunkSampler, IN.uv0 )); + blurred = half4(TORQUE_TEX2D( blurredSampler, IN.uv1 )); + color = shrunk.rgb; + //coc = shrunk.a; + //coc = blurred.a; + //coc = max( blurred.a, shrunk.a ); + coc = 2 * max( blurred.a, shrunk.a ) - shrunk.a; + + + //return float4( coc.rrr, 1.0 ); + //return float4( color, 1.0 ); + return float4( color, coc ); + //return float4( 1.0, 0.0, 1.0, 1.0 ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_CalcCoC_V.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_CalcCoC_V.hlsl new file mode 100644 index 000000000..8131e45cd --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_CalcCoC_V.hlsl @@ -0,0 +1,70 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "./../postFx.hlsl" +#include "./../../torque.hlsl" + +uniform float4 rtParams0; +uniform float4 rtParams1; +uniform float4 rtParams2; +uniform float4 rtParams3; + +PFXVertToPix main( PFXVert IN ) +{ + PFXVertToPix OUT; + + /* + OUT.hpos = IN.pos; + OUT.uv0 = IN.uv; + OUT.uv1 = IN.uv; + OUT.uv2 = IN.uv; + OUT.uv3 = IN.uv; + */ + + /* + OUT.hpos = IN.pos; + OUT.uv0 = IN.uv + rtParams0.xy; + OUT.uv1 = IN.uv + rtParams1.xy; + OUT.uv2 = IN.uv + rtParams2.xy; + OUT.uv3 = IN.uv + rtParams3.xy; + */ + + /* + OUT.hpos = IN.pos; + OUT.uv0 = IN.uv * rtParams0.zw; + OUT.uv1 = IN.uv * rtParams1.zw; + OUT.uv2 = IN.uv * rtParams2.zw; + OUT.uv3 = IN.uv * rtParams3.zw; + */ + + + OUT.hpos = float4(IN.pos,1.0); + OUT.uv0 = viewportCoordToRenderTarget( IN.uv, rtParams0 ); + OUT.uv1 = viewportCoordToRenderTarget( IN.uv, rtParams1 ); + OUT.uv2 = viewportCoordToRenderTarget( IN.uv, rtParams2 ); + OUT.uv3 = viewportCoordToRenderTarget( IN.uv, rtParams3 ); + + + OUT.wsEyeRay = IN.wsEyeRay; + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_DownSample_P.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_DownSample_P.hlsl new file mode 100644 index 000000000..907c3d122 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_DownSample_P.hlsl @@ -0,0 +1,143 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../shaderModel.hlsl" +#include "../../shaderModelAutoGen.hlsl" + +// These are set by the game engine. +// The render target size is one-quarter the scene rendering size. +TORQUE_UNIFORM_SAMPLER2D(colorSampler, 0); +TORQUE_UNIFORM_SAMPLER2D(depthSampler, 1); +uniform float2 dofEqWorld; +uniform float2 targetSize; +uniform float depthOffset; +uniform float maxWorldCoC; +//uniform float2 dofEqWeapon; +//uniform float2 dofRowDelta; // float2( 0, 0.25 / renderTargetHeight ) + +struct Pixel +{ + float4 position : TORQUE_POSITION; + float2 tcColor0 : TEXCOORD0; + float2 tcColor1 : TEXCOORD1; + float2 tcDepth0 : TEXCOORD2; + float2 tcDepth1 : TEXCOORD3; + float2 tcDepth2 : TEXCOORD4; + float2 tcDepth3 : TEXCOORD5; +}; + +half4 main( Pixel IN ) : TORQUE_TARGET0 +{ + //return float4( 1.0, 0.0, 1.0, 1.0 ); + + float2 dofRowDelta = float2( 0, 0.25 / targetSize.y ); + + //float2 dofEqWorld = float2( -60, 1.0 ); + + half3 color; + half maxCoc; + float4 depth; + half4 viewCoc; + half4 sceneCoc; + half4 curCoc; + half4 coc; + float2 rowOfs[4]; + + // "rowOfs" reduces how many moves PS2.0 uses to emulate swizzling. + rowOfs[0] = 0; + rowOfs[1] = dofRowDelta.xy; + rowOfs[2] = dofRowDelta.xy * 2; + rowOfs[3] = dofRowDelta.xy * 3; + + // Use bilinear filtering to average 4 color samples for free. + color = 0; + color += half3(TORQUE_TEX2D( colorSampler, IN.tcColor0.xy + rowOfs[0] ).rgb); + color += half3(TORQUE_TEX2D(colorSampler, IN.tcColor1.xy + rowOfs[0]).rgb); + color += half3(TORQUE_TEX2D(colorSampler, IN.tcColor0.xy + rowOfs[2]).rgb); + color += half3(TORQUE_TEX2D(colorSampler, IN.tcColor1.xy + rowOfs[2]).rgb); + color /= 4; + + //declare thse here to save doing it in each loop below + half4 zero4 = half4(0, 0, 0, 0); + coc = zero4; + half4 dofEqWorld4X = half4(dofEqWorld.xxxx); + half4 dofEqWorld4Y = half4(dofEqWorld.yyyy); + half4 maxWorldCoC4 = half4(maxWorldCoC, maxWorldCoC, maxWorldCoC, maxWorldCoC); + // Process 4 samples at a time to use vector hardware efficiently. + // The CoC will be 1 if the depth is negative, so use "min" to pick + // between "sceneCoc" and "viewCoc". + [unroll] // coc[i] causes this anyway + for (int i = 0; i < 4; i++) + { + depth[0] = TORQUE_DEFERRED_UNCONDITION(depthSampler, (IN.tcDepth0.xy + rowOfs[i])).w; + depth[1] = TORQUE_DEFERRED_UNCONDITION(depthSampler, (IN.tcDepth1.xy + rowOfs[i])).w; + depth[2] = TORQUE_DEFERRED_UNCONDITION(depthSampler, (IN.tcDepth2.xy + rowOfs[i])).w; + depth[3] = TORQUE_DEFERRED_UNCONDITION(depthSampler, (IN.tcDepth3.xy + rowOfs[i])).w; + + coc = max(coc, clamp(dofEqWorld4X * half4(depth)+dofEqWorld4Y, zero4, maxWorldCoC4)); + } + + /* + depth[0] = TORQUE_TEX2D( depthSampler, pixel.tcDepth0.xy + rowOfs[0] ).r; + depth[1] = TORQUE_TEX2D( depthSampler, pixel.tcDepth1.xy + rowOfs[0] ).r; + depth[2] = TORQUE_TEX2D( depthSampler, pixel.tcDepth2.xy + rowOfs[0] ).r; + depth[3] = TORQUE_TEX2D( depthSampler, pixel.tcDepth3.xy + rowOfs[0] ).r; + viewCoc = saturate( dofEqWeapon.x * -depth + dofEqWeapon.y ); + sceneCoc = saturate( dofEqWorld.x * depth + dofEqWorld.y ); + curCoc = min( viewCoc, sceneCoc ); + coc = curCoc; + + depth[0] = TORQUE_TEX2D( depthSampler, pixel.tcDepth0.xy + rowOfs[1] ).r; + depth[1] = TORQUE_TEX2D( depthSampler, pixel.tcDepth1.xy + rowOfs[1] ).r; + depth[2] = TORQUE_TEX2D( depthSampler, pixel.tcDepth2.xy + rowOfs[1] ).r; + depth[3] = TORQUE_TEX2D( depthSampler, pixel.tcDepth3.xy + rowOfs[1] ).r; + viewCoc = saturate( dofEqWeapon.x * -depth + dofEqWeapon.y ); + sceneCoc = saturate( dofEqWorld.x * depth + dofEqWorld.y ); + curCoc = min( viewCoc, sceneCoc ); + coc = max( coc, curCoc ); + + depth[0] = TORQUE_TEX2D( depthSampler, pixel.tcDepth0.xy + rowOfs[2] ).r; + depth[1] = TORQUE_TEX2D( depthSampler, pixel.tcDepth1.xy + rowOfs[2] ).r; + depth[2] = TORQUE_TEX2D( depthSampler, pixel.tcDepth2.xy + rowOfs[2] ).r; + depth[3] = TORQUE_TEX2D( depthSampler, pixel.tcDepth3.xy + rowOfs[2] ).r; + viewCoc = saturate( dofEqWeapon.x * -depth + dofEqWeapon.y ); + sceneCoc = saturate( dofEqWorld.x * depth + dofEqWorld.y ); + curCoc = min( viewCoc, sceneCoc ); + coc = max( coc, curCoc ); + + depth[0] = TORQUE_TEX2D( depthSampler, pixel.tcDepth0.xy + rowOfs[3] ).r; + depth[1] = TORQUE_TEX2D( depthSampler, pixel.tcDepth1.xy + rowOfs[3] ).r; + depth[2] = TORQUE_TEX2D( depthSampler, pixel.tcDepth2.xy + rowOfs[3] ).r; + depth[3] = TORQUE_TEX2D( depthSampler, pixel.tcDepth3.xy + rowOfs[3] ).r; + viewCoc = saturate( dofEqWeapon.x * -depth + dofEqWeapon.y ); + sceneCoc = saturate( dofEqWorld.x * depth + dofEqWorld.y ); + curCoc = min( viewCoc, sceneCoc ); + coc = max( coc, curCoc ); + */ + + maxCoc = max( max( coc[0], coc[1] ), max( coc[2], coc[3] ) ); + + //return half4( 1.0, 0.0, 1.0, 1.0 ); + return half4( color, maxCoc ); + //return half4( color, 1.0f ); + //return half4( maxCoc.rrr, 1.0 ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_DownSample_V.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_DownSample_V.hlsl new file mode 100644 index 000000000..0b3ec01e2 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_DownSample_V.hlsl @@ -0,0 +1,61 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "./../postFx.hlsl" +#include "./../../torque.hlsl" + +struct Vert +{ + float3 pos : POSITION; + float2 tc : TEXCOORD0; + float3 wsEyeRay : TEXCOORD1; +}; + +struct Pixel +{ + float4 position : TORQUE_POSITION; + float2 tcColor0 : TEXCOORD0; + float2 tcColor1 : TEXCOORD1; + float2 tcDepth0 : TEXCOORD2; + float2 tcDepth1 : TEXCOORD3; + float2 tcDepth2 : TEXCOORD4; + float2 tcDepth3 : TEXCOORD5; +}; + +uniform float4 rtParams0; +uniform float2 oneOverTargetSize; + +Pixel main( Vert IN ) +{ + Pixel OUT; + OUT.position = float4(IN.pos,1.0); + + float2 uv = viewportCoordToRenderTarget( IN.tc, rtParams0 ); + //OUT.position = mul( IN.pos, modelView ); + OUT.tcColor1 = uv + float2( +1.0, -0.0 ) * oneOverTargetSize; + OUT.tcColor0 = uv + float2( -1.0, -0.0 ) * oneOverTargetSize; + OUT.tcDepth0 = uv + float2( -0.5, -0.0 ) * oneOverTargetSize; + OUT.tcDepth1 = uv + float2( -1.5, -0.0 ) * oneOverTargetSize; + OUT.tcDepth2 = uv + float2( +1.5, -0.0 ) * oneOverTargetSize; + OUT.tcDepth3 = uv + float2( +2.5, -0.0 ) * oneOverTargetSize; + return OUT; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_Final_P.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_Final_P.hlsl new file mode 100644 index 000000000..9a7cb3d5e --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_Final_P.hlsl @@ -0,0 +1,145 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../shaderModelAutoGen.hlsl" +#include "./../postFx.hlsl" + +TORQUE_UNIFORM_SAMPLER2D(colorSampler,0); // Original source image +TORQUE_UNIFORM_SAMPLER2D(smallBlurSampler,1); // Output of SmallBlurPS() +TORQUE_UNIFORM_SAMPLER2D(largeBlurSampler,2); // Blurred output of DofDownsample() +TORQUE_UNIFORM_SAMPLER2D(depthSampler,3); + +uniform float2 oneOverTargetSize; +uniform float4 dofLerpScale; +uniform float4 dofLerpBias; +uniform float3 dofEqFar; +uniform float maxFarCoC; + +//static float d0 = 0.1; +//static float d1 = 0.1; +//static float d2 = 0.8; +//static float4 dofLerpScale = float4( -1.0 / d0, -1.0 / d1, -1.0 / d2, 1.0 / d2 ); +//static float4 dofLerpBias = float4( 1.0, (1.0 - d2) / d1, 1.0 / d2, (d2 - 1.0) / d2 ); +//static float3 dofEqFar = float3( 2.0, 0.0, 1.0 ); + +float4 tex2Doffset(TORQUE_SAMPLER2D(s), float2 tc, float2 offset) +{ + return TORQUE_TEX2D( s, tc + offset * oneOverTargetSize ); +} + +half3 GetSmallBlurSample( float2 tc ) +{ + half3 sum; + const half weight = 4.0 / 17; + sum = 0; // Unblurred sample done by alpha blending + //sum += weight * tex2Doffset( colorSampler, tc, float2( 0, 0 ) ).rgb; + sum += weight * half3(tex2Doffset(TORQUE_SAMPLER2D_MAKEARG(colorSampler), tc, float2(+0.5, -1.5)).rgb); + sum += weight * half3(tex2Doffset(TORQUE_SAMPLER2D_MAKEARG(colorSampler), tc, float2(-1.5, -0.5)).rgb); + sum += weight * half3(tex2Doffset(TORQUE_SAMPLER2D_MAKEARG(colorSampler), tc, float2(-0.5, +1.5)).rgb); + sum += weight * half3(tex2Doffset(TORQUE_SAMPLER2D_MAKEARG(colorSampler), tc, float2(+1.5, +0.5)).rgb); + return sum; +} + +half4 InterpolateDof( half3 small, half3 med, half3 large, half t ) +{ + //t = 2; + half4 weights; + half3 color; + half alpha; + + // Efficiently calculate the cross-blend weights for each sample. + // Let the unblurred sample to small blur fade happen over distance + // d0, the small to medium blur over distance d1, and the medium to + // large blur over distance d2, where d0 + d1 + d2 = 1. + //float4 dofLerpScale = float4( -1 / d0, -1 / d1, -1 / d2, 1 / d2 ); + //float4 dofLerpBias = float4( 1, (1 � d2) / d1, 1 / d2, (d2 � 1) / d2 ); + + weights = half4(saturate( t * dofLerpScale + dofLerpBias )); + weights.yz = min( weights.yz, 1 - weights.xy ); + + // Unblurred sample with weight "weights.x" done by alpha blending + color = weights.y * small + weights.z * med + weights.w * large; + //color = med; + alpha = dot( weights.yzw, half3( 16.0 / 17, 1.0, 1.0 ) ); + //alpha = 0.0; + + return half4( color, alpha ); +} + +half4 main( PFXVertToPix IN ) : TORQUE_TARGET0 +{ + //return half4( 1,0,1,1 ); + //return half4( TORQUE_TEX2D( colorSampler, IN.uv0 ).rgb, 1.0 ); + //return half4( TORQUE_TEX2D( colorSampler, texCoords ).rgb, 0 ); + half3 small; + half4 med; + half3 large; + half depth; + half nearCoc; + half farCoc; + half coc; + + small = GetSmallBlurSample( IN.uv0 ); + //small = half3( 1,0,0 ); + //return half4( small, 1.0 ); + med = half4(TORQUE_TEX2D( smallBlurSampler, IN.uv1 )); + //med.rgb = half3( 0,1,0 ); + //return half4(med.rgb, 0.0); + large = half3(TORQUE_TEX2D(largeBlurSampler, IN.uv2).rgb); + //large = half3( 0,0,1 ); + //return large; + //return half4(large.rgb,1.0); + nearCoc = med.a; + + // Since the med blur texture is screwed up currently + // replace it with the large, but this needs to be fixed. + //med.rgb = large; + + //nearCoc = 0; + depth = half(TORQUE_DEFERRED_UNCONDITION( depthSampler, IN.uv3 ).w); + //return half4(depth.rrr,1); + //return half4(nearCoc.rrr,1.0); + + if (depth > 0.999 ) + { + coc = nearCoc; // We don't want to blur the sky. + //coc = 0; + } + else + { + // dofEqFar.x and dofEqFar.y specify the linear ramp to convert + // to depth for the distant out-of-focus region. + // dofEqFar.z is the ratio of the far to the near blur radius. + farCoc = half(clamp( dofEqFar.x * depth + dofEqFar.y, 0.0, maxFarCoC )); + coc = half(max( nearCoc, farCoc * dofEqFar.z )); + //coc = nearCoc; + } + + //coc = nearCoc; + //coc = farCoc; + //return half4(coc.rrr,0.5); + //return half4(farCoc.rrr,1); + //return half4(nearCoc.rrr,1); + + //return half4( 1,0,1,0 ); + return InterpolateDof( small, med.rgb, large, coc ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_Final_V.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_Final_V.hlsl new file mode 100644 index 000000000..86c93701a --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_Final_V.hlsl @@ -0,0 +1,72 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "./../postFx.hlsl" +#include "./../../torque.hlsl" + +uniform float4 rtParams0; +uniform float4 rtParams1; +uniform float4 rtParams2; +uniform float4 rtParams3; +uniform float2 oneOverTargetSize; + +PFXVertToPix main( PFXVert IN ) +{ + PFXVertToPix OUT; + + /* + OUT.hpos = IN.pos; + OUT.uv0 = IN.uv; + OUT.uv1 = IN.uv; + OUT.uv2 = IN.uv; + OUT.uv3 = IN.uv; + */ + + /* + OUT.hpos = IN.pos; + OUT.uv0 = IN.uv + rtParams0.xy; + OUT.uv1 = IN.uv + rtParams1.xy; + OUT.uv2 = IN.uv + rtParams2.xy; + OUT.uv3 = IN.uv + rtParams3.xy; + */ + + + /* + OUT.hpos = IN.pos; + OUT.uv0 = IN.uv * rtParams0.zw; + OUT.uv1 = IN.uv * rtParams1.zw; + OUT.uv2 = IN.uv * rtParams2.zw; + OUT.uv3 = IN.uv * rtParams3.zw; + */ + + + OUT.hpos = float4(IN.pos,1.0); + OUT.uv0 = viewportCoordToRenderTarget( IN.uv, rtParams0 ); + OUT.uv1 = viewportCoordToRenderTarget( IN.uv, rtParams1 ); // + float2( -5, 1 ) * oneOverTargetSize; + OUT.uv2 = viewportCoordToRenderTarget( IN.uv, rtParams2 ); + OUT.uv3 = viewportCoordToRenderTarget( IN.uv, rtParams3 ); + + + OUT.wsEyeRay = IN.wsEyeRay; + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_Gausian_P.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_Gausian_P.hlsl new file mode 100644 index 000000000..f4d29f3e1 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_Gausian_P.hlsl @@ -0,0 +1,63 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "./../postFx.hlsl" + +TORQUE_UNIFORM_SAMPLER2D(diffuseMap, 0); + +struct VertToPix +{ + float4 hpos : TORQUE_POSITION; + + float2 uv0 : TEXCOORD0; + float2 uv1 : TEXCOORD1; + float2 uv2 : TEXCOORD2; + float2 uv3 : TEXCOORD3; + + float2 uv4 : TEXCOORD4; + float2 uv5 : TEXCOORD5; + float2 uv6 : TEXCOORD6; + float2 uv7 : TEXCOORD7; +}; + +float4 main( VertToPix IN ) : TORQUE_TARGET0 +{ + float4 kernel = float4( 0.175, 0.275, 0.375, 0.475 ) * 0.5 / 1.3; //25f; + + float4 OUT = 0; + OUT += TORQUE_TEX2D( diffuseMap, IN.uv0 ) * kernel.x; + OUT += TORQUE_TEX2D( diffuseMap, IN.uv1 ) * kernel.y; + OUT += TORQUE_TEX2D( diffuseMap, IN.uv2 ) * kernel.z; + OUT += TORQUE_TEX2D( diffuseMap, IN.uv3 ) * kernel.w; + + OUT += TORQUE_TEX2D( diffuseMap, IN.uv4 ) * kernel.x; + OUT += TORQUE_TEX2D( diffuseMap, IN.uv5 ) * kernel.y; + OUT += TORQUE_TEX2D( diffuseMap, IN.uv6 ) * kernel.z; + OUT += TORQUE_TEX2D( diffuseMap, IN.uv7 ) * kernel.w; + + // Calculate a lumenance value in the alpha so we + // can use alpha test to save fillrate. + //float3 rgb2lum = float3( 0.30, 0.59, 0.11 ); + //OUT.a = dot( OUT.rgb, rgb2lum ); + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_Gausian_V.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_Gausian_V.hlsl new file mode 100644 index 000000000..b2d4582e0 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_Gausian_V.hlsl @@ -0,0 +1,80 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "./../postFx.hlsl" +#include "./../../torque.hlsl" + + +uniform float4 rtParams0; +uniform float2 texSize0; +uniform float2 oneOverTargetSize; + +struct VertToPix +{ + float4 hpos : TORQUE_POSITION; + + float2 uv0 : TEXCOORD0; + float2 uv1 : TEXCOORD1; + float2 uv2 : TEXCOORD2; + float2 uv3 : TEXCOORD3; + + float2 uv4 : TEXCOORD4; + float2 uv5 : TEXCOORD5; + float2 uv6 : TEXCOORD6; + float2 uv7 : TEXCOORD7; +}; + +VertToPix main( PFXVert IN ) +{ + VertToPix OUT; + + OUT.hpos = float4(IN.pos,1.0); + + IN.uv = viewportCoordToRenderTarget( IN.uv, rtParams0 ); + + // I don't know why this offset is necessary, but it is. + //IN.uv = IN.uv * oneOverTargetSize; + + OUT.uv0 = IN.uv + ( ( BLUR_DIR * 3.5f ) / texSize0 ); + OUT.uv1 = IN.uv + ( ( BLUR_DIR * 2.5f ) / texSize0 ); + OUT.uv2 = IN.uv + ( ( BLUR_DIR * 1.5f ) / texSize0 ); + OUT.uv3 = IN.uv + ( ( BLUR_DIR * 0.5f ) / texSize0 ); + + OUT.uv4 = IN.uv - ( ( BLUR_DIR * 3.5f ) / texSize0 ); + OUT.uv5 = IN.uv - ( ( BLUR_DIR * 2.5f ) / texSize0 ); + OUT.uv6 = IN.uv - ( ( BLUR_DIR * 1.5f ) / texSize0 ); + OUT.uv7 = IN.uv - ( ( BLUR_DIR * 0.5f ) / texSize0 ); + + /* + OUT.uv0 = viewportCoordToRenderTarget( OUT.uv0, rtParams0 ); + OUT.uv1 = viewportCoordToRenderTarget( OUT.uv1, rtParams0 ); + OUT.uv2 = viewportCoordToRenderTarget( OUT.uv2, rtParams0 ); + OUT.uv3 = viewportCoordToRenderTarget( OUT.uv3, rtParams0 ); + + OUT.uv4 = viewportCoordToRenderTarget( OUT.uv4, rtParams0 ); + OUT.uv5 = viewportCoordToRenderTarget( OUT.uv5, rtParams0 ); + OUT.uv6 = viewportCoordToRenderTarget( OUT.uv6, rtParams0 ); + OUT.uv7 = viewportCoordToRenderTarget( OUT.uv7, rtParams0 ); + */ + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_Passthrough_V.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_Passthrough_V.hlsl new file mode 100644 index 000000000..8131e45cd --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_Passthrough_V.hlsl @@ -0,0 +1,70 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "./../postFx.hlsl" +#include "./../../torque.hlsl" + +uniform float4 rtParams0; +uniform float4 rtParams1; +uniform float4 rtParams2; +uniform float4 rtParams3; + +PFXVertToPix main( PFXVert IN ) +{ + PFXVertToPix OUT; + + /* + OUT.hpos = IN.pos; + OUT.uv0 = IN.uv; + OUT.uv1 = IN.uv; + OUT.uv2 = IN.uv; + OUT.uv3 = IN.uv; + */ + + /* + OUT.hpos = IN.pos; + OUT.uv0 = IN.uv + rtParams0.xy; + OUT.uv1 = IN.uv + rtParams1.xy; + OUT.uv2 = IN.uv + rtParams2.xy; + OUT.uv3 = IN.uv + rtParams3.xy; + */ + + /* + OUT.hpos = IN.pos; + OUT.uv0 = IN.uv * rtParams0.zw; + OUT.uv1 = IN.uv * rtParams1.zw; + OUT.uv2 = IN.uv * rtParams2.zw; + OUT.uv3 = IN.uv * rtParams3.zw; + */ + + + OUT.hpos = float4(IN.pos,1.0); + OUT.uv0 = viewportCoordToRenderTarget( IN.uv, rtParams0 ); + OUT.uv1 = viewportCoordToRenderTarget( IN.uv, rtParams1 ); + OUT.uv2 = viewportCoordToRenderTarget( IN.uv, rtParams2 ); + OUT.uv3 = viewportCoordToRenderTarget( IN.uv, rtParams3 ); + + + OUT.wsEyeRay = IN.wsEyeRay; + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_SmallBlur_P.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_SmallBlur_P.hlsl new file mode 100644 index 000000000..175525a91 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_SmallBlur_P.hlsl @@ -0,0 +1,46 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// This vertex and pixel shader applies a 3 x 3 blur to the image in +// colorMapSampler, which is the same size as the render target. +// The sample weights are 1/16 in the corners, 2/16 on the edges, +// and 4/16 in the center. +#include "../../shaderModel.hlsl" + +TORQUE_UNIFORM_SAMPLER2D(colorSampler, 0); // Output of DofNearCoc() + +struct Pixel +{ + float4 position : TORQUE_POSITION; + float4 texCoords : TEXCOORD0; +}; + +float4 main( Pixel IN ) : TORQUE_TARGET0 +{ + float4 color; + color = 0.0; + color += TORQUE_TEX2D( colorSampler, IN.texCoords.xz ); + color += TORQUE_TEX2D( colorSampler, IN.texCoords.yz ); + color += TORQUE_TEX2D( colorSampler, IN.texCoords.xw ); + color += TORQUE_TEX2D( colorSampler, IN.texCoords.yw ); + return color / 4.0; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_SmallBlur_V.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_SmallBlur_V.hlsl new file mode 100644 index 000000000..3edb1ec2a --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/DOF_SmallBlur_V.hlsl @@ -0,0 +1,56 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// This vertex and pixel shader applies a 3 x 3 blur to the image in +// colorMapSampler, which is the same size as the render target. +// The sample weights are 1/16 in the corners, 2/16 on the edges, +// and 4/16 in the center. + +#include "./../postFx.hlsl" +#include "./../../torque.hlsl" + +struct Vert +{ + float3 position : POSITION; + float2 texCoords : TEXCOORD0; +}; + +struct Pixel +{ + float4 position : TORQUE_POSITION; + float4 texCoords : TEXCOORD0; +}; + +uniform float2 oneOverTargetSize; +uniform float4 rtParams0; + +Pixel main( Vert IN ) +{ + Pixel OUT; + const float4 halfPixel = { -0.5, 0.5, -0.5, 0.5 }; + OUT.position = float4(IN.position,1.0); //Transform_ObjectToClip( IN.position ); + + //float2 uv = IN.texCoords + rtParams0.xy; + float2 uv = viewportCoordToRenderTarget( IN.texCoords, rtParams0 ); + OUT.texCoords = uv.xxyy + halfPixel * oneOverTargetSize.xxyy; + return OUT; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_CalcCoC_P.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_CalcCoC_P.glsl new file mode 100644 index 000000000..38cb099c4 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_CalcCoC_P.glsl @@ -0,0 +1,55 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" +#include "../../gl/postFX.glsl" + +// These are set by the game engine. +uniform sampler2D shrunkSampler; // Output of DofDownsample() +uniform sampler2D blurredSampler; // Blurred version of the shrunk sampler + +out vec4 OUT_col; + +// This is the pixel shader function that calculates the actual +// value used for the near circle of confusion. +// "texCoords" are 0 at the bottom left pixel and 1 at the top right. +void main() +{ + vec3 color; + float coc; + half4 blurred; + half4 shrunk; + + shrunk = texture( shrunkSampler, IN_uv0 ); + blurred = texture( blurredSampler, IN_uv1 ); + color = shrunk.rgb; + //coc = shrunk.a; + //coc = blurred.a; + //coc = max( blurred.a, shrunk.a ); + coc = 2 * max( blurred.a, shrunk.a ) - shrunk.a; + + + //OUT_col = vec4( coc.rrr, 1.0 ); + //OUT_col = vec4( color, 1.0 ); + OUT_col = vec4( color, coc ); + //OUT_col = vec4( 1.0, 0.0, 1.0, 1.0 ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_CalcCoC_V.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_CalcCoC_V.glsl new file mode 100644 index 000000000..d02ce6551 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_CalcCoC_V.glsl @@ -0,0 +1,69 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" +#include "../../../gl/torque.glsl" +#include "../../gl/postFX.glsl" + +uniform vec4 rtParams0; +uniform vec4 rtParams1; +uniform vec4 rtParams2; +uniform vec4 rtParams3; + +void main() +{ + /* + OUT_hpos = IN.pos; + OUT_uv0 = IN_uv; + OUT_uv1 = IN_uv; + OUT_uv2 = IN_uv; + OUT_uv3 = IN_uv; + */ + + /* + OUT_hpos = IN_pos; + OUT_uv0 = IN_uv + rtParams0.xy; + OUT_uv1 = IN_uv + rtParams1.xy; + OUT_uv2 = IN_uv + rtParams2.xy; + OUT_uv3 = IN_uv + rtParams3.xy; + */ + + /* + OUT_hpos = IN_pos; + OUT_uv0 = IN_uv * rtParams0.zw; + OUT_uv1 = IN_uv * rtParams1.zw; + OUT_uv2 = IN_uv * rtParams2.zw; + OUT_uv3 = IN_uv * rtParams3.zw; + */ + + + OUT_hpos = IN_pos; + OUT_uv0 = viewportCoordToRenderTarget( IN_uv, rtParams0 ); + OUT_uv1 = viewportCoordToRenderTarget( IN_uv, rtParams1 ); + OUT_uv2 = viewportCoordToRenderTarget( IN_uv, rtParams2 ); + OUT_uv3 = viewportCoordToRenderTarget( IN_uv, rtParams3 ); + + + OUT_wsEyeRay = IN_wsEyeRay; + + correctSSP(gl_Position);; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_DownSample_P.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_DownSample_P.glsl new file mode 100644 index 000000000..f3c093f31 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_DownSample_P.glsl @@ -0,0 +1,143 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" +#include "shadergen:/autogenConditioners.h" + +// These are set by the game engine. +// The render target size is one-quarter the scene rendering size. +uniform sampler2D colorSampler; +uniform sampler2D depthSampler; +uniform vec2 dofEqWorld; +uniform float depthOffset; +uniform vec2 targetSize; +uniform float maxWorldCoC; +//uniform vec2 dofEqWeapon; +//uniform vec2 dofRowDelta; // vec2( 0, 0.25 / renderTargetHeight ) + +in vec2 tcColor0; +#define IN_tcColor0 tcColor0 +in vec2 tcColor1; +#define IN_tcColor1 tcColor1 +in vec2 tcDepth0; +#define IN_tcDepth0 tcDepth0 +in vec2 tcDepth1; +#define IN_tcDepth1 tcDepth1 +in vec2 tcDepth2; +#define IN_tcDepth2 tcDepth2 +in vec2 tcDepth3; +#define IN_tcDepth3 tcDepth3 + +out vec4 OUT_col; + +void main() +{ + //return vec4( 1.0, 0.0, 1.0, 1.0 ); + + vec2 dofRowDelta = vec2( 0, 0.25 / targetSize.y ); + + //vec2 dofEqWorld = vec2( -60, 1.0 ); + + half3 color; + half maxCoc; + vec4 depth; + half4 viewCoc; + half4 sceneCoc; + half4 curCoc; + half4 coc; + vec2 rowOfs[4]; + + // "rowOfs" reduces how many moves PS2.0 uses to emulate swizzling. + rowOfs[0] = vec2(0); + rowOfs[1] = dofRowDelta.xy; + rowOfs[2] = dofRowDelta.xy * 2; + rowOfs[3] = dofRowDelta.xy * 3; + + // Use bilinear filtering to average 4 color samples for free. + color = half3(0); + color += texture( colorSampler, IN_tcColor0.xy + rowOfs[0] ).rgb; + color += texture( colorSampler, IN_tcColor1.xy + rowOfs[0] ).rgb; + color += texture( colorSampler, IN_tcColor0.xy + rowOfs[2] ).rgb; + color += texture( colorSampler, IN_tcColor1.xy + rowOfs[2] ).rgb; + color /= 4; + + // Process 4 samples at a time to use vector hardware efficiently. + // The CoC will be 1 if the depth is negative, so use "min" to pick + // between "sceneCoc" and "viewCoc". + + coc = half4(0); + for ( int i = 0; i < 4; i++ ) + { + depth[0] = deferredUncondition( depthSampler, ( IN_tcDepth0.xy + rowOfs[i] ) ).w; + depth[1] = deferredUncondition( depthSampler, ( IN_tcDepth1.xy + rowOfs[i] ) ).w; + depth[2] = deferredUncondition( depthSampler, ( IN_tcDepth2.xy + rowOfs[i] ) ).w; + depth[3] = deferredUncondition( depthSampler, ( IN_tcDepth3.xy + rowOfs[i] ) ).w; + + // @todo OPENGL INTEL need review + coc = max( coc, clamp( half4(dofEqWorld.x) * depth + half4(dofEqWorld.y), half4(0.0), half4(maxWorldCoC) ) ); + } + + /* + depth[0] = texture( depthSampler, pixel.tcDepth0.xy + rowOfs[0] ).r; + depth[1] = texture( depthSampler, pixel.tcDepth1.xy + rowOfs[0] ).r; + depth[2] = texture( depthSampler, pixel.tcDepth2.xy + rowOfs[0] ).r; + depth[3] = texture( depthSampler, pixel.tcDepth3.xy + rowOfs[0] ).r; + viewCoc = saturate( dofEqWeapon.x * -depth + dofEqWeapon.y ); + sceneCoc = saturate( dofEqWorld.x * depth + dofEqWorld.y ); + curCoc = min( viewCoc, sceneCoc ); + coc = curCoc; + + depth[0] = texture( depthSampler, pixel.tcDepth0.xy + rowOfs[1] ).r; + depth[1] = texture( depthSampler, pixel.tcDepth1.xy + rowOfs[1] ).r; + depth[2] = texture( depthSampler, pixel.tcDepth2.xy + rowOfs[1] ).r; + depth[3] = texture( depthSampler, pixel.tcDepth3.xy + rowOfs[1] ).r; + viewCoc = saturate( dofEqWeapon.x * -depth + dofEqWeapon.y ); + sceneCoc = saturate( dofEqWorld.x * depth + dofEqWorld.y ); + curCoc = min( viewCoc, sceneCoc ); + coc = max( coc, curCoc ); + + depth[0] = texture( depthSampler, pixel.tcDepth0.xy + rowOfs[2] ).r; + depth[1] = texture( depthSampler, pixel.tcDepth1.xy + rowOfs[2] ).r; + depth[2] = texture( depthSampler, pixel.tcDepth2.xy + rowOfs[2] ).r; + depth[3] = texture( depthSampler, pixel.tcDepth3.xy + rowOfs[2] ).r; + viewCoc = saturate( dofEqWeapon.x * -depth + dofEqWeapon.y ); + sceneCoc = saturate( dofEqWorld.x * depth + dofEqWorld.y ); + curCoc = min( viewCoc, sceneCoc ); + coc = max( coc, curCoc ); + + depth[0] = texture( depthSampler, pixel.tcDepth0.xy + rowOfs[3] ).r; + depth[1] = texture( depthSampler, pixel.tcDepth1.xy + rowOfs[3] ).r; + depth[2] = texture( depthSampler, pixel.tcDepth2.xy + rowOfs[3] ).r; + depth[3] = texture( depthSampler, pixel.tcDepth3.xy + rowOfs[3] ).r; + viewCoc = saturate( dofEqWeapon.x * -depth + dofEqWeapon.y ); + sceneCoc = saturate( dofEqWorld.x * depth + dofEqWorld.y ); + curCoc = min( viewCoc, sceneCoc ); + coc = max( coc, curCoc ); + */ + + maxCoc = max( max( coc[0], coc[1] ), max( coc[2], coc[3] ) ); + + //OUT_col = half4( 1.0, 0.0, 1.0, 1.0 ); + OUT_col = half4( color, maxCoc ); + //OUT_col = half4( color, 1.0f ); + //OUT_col = half4( maxCoc.rrr, 1.0 ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_DownSample_V.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_DownSample_V.glsl new file mode 100644 index 000000000..b8e840c9e --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_DownSample_V.glsl @@ -0,0 +1,67 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" +#include "../../../gl/torque.glsl" + +in vec4 vPosition; +in vec2 vTexCoord0; +in vec3 vTexCoord1; + +#define IN_pos vPosition +#define IN_tc vTexCoord0 +#define IN_wsEyeRay vTexCoord1 + +#define OUT_position gl_Position + +out vec2 tcColor0; +#define OUT_tcColor0 tcColor0 +out vec2 tcColor1; +#define OUT_tcColor1 tcColor1 +out vec2 tcDepth0; +#define OUT_tcDepth0 tcDepth0 +out vec2 tcDepth1; +#define OUT_tcDepth1 tcDepth1 +out vec2 tcDepth2; +#define OUT_tcDepth2 tcDepth2 +out vec2 tcDepth3; +#define OUT_tcDepth3 tcDepth3 + + +uniform vec4 rtParams0; +uniform vec2 oneOverTargetSize; + +void main() +{ + OUT_position = IN_pos; + + vec2 uv = viewportCoordToRenderTarget( IN_tc, rtParams0 ); + //OUT_position = tMul( IN_pos, modelView ); + OUT_tcColor1 = uv + vec2( +1.0, -0.0 ) * oneOverTargetSize; + OUT_tcColor0 = uv + vec2( -1.0, -0.0 ) * oneOverTargetSize; + OUT_tcDepth0 = uv + vec2( -0.5, -0.0 ) * oneOverTargetSize; + OUT_tcDepth1 = uv + vec2( -1.5, -0.0 ) * oneOverTargetSize; + OUT_tcDepth2 = uv + vec2( +1.5, -0.0 ) * oneOverTargetSize; + OUT_tcDepth3 = uv + vec2( +2.5, -0.0 ) * oneOverTargetSize; + + correctSSP(gl_Position); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_Final_P.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_Final_P.glsl new file mode 100644 index 000000000..9b976ba1e --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_Final_P.glsl @@ -0,0 +1,147 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" +#include "shadergen:/autogenConditioners.h" +#include "../../gl/postFX.glsl" + +uniform sampler2D colorSampler; // Original source image +uniform sampler2D smallBlurSampler; // Output of SmallBlurPS() +uniform sampler2D largeBlurSampler; // Blurred output of DofDownsample() +uniform sampler2D depthSampler; // +uniform vec2 oneOverTargetSize; +uniform vec4 dofLerpScale; +uniform vec4 dofLerpBias; +uniform vec3 dofEqFar; +uniform float maxFarCoC; + +//static float d0 = 0.1; +//static float d1 = 0.1; +//static float d2 = 0.8; +//static vec4 dofLerpScale = vec4( -1.0 / d0, -1.0 / d1, -1.0 / d2, 1.0 / d2 ); +//static vec4 dofLerpBias = vec4( 1.0, (1.0 - d2) / d1, 1.0 / d2, (d2 - 1.0) / d2 ); +//static vec3 dofEqFar = vec3( 2.0, 0.0, 1.0 ); + +out vec4 OUT_col; + +vec4 tex2Doffset( sampler2D s, vec2 tc, vec2 offset ) +{ + return texture( s, tc + offset * oneOverTargetSize ); +} + +half3 GetSmallBlurSample( vec2 tc ) +{ + half3 sum; + const half weight = 4.0 / 17; + sum = half3(0); // Unblurred sample done by alpha blending + //sum += weight * tex2Doffset( colorSampler, tc, vec2( 0, 0 ) ).rgb; + sum += weight * tex2Doffset( colorSampler, tc, vec2( +0.5, -1.5 ) ).rgb; + sum += weight * tex2Doffset( colorSampler, tc, vec2( -1.5, -0.5 ) ).rgb; + sum += weight * tex2Doffset( colorSampler, tc, vec2( -0.5, +1.5 ) ).rgb; + sum += weight * tex2Doffset( colorSampler, tc, vec2( +1.5, +0.5 ) ).rgb; + return sum; +} + +half4 InterpolateDof( half3 small, half3 med, half3 large, half t ) +{ + //t = 2; + half4 weights; + half3 color; + half alpha; + + // Efficiently calculate the cross-blend weights for each sample. + // Let the unblurred sample to small blur fade happen over distance + // d0, the small to medium blur over distance d1, and the medium to + // large blur over distance d2, where d0 + d1 + d2 = 1. + //vec4 dofLerpScale = vec4( -1 / d0, -1 / d1, -1 / d2, 1 / d2 ); + //vec4 dofLerpBias = vec4( 1, (1 – d2) / d1, 1 / d2, (d2 – 1) / d2 ); + + weights = saturate( t * dofLerpScale + dofLerpBias ); + weights.yz = min( weights.yz, 1 - weights.xy ); + + // Unblurred sample with weight "weights.x" done by alpha blending + color = weights.y * small + weights.z * med + weights.w * large; + //color = med; + alpha = dot( weights.yzw, half3( 16.0 / 17, 1.0, 1.0 ) ); + //alpha = 0.0; + + return half4( color, alpha ); +} + +void main() +{ + //return half4( 1,0,1,1 ); + //return half4( texture( colorSampler, IN_uv0 ).rgb, 1.0 ); + //return half4( texture( colorSampler, texCoords ).rgb, 0 ); + half3 small; + half4 med; + half3 large; + half depth; + half nearCoc; + half farCoc; + half coc; + + small = GetSmallBlurSample( IN_uv0 ); + //small = half3( 1,0,0 ); + //return half4( small, 1.0 ); + med = texture( smallBlurSampler, IN_uv1 ); + //med.rgb = half3( 0,1,0 ); + //return half4(med.rgb, 0.0); + large = texture( largeBlurSampler, IN_uv2 ).rgb; + //large = half3( 0,0,1 ); + //return large; + //return half4(large.rgb,1.0); + nearCoc = med.a; + + // Since the med blur texture is screwed up currently + // replace it with the large, but this needs to be fixed. + //med.rgb = large; + + //nearCoc = 0; + depth = deferredUncondition( depthSampler, IN_uv3 ).w; + //return half4(depth.rrr,1); + //return half4(nearCoc.rrr,1.0); + + if (depth > 0.999 ) + { + coc = nearCoc; // We don't want to blur the sky. + //coc = 0; + } + else + { + // dofEqFar.x and dofEqFar.y specify the linear ramp to convert + // to depth for the distant out-of-focus region. + // dofEqFar.z is the ratio of the far to the near blur radius. + farCoc = clamp( dofEqFar.x * depth + dofEqFar.y, 0.0, maxFarCoC ); + coc = max( nearCoc, farCoc * dofEqFar.z ); + //coc = nearCoc; + } + + //coc = nearCoc; + //coc = farCoc; + //return half4(coc.rrr,0.5); + //return half4(farCoc.rrr,1); + //return half4(nearCoc.rrr,1); + + //return half4( 1,0,1,0 ); + OUT_col = InterpolateDof( small, med.rgb, large, coc ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_Final_V.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_Final_V.glsl new file mode 100644 index 000000000..abc91246e --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_Final_V.glsl @@ -0,0 +1,71 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" +#include "../../../gl/torque.glsl" +#include "../../gl/postFX.glsl" + +uniform vec4 rtParams0; +uniform vec4 rtParams1; +uniform vec4 rtParams2; +uniform vec4 rtParams3; +uniform vec2 oneOverTargetSize; + +void main() +{ + /* + OUT.hpos = IN_pos; + OUT_uv0 = IN_uv; + OUT_uv1 = IN_uv; + OUT_uv2 = IN_uv; + OUT_uv3 = IN_uv; + */ + + /* + OUT_hpos = IN_pos; + OUT_uv0 = IN_uv + rtParams0.xy; + OUT_uv1 = IN_uv + rtParams1.xy; + OUT_uv2 = IN_uv + rtParams2.xy; + OUT_uv3 = IN_uv + rtParams3.xy; + */ + + + /* + OUT_hpos = IN_pos; + OUT_uv0 = IN_uv * rtParams0.zw; + OUT_uv1 = IN_uv * rtParams1.zw; + OUT_uv2 = IN_uv * rtParams2.zw; + OUT_uv3 = IN_uv * rtParams3.zw; + */ + + + OUT_hpos = IN_pos; + OUT_uv0 = viewportCoordToRenderTarget( IN_uv, rtParams0 ); + OUT_uv1 = viewportCoordToRenderTarget( IN_uv, rtParams1 ); // + vec2( -5, 1 ) * oneOverTargetSize; + OUT_uv2 = viewportCoordToRenderTarget( IN_uv, rtParams2 ); + OUT_uv3 = viewportCoordToRenderTarget( IN_uv, rtParams3 ); + + + OUT_wsEyeRay = IN_wsEyeRay; + + correctSSP(gl_Position); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_Gausian_P.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_Gausian_P.glsl new file mode 100644 index 000000000..61e7697af --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_Gausian_P.glsl @@ -0,0 +1,68 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" +#include "shadergen:/autogenConditioners.h" + +in vec3 wsEyeRay; +#define IN_wsEyeRay wsEyeRay +in vec2 uv0; +#define IN_uv0 uv0 +in vec2 uv1; +#define IN_uv1 uv1 +in vec2 uv2; +#define IN_uv2 uv2 +in vec2 uv3; +#define IN_uv3 uv3 +in vec2 uv4; +#define IN_uv4 uv4 +in vec2 uv5; +#define IN_uv5 uv5 +in vec2 uv6; +#define IN_uv6 uv6 +in vec2 uv7; +#define IN_uv7 uv7 + +out vec4 OUT_col; + +uniform sampler2D diffuseMap; + +void main() +{ + vec4 kernel = vec4( 0.175, 0.275, 0.375, 0.475 ) * 0.5 / 1.3; //25f; + + OUT_col = vec4(0); + OUT_col += texture( diffuseMap, IN_uv0 ) * kernel.x; + OUT_col += texture( diffuseMap, IN_uv1 ) * kernel.y; + OUT_col += texture( diffuseMap, IN_uv2 ) * kernel.z; + OUT_col += texture( diffuseMap, IN_uv3 ) * kernel.w; + + OUT_col += texture( diffuseMap, IN_uv4 ) * kernel.x; + OUT_col += texture( diffuseMap, IN_uv5 ) * kernel.y; + OUT_col += texture( diffuseMap, IN_uv6 ) * kernel.z; + OUT_col += texture( diffuseMap, IN_uv7 ) * kernel.w; + + // Calculate a lumenance value in the alpha so we + // can use alpha test to save fillrate. + //vec3 rgb2lum = vec3( 0.30, 0.59, 0.11 ); + //OUT_col.a = dot( OUT_col.rgb, rgb2lum ); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_Gausian_V.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_Gausian_V.glsl new file mode 100644 index 000000000..c77e23c53 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_Gausian_V.glsl @@ -0,0 +1,91 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" +#include "../../../gl/torque.glsl" + +in vec4 vPosition; +in vec2 vTexCoord0; +in vec3 vTexCoord1; + +#define IN_pos vPosition +#define _IN_uv vTexCoord0 +#define IN_wsEyeRay vTexCoord1 + +#define OUT_hpos gl_Position +out vec3 wsEyeRay; +#define OUT_wsEyeRay wsEyeRay +out vec2 uv0; +#define OUT_uv0 uv0 +out vec2 uv1; +#define OUT_uv1 uv1 +out vec2 uv2; +#define OUT_uv2 uv2 +out vec2 uv3; +#define OUT_uv3 uv3 +out vec2 uv4; +#define OUT_uv4 uv4 +out vec2 uv5; +#define OUT_uv5 uv5 +out vec2 uv6; +#define OUT_uv6 uv6 +out vec2 uv7; +#define OUT_uv7 uv7 + +uniform vec2 texSize0; +uniform vec4 rtParams0; +uniform vec2 oneOverTargetSize; + + +void main() +{ + OUT_hpos = IN_pos; + + vec2 IN_uv = viewportCoordToRenderTarget( _IN_uv, rtParams0 ); + + // I don't know why this offset is necessary, but it is. + //IN_uv = IN_uv * oneOverTargetSize; + + OUT_uv0 = IN_uv + ( ( BLUR_DIR * 3.5f ) / texSize0 ); + OUT_uv1 = IN_uv + ( ( BLUR_DIR * 2.5f ) / texSize0 ); + OUT_uv2 = IN_uv + ( ( BLUR_DIR * 1.5f ) / texSize0 ); + OUT_uv3 = IN_uv + ( ( BLUR_DIR * 0.5f ) / texSize0 ); + + OUT_uv4 = IN_uv - ( ( BLUR_DIR * 3.5f ) / texSize0 ); + OUT_uv5 = IN_uv - ( ( BLUR_DIR * 2.5f ) / texSize0 ); + OUT_uv6 = IN_uv - ( ( BLUR_DIR * 1.5f ) / texSize0 ); + OUT_uv7 = IN_uv - ( ( BLUR_DIR * 0.5f ) / texSize0 ); + + /* + OUT_uv0 = viewportCoordToRenderTarget( OUT_uv0, rtParams0 ); + OUT_uv1 = viewportCoordToRenderTarget( OUT_uv1, rtParams0 ); + OUT_uv2 = viewportCoordToRenderTarget( OUT_uv2, rtParams0 ); + OUT_uv3 = viewportCoordToRenderTarget( OUT_uv3, rtParams0 ); + + OUT_uv4 = viewportCoordToRenderTarget( OUT_uv4, rtParams0 ); + OUT_uv5 = viewportCoordToRenderTarget( OUT_uv5, rtParams0 ); + OUT_uv6 = viewportCoordToRenderTarget( OUT_uv6, rtParams0 ); + OUT_uv7 = viewportCoordToRenderTarget( OUT_uv7, rtParams0 ); + */ + + correctSSP(gl_Position); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_Passthrough_V.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_Passthrough_V.glsl new file mode 100644 index 000000000..bd02fb7d4 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_Passthrough_V.glsl @@ -0,0 +1,69 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" +#include "../../../gl/torque.glsl" +#include "../../gl/postFX.glsl" + +uniform vec4 rtParams0; +uniform vec4 rtParams1; +uniform vec4 rtParams2; +uniform vec4 rtParams3; + +void main() +{ + /* + OUT.hpos = IN_pos; + OUT_uv0 = IN_uv; + OUT_uv1 = IN_uv; + OUT_uv2 = IN_uv; + OUT_uv3 = IN_uv; + */ + + /* + OUT_hpos = IN_pos; + OUT_uv0 = IN_uv + rtParams0.xy; + OUT_uv1 = IN_uv + rtParams1.xy; + OUT_uv2 = IN_uv + rtParams2.xy; + OUT_uv3 = IN_uv + rtParams3.xy; + */ + + /* + OUT_hpos = IN_pos; + OUT_uv0 = IN_uv * rtParams0.zw; + OUT_uv1 = IN_uv * rtParams1.zw; + OUT_uv2 = IN_uv * rtParams2.zw; + OUT_uv3 = IN_uv * rtParams3.zw; + */ + + + OUT_hpos = IN_pos; + OUT_uv0 = viewportCoordToRenderTarget( IN_uv, rtParams0 ); + OUT_uv1 = viewportCoordToRenderTarget( IN_uv, rtParams1 ); + OUT_uv2 = viewportCoordToRenderTarget( IN_uv, rtParams2 ); + OUT_uv3 = viewportCoordToRenderTarget( IN_uv, rtParams3 ); + + + OUT_wsEyeRay = IN_wsEyeRay; + + correctSSP(gl_Position); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_SmallBlur_P.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_SmallBlur_P.glsl new file mode 100644 index 000000000..ae94edd78 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_SmallBlur_P.glsl @@ -0,0 +1,46 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// This vertex and pixel shader applies a 3 x 3 blur to the image in +// colorMapSampler, which is the same size as the render target. +// The sample weights are 1/16 in the corners, 2/16 on the edges, +// and 4/16 in the center. + +#include "../../../gl/hlslCompat.glsl" + +uniform sampler2D colorSampler; // Output of DofNearCoc() + +in vec4 texCoords; +#define IN_texCoords texCoords + +out vec4 OUT_col; + +void main() +{ + vec4 color; + color = vec4(0.0); + color += texture( colorSampler, IN_texCoords.xz ); + color += texture( colorSampler, IN_texCoords.yz ); + color += texture( colorSampler, IN_texCoords.xw ); + color += texture( colorSampler, IN_texCoords.yw ); + OUT_col = color / 4.0; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_SmallBlur_V.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_SmallBlur_V.glsl new file mode 100644 index 000000000..413abd352 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/dof/gl/DOF_SmallBlur_V.glsl @@ -0,0 +1,54 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// This vertex and pixel shader applies a 3 x 3 blur to the image in +// colorMapSampler, which is the same size as the render target. +// The sample weights are 1/16 in the corners, 2/16 on the edges, +// and 4/16 in the center. + +#include "../../../gl/hlslCompat.glsl" +#include "../../../gl/torque.glsl" + +in vec4 vPosition; +in vec2 vTexCoord0; + +#define IN_position vPosition +#define IN_texCoords vTexCoord0 + +#define OUT_position gl_Position +out vec4 texCoords; +#define OUT_texCoords texCoords + +uniform vec2 oneOverTargetSize; +uniform vec4 rtParams0; + +void main() +{ + const vec4 halfPixel = vec4( -0.5, 0.5, -0.5, 0.5 ); + OUT_position = IN_position; //Transform_ObjectToClip( IN_position ); + + //vec2 uv = IN_texCoords + rtParams0.xy; + vec2 uv = viewportCoordToRenderTarget( IN_texCoords, rtParams0 ); + OUT_texCoords = uv.xxyy + halfPixel * oneOverTargetSize.xxyy; + + correctSSP(gl_Position); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/edgeaa/dbgEdgeDisplayP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/edgeaa/dbgEdgeDisplayP.hlsl new file mode 100644 index 000000000..fbd529031 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/edgeaa/dbgEdgeDisplayP.hlsl @@ -0,0 +1,30 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../postFx.hlsl" + +TORQUE_UNIFORM_SAMPLER2D(edgeBuffer); + +float4 main( PFXVertToPix IN ) : TORQUE_TARGET0 +{ + return float4( TORQUE_TEX2D( edgeBuffer, IN.uv0 ).rrr, 1.0 ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/edgeaa/edgeAAP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/edgeaa/edgeAAP.hlsl new file mode 100644 index 000000000..f5a71687d --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/edgeaa/edgeAAP.hlsl @@ -0,0 +1,66 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../postFx.hlsl" + +TORQUE_UNIFORM_SAMPLER2D(edgeBuffer,0); +TORQUE_UNIFORM_SAMPLER2D(backBuffer, 1); +uniform float2 targetSize; + +float4 main( PFXVertToPix IN ) : TORQUE_TARGET0 +{ + float2 pixelSize = 1.0 / targetSize; + + // Sample edge buffer, bail if not on an edge + float edgeSample = TORQUE_TEX2D(edgeBuffer, IN.uv0).r; + clip(edgeSample - 1e-6); + + // Ok we're on an edge, so multi-tap sample, average, and return + float2 offsets[9] = { + float2( 0.0, 0.0), + float2(-1.0, -1.0), + float2( 0.0, -1.0), + float2( 1.0, -1.0), + float2( 1.0, 0.0), + float2( 1.0, 1.0), + float2( 0.0, 1.0), + float2(-1.0, 1.0), + float2(-1.0, 0.0), + }; + + float4 accumColor = 0; + for(int i = 0; i < 9; i++) + { + // Multiply the intensity of the edge, by the UV, so that things which maybe + // aren't quite full edges get sub-pixel sampling to reduce artifacts + + // Scaling offsets by 0.5 to reduce the range bluriness from extending to + // far outward from the edge. + + float2 offsetUV = IN.uv1 + edgeSample * ( offsets[i] * 0.5 ) * pixelSize;//rtWidthHeightInvWidthNegHeight.zw; + //offsetUV *= 0.999; + accumColor += TORQUE_TEX2D(backBuffer, offsetUV); + } + accumColor /= 9.0; + + return accumColor; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/edgeaa/edgeAAV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/edgeaa/edgeAAV.hlsl new file mode 100644 index 000000000..4718b40f5 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/edgeaa/edgeAAV.hlsl @@ -0,0 +1,45 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "./../postFx.hlsl" +#include "./../../torque.hlsl" + + +uniform float4 rtParams0; +uniform float4 rtParams1; +uniform float4 rtParams2; +uniform float4 rtParams3; + +PFXVertToPix main( PFXVert IN ) +{ + PFXVertToPix OUT; + + OUT.hpos = IN.pos; + OUT.uv0 = viewportCoordToRenderTarget( IN.uv, rtParams0 ); + OUT.uv1 = viewportCoordToRenderTarget( IN.uv, rtParams1 ); + OUT.uv2 = viewportCoordToRenderTarget( IN.uv, rtParams2 ); + OUT.uv3 = viewportCoordToRenderTarget( IN.uv, rtParams3 ); + + OUT.wsEyeRay = IN.wsEyeRay; + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/edgeaa/edgeDetectP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/edgeaa/edgeDetectP.hlsl new file mode 100644 index 000000000..c8bfb2153 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/edgeaa/edgeDetectP.hlsl @@ -0,0 +1,93 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../postFx.hlsl" +#include "../../shaderModelAutoGen.hlsl" + +TORQUE_UNIFORM_SAMPLER2D(deferredBuffer,0); + +// GPU Gems 3, pg 443-444 +float GetEdgeWeight(float2 uv0, in float2 targetSize) +{ + float2 offsets[9] = { + float2( 0.0, 0.0), + float2(-1.0, -1.0), + float2( 0.0, -1.0), + float2( 1.0, -1.0), + float2( 1.0, 0.0), + float2( 1.0, 1.0), + float2( 0.0, 1.0), + float2(-1.0, 1.0), + float2(-1.0, 0.0), + }; + + + float2 PixelSize = 1.0 / targetSize; + + float Depth[9]; + float3 Normal[9]; + + [unroll] //no getting around this, may as well save the annoying warning message + for(int i = 0; i < 9; i++) + { + float2 uv = uv0 + offsets[i] * PixelSize; + float4 gbSample = TORQUE_DEFERRED_UNCONDITION( deferredBuffer, uv ); + Depth[i] = gbSample.a; + Normal[i] = gbSample.rgb; + } + + float4 Deltas1 = float4(Depth[1], Depth[2], Depth[3], Depth[4]); + float4 Deltas2 = float4(Depth[5], Depth[6], Depth[7], Depth[8]); + + Deltas1 = abs(Deltas1 - Depth[0]); + Deltas2 = abs(Depth[0] - Deltas2); + + float4 maxDeltas = max(Deltas1, Deltas2); + float4 minDeltas = max(min(Deltas1, Deltas2), 0.00001); + + float4 depthResults = step(minDeltas * 25.0, maxDeltas); + + Deltas1.x = dot(Normal[1], Normal[0]); + Deltas1.y = dot(Normal[2], Normal[0]); + Deltas1.z = dot(Normal[3], Normal[0]); + Deltas1.w = dot(Normal[4], Normal[0]); + + Deltas2.x = dot(Normal[5], Normal[0]); + Deltas2.y = dot(Normal[6], Normal[0]); + Deltas2.z = dot(Normal[7], Normal[0]); + Deltas2.w = dot(Normal[8], Normal[0]); + + Deltas1 = abs(Deltas1 - Deltas2); + + float4 normalResults = step(0.4, Deltas1); + + normalResults = max(normalResults, depthResults); + + return dot(normalResults, float4(1.0, 1.0, 1.0, 1.0)) * 0.25; +} + +uniform float2 targetSize; + +float4 main( PFXVertToPix IN ) : TORQUE_TARGET0 +{ + return GetEdgeWeight(IN.uv0, targetSize);//rtWidthHeightInvWidthNegHeight.zw); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/edgeaa/gl/dbgEdgeDisplayP.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/edgeaa/gl/dbgEdgeDisplayP.glsl new file mode 100644 index 000000000..ccc3b8ba5 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/edgeaa/gl/dbgEdgeDisplayP.glsl @@ -0,0 +1,36 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" +#include "shadergen:/autogenConditioners.h" + +in vec2 uv0; +#define IN_uv0 uv0 + +uniform sampler2D edgeBuffer; + +out vec4 OUT_col; + +void main() +{ + OUT_col = vec4( texture( edgeBuffer, IN_uv0 ).rrr, 1.0 ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/edgeaa/gl/edgeAAP.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/edgeaa/gl/edgeAAP.glsl new file mode 100644 index 000000000..216dc8725 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/edgeaa/gl/edgeAAP.glsl @@ -0,0 +1,70 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" +#include "shadergen:/autogenConditioners.h" +#include "../../gl/postFX.glsl" + +uniform sampler2D edgeBuffer; +uniform sampler2D backBuffer; +uniform vec2 targetSize; + +out vec4 OUT_col; + +void main() +{ + vec2 pixelSize = 1.0 / targetSize; + + // Sample edge buffer, bail if not on an edge + float edgeSample = texture(edgeBuffer, IN_uv0).r; + clip(edgeSample - 1e-6); + + // Ok we're on an edge, so multi-tap sample, average, and return + vec2 offsets[9] = vec2[]( + vec2( 0.0, 0.0), + vec2(-1.0, -1.0), + vec2( 0.0, -1.0), + vec2( 1.0, -1.0), + vec2( 1.0, 0.0), + vec2( 1.0, 1.0), + vec2( 0.0, 1.0), + vec2(-1.0, 1.0), + vec2(-1.0, 0.0) + ); + + vec4 accumColor = vec4(0.0); + for(int i = 0; i < 9; i++) + { + // Multiply the intensity of the edge, by the UV, so that things which maybe + // aren't quite full edges get sub-pixel sampling to reduce artifacts + + // Scaling offsets by 0.5 to reduce the range bluriness from extending to + // far outward from the edge. + + vec2 offsetUV = IN_uv1 + edgeSample * ( offsets[i] * 0.5 ) * pixelSize;//rtWidthHeightInvWidthNegHeight.zw; + //offsetUV *= 0.999; + accumColor+= texture(backBuffer, offsetUV); + } + accumColor /= 9.0; + + OUT_col = accumColor; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/edgeaa/gl/edgeAAV.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/edgeaa/gl/edgeAAV.glsl new file mode 100644 index 000000000..975532272 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/edgeaa/gl/edgeAAV.glsl @@ -0,0 +1,43 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" +#include "../../../gl/torque.glsl" +#include "../../gl/postFX.glsl" + +uniform vec4 rtParams0; +uniform vec4 rtParams1; +uniform vec4 rtParams2; +uniform vec4 rtParams3; + +void main() +{ + OUT_hpos = IN_pos; + OUT_uv0 = viewportCoordToRenderTarget( IN_uv, rtParams0 ); + OUT_uv1 = viewportCoordToRenderTarget( IN_uv, rtParams1 ); + OUT_uv2 = viewportCoordToRenderTarget( IN_uv, rtParams2 ); + OUT_uv3 = viewportCoordToRenderTarget( IN_uv, rtParams3 ); + + OUT_wsEyeRay = IN_wsEyeRay; + + correctSSP(gl_Position); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/edgeaa/gl/edgeDetectP.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/edgeaa/gl/edgeDetectP.glsl new file mode 100644 index 000000000..02507eee8 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/edgeaa/gl/edgeDetectP.glsl @@ -0,0 +1,96 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" +#include "shadergen:/autogenConditioners.h" + +// GPU Gems 3, pg 443-444 +float GetEdgeWeight(vec2 uv0, in sampler2D deferredBuffer, in vec2 targetSize) +{ + vec2 offsets[9] = vec2[]( + vec2( 0.0, 0.0), + vec2(-1.0, -1.0), + vec2( 0.0, -1.0), + vec2( 1.0, -1.0), + vec2( 1.0, 0.0), + vec2( 1.0, 1.0), + vec2( 0.0, 1.0), + vec2(-1.0, 1.0), + vec2(-1.0, 0.0) + ); + + + vec2 PixelSize = 1.0 / targetSize; + + float Depth[9]; + vec3 Normal[9]; + + for(int i = 0; i < 9; i++) + { + vec2 uv = uv0 + offsets[i] * PixelSize; + vec4 gbSample = deferredUncondition( deferredBuffer, uv ); + Depth[i] = gbSample.a; + Normal[i] = gbSample.rgb; + } + + vec4 Deltas1 = vec4(Depth[1], Depth[2], Depth[3], Depth[4]); + vec4 Deltas2 = vec4(Depth[5], Depth[6], Depth[7], Depth[8]); + + Deltas1 = abs(Deltas1 - Depth[0]); + Deltas2 = abs(Depth[0] - Deltas2); + + vec4 maxDeltas = max(Deltas1, Deltas2); + vec4 minDeltas = max(min(Deltas1, Deltas2), 0.00001); + + vec4 depthResults = step(minDeltas * 25.0, maxDeltas); + + Deltas1.x = dot(Normal[1], Normal[0]); + Deltas1.y = dot(Normal[2], Normal[0]); + Deltas1.z = dot(Normal[3], Normal[0]); + Deltas1.w = dot(Normal[4], Normal[0]); + + Deltas2.x = dot(Normal[5], Normal[0]); + Deltas2.y = dot(Normal[6], Normal[0]); + Deltas2.z = dot(Normal[7], Normal[0]); + Deltas2.w = dot(Normal[8], Normal[0]); + + Deltas1 = abs(Deltas1 - Deltas2); + + vec4 normalResults = step(0.4, Deltas1); + + normalResults = max(normalResults, depthResults); + + return dot(normalResults, vec4(1.0, 1.0, 1.0, 1.0)) * 0.25; +} + +in vec2 uv0; +#define IN_uv0 uv0 + +uniform sampler2D deferredBuffer; +uniform vec2 targetSize; + +out vec4 OUT_col; + +void main() +{ + OUT_col = vec4( GetEdgeWeight(IN_uv0, deferredBuffer, targetSize ) );//rtWidthHeightInvWidthNegHeight.zw); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/flashP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/flashP.hlsl new file mode 100644 index 000000000..93daf3c26 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/flashP.hlsl @@ -0,0 +1,36 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "./postFx.hlsl" +#include "../torque.hlsl" + +uniform float damageFlash; +uniform float whiteOut; +TORQUE_UNIFORM_SAMPLER2D(backBuffer, 0); + +float4 main(PFXVertToPix IN) : TORQUE_TARGET0 +{ + float4 color1 = TORQUE_TEX2D(backBuffer, IN.uv0); + float4 color2 = color1 * MUL_COLOR; + float4 damage = lerp(color1,color2,damageFlash); + return lerp(damage,WHITE_COLOR,whiteOut); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/fogP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/fogP.hlsl new file mode 100644 index 000000000..9f3500f67 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/fogP.hlsl @@ -0,0 +1,47 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + + +#include "./postFx.hlsl" +#include "./../torque.hlsl" +#include "./../shaderModelAutoGen.hlsl" + +TORQUE_UNIFORM_SAMPLER2D(deferredTex, 0); +uniform float3 eyePosWorld; +uniform float4 fogColor; +uniform float3 fogData; +uniform float4 rtParams0; + +float4 main( PFXVertToPix IN ) : TORQUE_TARGET0 +{ + //float2 deferredCoord = ( IN.uv0.xy * rtParams0.zw ) + rtParams0.xy; + float depth = TORQUE_DEFERRED_UNCONDITION( deferredTex, IN.uv0 ).w; + //return float4( depth, 0, 0, 0.7 ); + + float factor = computeSceneFog( eyePosWorld, + eyePosWorld + ( IN.wsEyeRay * depth ), + fogData.x, + fogData.y, + fogData.z ); + + return hdrEncode( float4( fogColor.rgb, 1.0 - saturate( factor ) ) ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/fxaa/Fxaa3_11.h b/Templates/BaseGame/game/core/rendering/shaders/postFX/fxaa/Fxaa3_11.h new file mode 100644 index 000000000..9ca7627d4 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/fxaa/Fxaa3_11.h @@ -0,0 +1,2047 @@ +/*============================================================================ + + + NVIDIA FXAA 3.11 by TIMOTHY LOTTES + + +------------------------------------------------------------------------------ +COPYRIGHT (C) 2010, 2011 NVIDIA CORPORATION. ALL RIGHTS RESERVED. +------------------------------------------------------------------------------ +TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED +*AS IS* AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA +OR ITS SUPPLIERS BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT, OR +CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR +LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, +OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE +THIS SOFTWARE, EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + +------------------------------------------------------------------------------ + INTEGRATION CHECKLIST +------------------------------------------------------------------------------ +(1.) +In the shader source, setup defines for the desired configuration. +When providing multiple shaders (for different presets), +simply setup the defines differently in multiple files. +Example, + + #define FXAA_PC 1 + #define FXAA_HLSL_5 1 + #define FXAA_QUALITY__PRESET 12 + +Or, + + #define FXAA_360 1 + +Or, + + #define FXAA_PS3 1 + +Etc. + +(2.) +Then include this file, + + include "Fxaa3_11.h" + +(3.) +Then call the FXAA pixel shader from within your desired shader. +Look at the FXAA Quality FxaaPixelShader() for docs on inputs. +As for FXAA 3.11 all inputs for all shaders are the same +to enable easy porting between platforms. + + return FxaaPixelShader(...); + +(4.) +Insure pass prior to FXAA outputs RGBL (see next section). +Or use, + + #define FXAA_GREEN_AS_LUMA 1 + +(5.) +Setup engine to provide the following constants +which are used in the FxaaPixelShader() inputs, + + FxaaFloat2 fxaaQualityRcpFrame, + FxaaFloat4 fxaaConsoleRcpFrameOpt, + FxaaFloat4 fxaaConsoleRcpFrameOpt2, + FxaaFloat4 fxaaConsole360RcpFrameOpt2, + FxaaFloat fxaaQualitySubpix, + FxaaFloat fxaaQualityEdgeThreshold, + FxaaFloat fxaaQualityEdgeThresholdMin, + FxaaFloat fxaaConsoleEdgeSharpness, + FxaaFloat fxaaConsoleEdgeThreshold, + FxaaFloat fxaaConsoleEdgeThresholdMin, + FxaaFloat4 fxaaConsole360ConstDir + +Look at the FXAA Quality FxaaPixelShader() for docs on inputs. + +(6.) +Have FXAA vertex shader run as a full screen triangle, +and output "pos" and "fxaaConsolePosPos" +such that inputs in the pixel shader provide, + + // {xy} = center of pixel + FxaaFloat2 pos, + + // {xy__} = upper left of pixel + // {__zw} = lower right of pixel + FxaaFloat4 fxaaConsolePosPos, + +(7.) +Insure the texture sampler(s) used by FXAA are set to bilinear filtering. + + +------------------------------------------------------------------------------ + INTEGRATION - RGBL AND COLORSPACE +------------------------------------------------------------------------------ +FXAA3 requires RGBL as input unless the following is set, + + #define FXAA_GREEN_AS_LUMA 1 + +In which case the engine uses green in place of luma, +and requires RGB input is in a non-linear colorspace. + +RGB should be LDR (low dynamic range). +Specifically do FXAA after tonemapping. + +RGB data as returned by a texture fetch can be non-linear, +or linear when FXAA_GREEN_AS_LUMA is not set. +Note an "sRGB format" texture counts as linear, +because the result of a texture fetch is linear data. +Regular "RGBA8" textures in the sRGB colorspace are non-linear. + +If FXAA_GREEN_AS_LUMA is not set, +luma must be stored in the alpha channel prior to running FXAA. +This luma should be in a perceptual space (could be gamma 2.0). +Example pass before FXAA where output is gamma 2.0 encoded, + + color.rgb = ToneMap(color.rgb); // linear color output + color.rgb = sqrt(color.rgb); // gamma 2.0 color output + return color; + +To use FXAA, + + color.rgb = ToneMap(color.rgb); // linear color output + color.rgb = sqrt(color.rgb); // gamma 2.0 color output + color.a = dot(color.rgb, FxaaFloat3(0.299, 0.587, 0.114)); // compute luma + return color; + +Another example where output is linear encoded, +say for instance writing to an sRGB formated render target, +where the render target does the conversion back to sRGB after blending, + + color.rgb = ToneMap(color.rgb); // linear color output + return color; + +To use FXAA, + + color.rgb = ToneMap(color.rgb); // linear color output + color.a = sqrt(dot(color.rgb, FxaaFloat3(0.299, 0.587, 0.114))); // compute luma + return color; + +Getting luma correct is required for the algorithm to work correctly. + + +------------------------------------------------------------------------------ + BEING LINEARLY CORRECT? +------------------------------------------------------------------------------ +Applying FXAA to a framebuffer with linear RGB color will look worse. +This is very counter intuitive, but happends to be true in this case. +The reason is because dithering artifacts will be more visiable +in a linear colorspace. + + +------------------------------------------------------------------------------ + COMPLEX INTEGRATION +------------------------------------------------------------------------------ +Q. What if the engine is blending into RGB before wanting to run FXAA? + +A. In the last opaque pass prior to FXAA, + have the pass write out luma into alpha. + Then blend into RGB only. + FXAA should be able to run ok + assuming the blending pass did not any add aliasing. + This should be the common case for particles and common blending passes. + +A. Or use FXAA_GREEN_AS_LUMA. + +============================================================================*/ + +/*============================================================================ + + INTEGRATION KNOBS + +============================================================================*/ +// +// FXAA_PS3 and FXAA_360 choose the console algorithm (FXAA3 CONSOLE). +// FXAA_360_OPT is a prototype for the new optimized 360 version. +// +// 1 = Use API. +// 0 = Don't use API. +// +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_PS3 + #define FXAA_PS3 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_360 + #define FXAA_360 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_360_OPT + #define FXAA_360_OPT 0 +#endif +/*==========================================================================*/ +#ifndef FXAA_PC + // + // FXAA Quality + // The high quality PC algorithm. + // + #define FXAA_PC 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_PC_CONSOLE + // + // The console algorithm for PC is included + // for developers targeting really low spec machines. + // Likely better to just run FXAA_PC, and use a really low preset. + // + #define FXAA_PC_CONSOLE 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_GLSL_120 + #define FXAA_GLSL_120 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_GLSL_130 + #define FXAA_GLSL_130 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_HLSL_3 + #define FXAA_HLSL_3 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_HLSL_4 + #define FXAA_HLSL_4 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_HLSL_5 + #define FXAA_HLSL_5 0 +#endif +/*==========================================================================*/ +#ifndef FXAA_GREEN_AS_LUMA + // + // For those using non-linear color, + // and either not able to get luma in alpha, or not wanting to, + // this enables FXAA to run using green as a proxy for luma. + // So with this enabled, no need to pack luma in alpha. + // + // This will turn off AA on anything which lacks some amount of green. + // Pure red and blue or combination of only R and B, will get no AA. + // + // Might want to lower the settings for both, + // fxaaConsoleEdgeThresholdMin + // fxaaQualityEdgeThresholdMin + // In order to insure AA does not get turned off on colors + // which contain a minor amount of green. + // + // 1 = On. + // 0 = Off. + // + #define FXAA_GREEN_AS_LUMA 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_EARLY_EXIT + // + // Controls algorithm's early exit path. + // On PS3 turning this ON adds 2 cycles to the shader. + // On 360 turning this OFF adds 10ths of a millisecond to the shader. + // Turning this off on console will result in a more blurry image. + // So this defaults to on. + // + // 1 = On. + // 0 = Off. + // + #define FXAA_EARLY_EXIT 1 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_DISCARD + // + // Only valid for PC OpenGL currently. + // Probably will not work when FXAA_GREEN_AS_LUMA = 1. + // + // 1 = Use discard on pixels which don't need AA. + // For APIs which enable concurrent TEX+ROP from same surface. + // 0 = Return unchanged color on pixels which don't need AA. + // + #define FXAA_DISCARD 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_FAST_PIXEL_OFFSET + // + // Used for GLSL 120 only. + // + // 1 = GL API supports fast pixel offsets + // 0 = do not use fast pixel offsets + // + #ifdef GL_EXT_gpu_shader4 + #define FXAA_FAST_PIXEL_OFFSET 1 + #endif + #ifdef GL_NV_gpu_shader5 + #define FXAA_FAST_PIXEL_OFFSET 1 + #endif + #ifdef GL_ARB_gpu_shader5 + #define FXAA_FAST_PIXEL_OFFSET 1 + #endif + #ifndef FXAA_FAST_PIXEL_OFFSET + #define FXAA_FAST_PIXEL_OFFSET 0 + #endif +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_GATHER4_ALPHA + // + // 1 = API supports gather4 on alpha channel. + // 0 = API does not support gather4 on alpha channel. + // + #if (FXAA_HLSL_5 == 1) + #define FXAA_GATHER4_ALPHA 1 + #endif + #ifdef GL_ARB_gpu_shader5 + #define FXAA_GATHER4_ALPHA 1 + #endif + #ifdef GL_NV_gpu_shader5 + #define FXAA_GATHER4_ALPHA 1 + #endif + #ifndef FXAA_GATHER4_ALPHA + #define FXAA_GATHER4_ALPHA 0 + #endif +#endif + +/*============================================================================ + FXAA CONSOLE PS3 - TUNING KNOBS +============================================================================*/ +#ifndef FXAA_CONSOLE__PS3_EDGE_SHARPNESS + // + // Consoles the sharpness of edges on PS3 only. + // Non-PS3 tuning is done with shader input. + // + // Due to the PS3 being ALU bound, + // there are only two safe values here: 4 and 8. + // These options use the shaders ability to a free *|/ by 2|4|8. + // + // 8.0 is sharper + // 4.0 is softer + // 2.0 is really soft (good for vector graphics inputs) + // + #if 1 + #define FXAA_CONSOLE__PS3_EDGE_SHARPNESS 8.0 + #endif + #if 0 + #define FXAA_CONSOLE__PS3_EDGE_SHARPNESS 4.0 + #endif + #if 0 + #define FXAA_CONSOLE__PS3_EDGE_SHARPNESS 2.0 + #endif +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_CONSOLE__PS3_EDGE_THRESHOLD + // + // Only effects PS3. + // Non-PS3 tuning is done with shader input. + // + // The minimum amount of local contrast required to apply algorithm. + // The console setting has a different mapping than the quality setting. + // + // This only applies when FXAA_EARLY_EXIT is 1. + // + // Due to the PS3 being ALU bound, + // there are only two safe values here: 0.25 and 0.125. + // These options use the shaders ability to a free *|/ by 2|4|8. + // + // 0.125 leaves less aliasing, but is softer + // 0.25 leaves more aliasing, and is sharper + // + #if 1 + #define FXAA_CONSOLE__PS3_EDGE_THRESHOLD 0.125 + #else + #define FXAA_CONSOLE__PS3_EDGE_THRESHOLD 0.25 + #endif +#endif + +/*============================================================================ + FXAA QUALITY - TUNING KNOBS +------------------------------------------------------------------------------ +NOTE the other tuning knobs are now in the shader function inputs! +============================================================================*/ +#ifndef FXAA_QUALITY__PRESET + // + // Choose the quality preset. + // This needs to be compiled into the shader as it effects code. + // Best option to include multiple presets is to + // in each shader define the preset, then include this file. + // + // OPTIONS + // ----------------------------------------------------------------------- + // 10 to 15 - default medium dither (10=fastest, 15=highest quality) + // 20 to 29 - less dither, more expensive (20=fastest, 29=highest quality) + // 39 - no dither, very expensive + // + // NOTES + // ----------------------------------------------------------------------- + // 12 = slightly faster then FXAA 3.9 and higher edge quality (default) + // 13 = about same speed as FXAA 3.9 and better than 12 + // 23 = closest to FXAA 3.9 visually and performance wise + // _ = the lowest digit is directly related to performance + // _ = the highest digit is directly related to style + // + #define FXAA_QUALITY__PRESET 12 +#endif + + +/*============================================================================ + + FXAA QUALITY - PRESETS + +============================================================================*/ + +/*============================================================================ + FXAA QUALITY - MEDIUM DITHER PRESETS +============================================================================*/ +#if (FXAA_QUALITY__PRESET == 10) + #define FXAA_QUALITY__PS 3 + #define FXAA_QUALITY__P0 1.5 + #define FXAA_QUALITY__P1 3.0 + #define FXAA_QUALITY__P2 12.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 11) + #define FXAA_QUALITY__PS 4 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 3.0 + #define FXAA_QUALITY__P3 12.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 12) + #define FXAA_QUALITY__PS 5 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 4.0 + #define FXAA_QUALITY__P4 12.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 13) + #define FXAA_QUALITY__PS 6 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 4.0 + #define FXAA_QUALITY__P5 12.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 14) + #define FXAA_QUALITY__PS 7 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 4.0 + #define FXAA_QUALITY__P6 12.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 15) + #define FXAA_QUALITY__PS 8 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 4.0 + #define FXAA_QUALITY__P7 12.0 +#endif + +/*============================================================================ + FXAA QUALITY - LOW DITHER PRESETS +============================================================================*/ +#if (FXAA_QUALITY__PRESET == 20) + #define FXAA_QUALITY__PS 3 + #define FXAA_QUALITY__P0 1.5 + #define FXAA_QUALITY__P1 2.0 + #define FXAA_QUALITY__P2 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 21) + #define FXAA_QUALITY__PS 4 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 22) + #define FXAA_QUALITY__PS 5 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 23) + #define FXAA_QUALITY__PS 6 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 24) + #define FXAA_QUALITY__PS 7 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 3.0 + #define FXAA_QUALITY__P6 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 25) + #define FXAA_QUALITY__PS 8 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 4.0 + #define FXAA_QUALITY__P7 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 26) + #define FXAA_QUALITY__PS 9 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 4.0 + #define FXAA_QUALITY__P8 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 27) + #define FXAA_QUALITY__PS 10 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 2.0 + #define FXAA_QUALITY__P8 4.0 + #define FXAA_QUALITY__P9 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 28) + #define FXAA_QUALITY__PS 11 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 2.0 + #define FXAA_QUALITY__P8 2.0 + #define FXAA_QUALITY__P9 4.0 + #define FXAA_QUALITY__P10 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 29) + #define FXAA_QUALITY__PS 12 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 2.0 + #define FXAA_QUALITY__P8 2.0 + #define FXAA_QUALITY__P9 2.0 + #define FXAA_QUALITY__P10 4.0 + #define FXAA_QUALITY__P11 8.0 +#endif + +/*============================================================================ + FXAA QUALITY - EXTREME QUALITY +============================================================================*/ +#if (FXAA_QUALITY__PRESET == 39) + #define FXAA_QUALITY__PS 12 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.0 + #define FXAA_QUALITY__P2 1.0 + #define FXAA_QUALITY__P3 1.0 + #define FXAA_QUALITY__P4 1.0 + #define FXAA_QUALITY__P5 1.5 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 2.0 + #define FXAA_QUALITY__P8 2.0 + #define FXAA_QUALITY__P9 2.0 + #define FXAA_QUALITY__P10 4.0 + #define FXAA_QUALITY__P11 8.0 +#endif + + + +/*============================================================================ + + API PORTING + +============================================================================*/ +#if (FXAA_GLSL_120 == 1) || (FXAA_GLSL_130 == 1) + #define FxaaBool bool + #define FxaaDiscard discard + #define FxaaFloat float + #define FxaaFloat2 vec2 + #define FxaaFloat3 vec3 + #define FxaaFloat4 vec4 + #define FxaaHalf float + #define FxaaHalf2 vec2 + #define FxaaHalf3 vec3 + #define FxaaHalf4 vec4 + #define FxaaInt2 ivec2 + #define FxaaSat(x) clamp(x, 0.0, 1.0) + #define FxaaTex sampler2D +#else + #define FxaaBool bool + #define FxaaDiscard clip(-1) + #define FxaaFloat float + #define FxaaFloat2 float2 + #define FxaaFloat3 float3 + #define FxaaFloat4 float4 + #define FxaaHalf half + #define FxaaHalf2 half2 + #define FxaaHalf3 half3 + #define FxaaHalf4 half4 + #define FxaaSat(x) saturate(x) +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_GLSL_120 == 1) + // Requires, + // #version 120 + // And at least, + // #extension GL_EXT_gpu_shader4 : enable + // (or set FXAA_FAST_PIXEL_OFFSET 1 to work like DX9) + #define FxaaTexTop(t, p) texture2DLod(t, p, 0.0) + #if (FXAA_FAST_PIXEL_OFFSET == 1) + #define FxaaTexOff(t, p, o, r) texture2DLodOffset(t, p, 0.0, o) + #else + #define FxaaTexOff(t, p, o, r) texture2DLod(t, p + (o * r), 0.0) + #endif + #if (FXAA_GATHER4_ALPHA == 1) + // use #extension GL_ARB_gpu_shader5 : enable + #define FxaaTexAlpha4(t, p) textureGather(t, p, 3) + #define FxaaTexOffAlpha4(t, p, o) textureGatherOffset(t, p, o, 3) + #define FxaaTexGreen4(t, p) textureGather(t, p, 1) + #define FxaaTexOffGreen4(t, p, o) textureGatherOffset(t, p, o, 1) + #endif +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_GLSL_130 == 1) + // Requires "#version 130" or better + #define FxaaTexTop(t, p) textureLod(t, p, 0.0) + #define FxaaTexOff(t, p, o, r) textureLodOffset(t, p, 0.0, o) + #if (FXAA_GATHER4_ALPHA == 1) + // use #extension GL_ARB_gpu_shader5 : enable + #define FxaaTexAlpha4(t, p) textureGather(t, p, 3) + #define FxaaTexOffAlpha4(t, p, o) textureGatherOffset(t, p, o, 3) + #define FxaaTexGreen4(t, p) textureGather(t, p, 1) + #define FxaaTexOffGreen4(t, p, o) textureGatherOffset(t, p, o, 1) + #endif +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_HLSL_3 == 1) || (FXAA_360 == 1) || (FXAA_PS3 == 1) + #define FxaaInt2 float2 + #define FxaaTex sampler2D + #define FxaaTexTop(t, p) tex2Dlod(t, float4(p, 0.0, 0.0)) + #define FxaaTexOff(t, p, o, r) tex2Dlod(t, float4(p + (o * r), 0, 0)) +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_HLSL_4 == 1) + #define FxaaInt2 int2 + struct FxaaTex { SamplerState smpl; Texture2D tex; }; + #define FxaaTexTop(t, p) t.tex.SampleLevel(t.smpl, p, 0.0) + #define FxaaTexOff(t, p, o, r) t.tex.SampleLevel(t.smpl, p, 0.0, o) +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_HLSL_5 == 1) + #define FxaaInt2 int2 + struct FxaaTex { SamplerState smpl; Texture2D tex; }; + #define FxaaTexTop(t, p) t.tex.SampleLevel(t.smpl, p, 0.0) + #define FxaaTexOff(t, p, o, r) t.tex.SampleLevel(t.smpl, p, 0.0, o) + #define FxaaTexAlpha4(t, p) t.tex.GatherAlpha(t.smpl, p) + #define FxaaTexOffAlpha4(t, p, o) t.tex.GatherAlpha(t.smpl, p, o) + #define FxaaTexGreen4(t, p) t.tex.GatherGreen(t.smpl, p) + #define FxaaTexOffGreen4(t, p, o) t.tex.GatherGreen(t.smpl, p, o) +#endif + + +/*============================================================================ + GREEN AS LUMA OPTION SUPPORT FUNCTION +============================================================================*/ +#if (FXAA_GREEN_AS_LUMA == 0) + FxaaFloat FxaaLuma(FxaaFloat4 rgba) { return rgba.w; } +#else + FxaaFloat FxaaLuma(FxaaFloat4 rgba) { return rgba.y; } +#endif + + + + +/*============================================================================ + + FXAA3 QUALITY - PC + +============================================================================*/ +#if (FXAA_PC == 1) +/*--------------------------------------------------------------------------*/ +FxaaFloat4 FxaaPixelShader( + // + // Use noperspective interpolation here (turn off perspective interpolation). + // {xy} = center of pixel + FxaaFloat2 pos, + // + // Used only for FXAA Console, and not used on the 360 version. + // Use noperspective interpolation here (turn off perspective interpolation). + // {xy__} = upper left of pixel + // {__zw} = lower right of pixel + FxaaFloat4 fxaaConsolePosPos, + // + // Input color texture. + // {rgb_} = color in linear or perceptual color space + // if (FXAA_GREEN_AS_LUMA == 0) + // {___a} = luma in perceptual color space (not linear) + FxaaTex tex, + // + // Only used on the optimized 360 version of FXAA Console. + // For everything but 360, just use the same input here as for "tex". + // For 360, same texture, just alias with a 2nd sampler. + // This sampler needs to have an exponent bias of -1. + FxaaTex fxaaConsole360TexExpBiasNegOne, + // + // Only used on the optimized 360 version of FXAA Console. + // For everything but 360, just use the same input here as for "tex". + // For 360, same texture, just alias with a 3nd sampler. + // This sampler needs to have an exponent bias of -2. + FxaaTex fxaaConsole360TexExpBiasNegTwo, + // + // Only used on FXAA Quality. + // This must be from a constant/uniform. + // {x_} = 1.0/screenWidthInPixels + // {_y} = 1.0/screenHeightInPixels + FxaaFloat2 fxaaQualityRcpFrame, + // + // Only used on FXAA Console. + // This must be from a constant/uniform. + // This effects sub-pixel AA quality and inversely sharpness. + // Where N ranges between, + // N = 0.50 (default) + // N = 0.33 (sharper) + // {x___} = -N/screenWidthInPixels + // {_y__} = -N/screenHeightInPixels + // {__z_} = N/screenWidthInPixels + // {___w} = N/screenHeightInPixels + FxaaFloat4 fxaaConsoleRcpFrameOpt, + // + // Only used on FXAA Console. + // Not used on 360, but used on PS3 and PC. + // This must be from a constant/uniform. + // {x___} = -2.0/screenWidthInPixels + // {_y__} = -2.0/screenHeightInPixels + // {__z_} = 2.0/screenWidthInPixels + // {___w} = 2.0/screenHeightInPixels + FxaaFloat4 fxaaConsoleRcpFrameOpt2, + // + // Only used on FXAA Console. + // Only used on 360 in place of fxaaConsoleRcpFrameOpt2. + // This must be from a constant/uniform. + // {x___} = 8.0/screenWidthInPixels + // {_y__} = 8.0/screenHeightInPixels + // {__z_} = -4.0/screenWidthInPixels + // {___w} = -4.0/screenHeightInPixels + FxaaFloat4 fxaaConsole360RcpFrameOpt2, + // + // Only used on FXAA Quality. + // This used to be the FXAA_QUALITY__SUBPIX define. + // It is here now to allow easier tuning. + // Choose the amount of sub-pixel aliasing removal. + // This can effect sharpness. + // 1.00 - upper limit (softer) + // 0.75 - default amount of filtering + // 0.50 - lower limit (sharper, less sub-pixel aliasing removal) + // 0.25 - almost off + // 0.00 - completely off + FxaaFloat fxaaQualitySubpix, + // + // Only used on FXAA Quality. + // This used to be the FXAA_QUALITY__EDGE_THRESHOLD define. + // It is here now to allow easier tuning. + // The minimum amount of local contrast required to apply algorithm. + // 0.333 - too little (faster) + // 0.250 - low quality + // 0.166 - default + // 0.125 - high quality + // 0.063 - overkill (slower) + FxaaFloat fxaaQualityEdgeThreshold, + // + // Only used on FXAA Quality. + // This used to be the FXAA_QUALITY__EDGE_THRESHOLD_MIN define. + // It is here now to allow easier tuning. + // Trims the algorithm from processing darks. + // 0.0833 - upper limit (default, the start of visible unfiltered edges) + // 0.0625 - high quality (faster) + // 0.0312 - visible limit (slower) + // Special notes when using FXAA_GREEN_AS_LUMA, + // Likely want to set this to zero. + // As colors that are mostly not-green + // will appear very dark in the green channel! + // Tune by looking at mostly non-green content, + // then start at zero and increase until aliasing is a problem. + FxaaFloat fxaaQualityEdgeThresholdMin, + // + // Only used on FXAA Console. + // This used to be the FXAA_CONSOLE__EDGE_SHARPNESS define. + // It is here now to allow easier tuning. + // This does not effect PS3, as this needs to be compiled in. + // Use FXAA_CONSOLE__PS3_EDGE_SHARPNESS for PS3. + // Due to the PS3 being ALU bound, + // there are only three safe values here: 2 and 4 and 8. + // These options use the shaders ability to a free *|/ by 2|4|8. + // For all other platforms can be a non-power of two. + // 8.0 is sharper (default!!!) + // 4.0 is softer + // 2.0 is really soft (good only for vector graphics inputs) + FxaaFloat fxaaConsoleEdgeSharpness, + // + // Only used on FXAA Console. + // This used to be the FXAA_CONSOLE__EDGE_THRESHOLD define. + // It is here now to allow easier tuning. + // This does not effect PS3, as this needs to be compiled in. + // Use FXAA_CONSOLE__PS3_EDGE_THRESHOLD for PS3. + // Due to the PS3 being ALU bound, + // there are only two safe values here: 1/4 and 1/8. + // These options use the shaders ability to a free *|/ by 2|4|8. + // The console setting has a different mapping than the quality setting. + // Other platforms can use other values. + // 0.125 leaves less aliasing, but is softer (default!!!) + // 0.25 leaves more aliasing, and is sharper + FxaaFloat fxaaConsoleEdgeThreshold, + // + // Only used on FXAA Console. + // This used to be the FXAA_CONSOLE__EDGE_THRESHOLD_MIN define. + // It is here now to allow easier tuning. + // Trims the algorithm from processing darks. + // The console setting has a different mapping than the quality setting. + // This only applies when FXAA_EARLY_EXIT is 1. + // This does not apply to PS3, + // PS3 was simplified to avoid more shader instructions. + // 0.06 - faster but more aliasing in darks + // 0.05 - default + // 0.04 - slower and less aliasing in darks + // Special notes when using FXAA_GREEN_AS_LUMA, + // Likely want to set this to zero. + // As colors that are mostly not-green + // will appear very dark in the green channel! + // Tune by looking at mostly non-green content, + // then start at zero and increase until aliasing is a problem. + FxaaFloat fxaaConsoleEdgeThresholdMin, + // + // Extra constants for 360 FXAA Console only. + // Use zeros or anything else for other platforms. + // These must be in physical constant registers and NOT immedates. + // Immedates will result in compiler un-optimizing. + // {xyzw} = float4(1.0, -1.0, 0.25, -0.25) + FxaaFloat4 fxaaConsole360ConstDir +) { +/*--------------------------------------------------------------------------*/ + FxaaFloat2 posM; + posM.x = pos.x; + posM.y = pos.y; + #if (FXAA_GATHER4_ALPHA == 1) + #if (FXAA_DISCARD == 0) + FxaaFloat4 rgbyM = FxaaTexTop(tex, posM); + #if (FXAA_GREEN_AS_LUMA == 0) + #define lumaM rgbyM.w + #else + #define lumaM rgbyM.y + #endif + #endif + #if (FXAA_GREEN_AS_LUMA == 0) + FxaaFloat4 luma4A = FxaaTexAlpha4(tex, posM); + FxaaFloat4 luma4B = FxaaTexOffAlpha4(tex, posM, FxaaInt2(-1, -1)); + #else + FxaaFloat4 luma4A = FxaaTexGreen4(tex, posM); + FxaaFloat4 luma4B = FxaaTexOffGreen4(tex, posM, FxaaInt2(-1, -1)); + #endif + #if (FXAA_DISCARD == 1) + #define lumaM luma4A.w + #endif + #define lumaE luma4A.z + #define lumaS luma4A.x + #define lumaSE luma4A.y + #define lumaNW luma4B.w + #define lumaN luma4B.z + #define lumaW luma4B.x + #else + FxaaFloat4 rgbyM = FxaaTexTop(tex, posM); + #if (FXAA_GREEN_AS_LUMA == 0) + #define lumaM rgbyM.w + #else + #define lumaM rgbyM.y + #endif + FxaaFloat lumaS = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 0, 1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1, 0), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaN = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 0,-1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 0), fxaaQualityRcpFrame.xy)); + #endif +/*--------------------------------------------------------------------------*/ + FxaaFloat maxSM = max(lumaS, lumaM); + FxaaFloat minSM = min(lumaS, lumaM); + FxaaFloat maxESM = max(lumaE, maxSM); + FxaaFloat minESM = min(lumaE, minSM); + FxaaFloat maxWN = max(lumaN, lumaW); + FxaaFloat minWN = min(lumaN, lumaW); + FxaaFloat rangeMax = max(maxWN, maxESM); + FxaaFloat rangeMin = min(minWN, minESM); + FxaaFloat rangeMaxScaled = rangeMax * fxaaQualityEdgeThreshold; + FxaaFloat range = rangeMax - rangeMin; + FxaaFloat rangeMaxClamped = max(fxaaQualityEdgeThresholdMin, rangeMaxScaled); + FxaaBool earlyExit = range < rangeMaxClamped; +/*--------------------------------------------------------------------------*/ + if(earlyExit) + #if (FXAA_DISCARD == 1) + FxaaDiscard; + #else + return rgbyM; + #endif +/*--------------------------------------------------------------------------*/ + #if (FXAA_GATHER4_ALPHA == 0) + FxaaFloat lumaNW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1,-1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaSE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1, 1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaNE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1,-1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaSW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 1), fxaaQualityRcpFrame.xy)); + #else + FxaaFloat lumaNE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(1, -1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaSW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 1), fxaaQualityRcpFrame.xy)); + #endif +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaNS = lumaN + lumaS; + FxaaFloat lumaWE = lumaW + lumaE; + FxaaFloat subpixRcpRange = 1.0/range; + FxaaFloat subpixNSWE = lumaNS + lumaWE; + FxaaFloat edgeHorz1 = (-2.0 * lumaM) + lumaNS; + FxaaFloat edgeVert1 = (-2.0 * lumaM) + lumaWE; +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaNESE = lumaNE + lumaSE; + FxaaFloat lumaNWNE = lumaNW + lumaNE; + FxaaFloat edgeHorz2 = (-2.0 * lumaE) + lumaNESE; + FxaaFloat edgeVert2 = (-2.0 * lumaN) + lumaNWNE; +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaNWSW = lumaNW + lumaSW; + FxaaFloat lumaSWSE = lumaSW + lumaSE; + FxaaFloat edgeHorz4 = (abs(edgeHorz1) * 2.0) + abs(edgeHorz2); + FxaaFloat edgeVert4 = (abs(edgeVert1) * 2.0) + abs(edgeVert2); + FxaaFloat edgeHorz3 = (-2.0 * lumaW) + lumaNWSW; + FxaaFloat edgeVert3 = (-2.0 * lumaS) + lumaSWSE; + FxaaFloat edgeHorz = abs(edgeHorz3) + edgeHorz4; + FxaaFloat edgeVert = abs(edgeVert3) + edgeVert4; +/*--------------------------------------------------------------------------*/ + FxaaFloat subpixNWSWNESE = lumaNWSW + lumaNESE; + FxaaFloat lengthSign = fxaaQualityRcpFrame.x; + FxaaBool horzSpan = edgeHorz >= edgeVert; + FxaaFloat subpixA = subpixNSWE * 2.0 + subpixNWSWNESE; +/*--------------------------------------------------------------------------*/ + if(!horzSpan) lumaN = lumaW; + if(!horzSpan) lumaS = lumaE; + if(horzSpan) lengthSign = fxaaQualityRcpFrame.y; + FxaaFloat subpixB = (subpixA * (1.0/12.0)) - lumaM; +/*--------------------------------------------------------------------------*/ + FxaaFloat gradientN = lumaN - lumaM; + FxaaFloat gradientS = lumaS - lumaM; + FxaaFloat lumaNN = lumaN + lumaM; + FxaaFloat lumaSS = lumaS + lumaM; + FxaaBool pairN = abs(gradientN) >= abs(gradientS); + FxaaFloat gradient = max(abs(gradientN), abs(gradientS)); + if(pairN) lengthSign = -lengthSign; + FxaaFloat subpixC = FxaaSat(abs(subpixB) * subpixRcpRange); +/*--------------------------------------------------------------------------*/ + FxaaFloat2 posB; + posB.x = posM.x; + posB.y = posM.y; + FxaaFloat2 offNP; + offNP.x = (!horzSpan) ? 0.0 : fxaaQualityRcpFrame.x; + offNP.y = ( horzSpan) ? 0.0 : fxaaQualityRcpFrame.y; + if(!horzSpan) posB.x += lengthSign * 0.5; + if( horzSpan) posB.y += lengthSign * 0.5; +/*--------------------------------------------------------------------------*/ + FxaaFloat2 posN; + posN.x = posB.x - offNP.x * FXAA_QUALITY__P0; + posN.y = posB.y - offNP.y * FXAA_QUALITY__P0; + FxaaFloat2 posP; + posP.x = posB.x + offNP.x * FXAA_QUALITY__P0; + posP.y = posB.y + offNP.y * FXAA_QUALITY__P0; + FxaaFloat subpixD = ((-2.0)*subpixC) + 3.0; + FxaaFloat lumaEndN = FxaaLuma(FxaaTexTop(tex, posN)); + FxaaFloat subpixE = subpixC * subpixC; + FxaaFloat lumaEndP = FxaaLuma(FxaaTexTop(tex, posP)); +/*--------------------------------------------------------------------------*/ + if(!pairN) lumaNN = lumaSS; + FxaaFloat gradientScaled = gradient * 1.0/4.0; + FxaaFloat lumaMM = lumaM - lumaNN * 0.5; + FxaaFloat subpixF = subpixD * subpixE; + FxaaBool lumaMLTZero = lumaMM < 0.0; +/*--------------------------------------------------------------------------*/ + lumaEndN -= lumaNN * 0.5; + lumaEndP -= lumaNN * 0.5; + FxaaBool doneN = abs(lumaEndN) >= gradientScaled; + FxaaBool doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P1; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P1; + FxaaBool doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P1; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P1; +/*--------------------------------------------------------------------------*/ + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P2; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P2; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P2; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P2; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 3) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P3; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P3; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P3; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P3; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 4) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P4; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P4; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P4; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P4; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 5) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P5; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P5; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P5; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P5; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 6) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P6; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P6; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P6; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P6; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 7) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P7; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P7; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P7; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P7; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 8) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P8; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P8; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P8; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P8; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 9) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P9; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P9; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P9; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P9; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 10) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P10; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P10; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P10; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P10; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 11) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P11; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P11; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P11; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P11; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 12) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P12; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P12; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P12; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P12; +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } +/*--------------------------------------------------------------------------*/ + FxaaFloat dstN = posM.x - posN.x; + FxaaFloat dstP = posP.x - posM.x; + if(!horzSpan) dstN = posM.y - posN.y; + if(!horzSpan) dstP = posP.y - posM.y; +/*--------------------------------------------------------------------------*/ + FxaaBool goodSpanN = (lumaEndN < 0.0) != lumaMLTZero; + FxaaFloat spanLength = (dstP + dstN); + FxaaBool goodSpanP = (lumaEndP < 0.0) != lumaMLTZero; + FxaaFloat spanLengthRcp = 1.0/spanLength; +/*--------------------------------------------------------------------------*/ + FxaaBool directionN = dstN < dstP; + FxaaFloat dst = min(dstN, dstP); + FxaaBool goodSpan = directionN ? goodSpanN : goodSpanP; + FxaaFloat subpixG = subpixF * subpixF; + FxaaFloat pixelOffset = (dst * (-spanLengthRcp)) + 0.5; + FxaaFloat subpixH = subpixG * fxaaQualitySubpix; +/*--------------------------------------------------------------------------*/ + FxaaFloat pixelOffsetGood = goodSpan ? pixelOffset : 0.0; + FxaaFloat pixelOffsetSubpix = max(pixelOffsetGood, subpixH); + if(!horzSpan) posM.x += pixelOffsetSubpix * lengthSign; + if( horzSpan) posM.y += pixelOffsetSubpix * lengthSign; + #if (FXAA_DISCARD == 1) + return FxaaTexTop(tex, posM); + #else + return FxaaFloat4(FxaaTexTop(tex, posM).xyz, lumaM); + #endif +} +/*==========================================================================*/ +#endif + + + + +/*============================================================================ + + FXAA3 CONSOLE - PC VERSION + +------------------------------------------------------------------------------ +Instead of using this on PC, I'd suggest just using FXAA Quality with + #define FXAA_QUALITY__PRESET 10 +Or + #define FXAA_QUALITY__PRESET 20 +Either are higher qualilty and almost as fast as this on modern PC GPUs. +============================================================================*/ +#if (FXAA_PC_CONSOLE == 1) +/*--------------------------------------------------------------------------*/ +FxaaFloat4 FxaaPixelShader( + // See FXAA Quality FxaaPixelShader() source for docs on Inputs! + FxaaFloat2 pos, + FxaaFloat4 fxaaConsolePosPos, + FxaaTex tex, + FxaaTex fxaaConsole360TexExpBiasNegOne, + FxaaTex fxaaConsole360TexExpBiasNegTwo, + FxaaFloat2 fxaaQualityRcpFrame, + FxaaFloat4 fxaaConsoleRcpFrameOpt, + FxaaFloat4 fxaaConsoleRcpFrameOpt2, + FxaaFloat4 fxaaConsole360RcpFrameOpt2, + FxaaFloat fxaaQualitySubpix, + FxaaFloat fxaaQualityEdgeThreshold, + FxaaFloat fxaaQualityEdgeThresholdMin, + FxaaFloat fxaaConsoleEdgeSharpness, + FxaaFloat fxaaConsoleEdgeThreshold, + FxaaFloat fxaaConsoleEdgeThresholdMin, + FxaaFloat4 fxaaConsole360ConstDir +) { +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaNw = FxaaLuma(FxaaTexTop(tex, fxaaConsolePosPos.xy)); + FxaaFloat lumaSw = FxaaLuma(FxaaTexTop(tex, fxaaConsolePosPos.xw)); + FxaaFloat lumaNe = FxaaLuma(FxaaTexTop(tex, fxaaConsolePosPos.zy)); + FxaaFloat lumaSe = FxaaLuma(FxaaTexTop(tex, fxaaConsolePosPos.zw)); +/*--------------------------------------------------------------------------*/ + FxaaFloat4 rgbyM = FxaaTexTop(tex, pos.xy); + #if (FXAA_GREEN_AS_LUMA == 0) + FxaaFloat lumaM = rgbyM.w; + #else + FxaaFloat lumaM = rgbyM.y; + #endif +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaMaxNwSw = max(lumaNw, lumaSw); + lumaNe += 1.0/384.0; + FxaaFloat lumaMinNwSw = min(lumaNw, lumaSw); +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaMaxNeSe = max(lumaNe, lumaSe); + FxaaFloat lumaMinNeSe = min(lumaNe, lumaSe); +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaMax = max(lumaMaxNeSe, lumaMaxNwSw); + FxaaFloat lumaMin = min(lumaMinNeSe, lumaMinNwSw); +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaMaxScaled = lumaMax * fxaaConsoleEdgeThreshold; +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaMinM = min(lumaMin, lumaM); + FxaaFloat lumaMaxScaledClamped = max(fxaaConsoleEdgeThresholdMin, lumaMaxScaled); + FxaaFloat lumaMaxM = max(lumaMax, lumaM); + FxaaFloat dirSwMinusNe = lumaSw - lumaNe; + FxaaFloat lumaMaxSubMinM = lumaMaxM - lumaMinM; + FxaaFloat dirSeMinusNw = lumaSe - lumaNw; + if(lumaMaxSubMinM < lumaMaxScaledClamped) return rgbyM; +/*--------------------------------------------------------------------------*/ + FxaaFloat2 dir; + dir.x = dirSwMinusNe + dirSeMinusNw; + dir.y = dirSwMinusNe - dirSeMinusNw; +/*--------------------------------------------------------------------------*/ + FxaaFloat2 dir1 = normalize(dir.xy); + FxaaFloat4 rgbyN1 = FxaaTexTop(tex, pos.xy - dir1 * fxaaConsoleRcpFrameOpt.zw); + FxaaFloat4 rgbyP1 = FxaaTexTop(tex, pos.xy + dir1 * fxaaConsoleRcpFrameOpt.zw); +/*--------------------------------------------------------------------------*/ + FxaaFloat dirAbsMinTimesC = min(abs(dir1.x), abs(dir1.y)) * fxaaConsoleEdgeSharpness; + FxaaFloat2 dir2 = clamp(dir1.xy / dirAbsMinTimesC, -2.0, 2.0); +/*--------------------------------------------------------------------------*/ + FxaaFloat4 rgbyN2 = FxaaTexTop(tex, pos.xy - dir2 * fxaaConsoleRcpFrameOpt2.zw); + FxaaFloat4 rgbyP2 = FxaaTexTop(tex, pos.xy + dir2 * fxaaConsoleRcpFrameOpt2.zw); +/*--------------------------------------------------------------------------*/ + FxaaFloat4 rgbyA = rgbyN1 + rgbyP1; + FxaaFloat4 rgbyB = ((rgbyN2 + rgbyP2) * 0.25) + (rgbyA * 0.25); +/*--------------------------------------------------------------------------*/ + #if (FXAA_GREEN_AS_LUMA == 0) + FxaaBool twoTap = (rgbyB.w < lumaMin) || (rgbyB.w > lumaMax); + #else + FxaaBool twoTap = (rgbyB.y < lumaMin) || (rgbyB.y > lumaMax); + #endif + if(twoTap) rgbyB.xyz = rgbyA.xyz * 0.5; + return rgbyB; } +/*==========================================================================*/ +#endif + + + +/*============================================================================ + + FXAA3 CONSOLE - 360 PIXEL SHADER + +------------------------------------------------------------------------------ +This optimized version thanks to suggestions from Andy Luedke. +Should be fully tex bound in all cases. +As of the FXAA 3.11 release, I have still not tested this code, +however I fixed a bug which was in both FXAA 3.9 and FXAA 3.10. +And note this is replacing the old unoptimized version. +If it does not work, please let me know so I can fix it. +============================================================================*/ +#if (FXAA_360 == 1) +/*--------------------------------------------------------------------------*/ +[reduceTempRegUsage(4)] +float4 FxaaPixelShader( + // See FXAA Quality FxaaPixelShader() source for docs on Inputs! + FxaaFloat2 pos, + FxaaFloat4 fxaaConsolePosPos, + FxaaTex tex, + FxaaTex fxaaConsole360TexExpBiasNegOne, + FxaaTex fxaaConsole360TexExpBiasNegTwo, + FxaaFloat2 fxaaQualityRcpFrame, + FxaaFloat4 fxaaConsoleRcpFrameOpt, + FxaaFloat4 fxaaConsoleRcpFrameOpt2, + FxaaFloat4 fxaaConsole360RcpFrameOpt2, + FxaaFloat fxaaQualitySubpix, + FxaaFloat fxaaQualityEdgeThreshold, + FxaaFloat fxaaQualityEdgeThresholdMin, + FxaaFloat fxaaConsoleEdgeSharpness, + FxaaFloat fxaaConsoleEdgeThreshold, + FxaaFloat fxaaConsoleEdgeThresholdMin, + FxaaFloat4 fxaaConsole360ConstDir +) { +/*--------------------------------------------------------------------------*/ + float4 lumaNwNeSwSe; + #if (FXAA_GREEN_AS_LUMA == 0) + asm { + tfetch2D lumaNwNeSwSe.w___, tex, pos.xy, OffsetX = -0.5, OffsetY = -0.5, UseComputedLOD=false + tfetch2D lumaNwNeSwSe._w__, tex, pos.xy, OffsetX = 0.5, OffsetY = -0.5, UseComputedLOD=false + tfetch2D lumaNwNeSwSe.__w_, tex, pos.xy, OffsetX = -0.5, OffsetY = 0.5, UseComputedLOD=false + tfetch2D lumaNwNeSwSe.___w, tex, pos.xy, OffsetX = 0.5, OffsetY = 0.5, UseComputedLOD=false + }; + #else + asm { + tfetch2D lumaNwNeSwSe.y___, tex, pos.xy, OffsetX = -0.5, OffsetY = -0.5, UseComputedLOD=false + tfetch2D lumaNwNeSwSe._y__, tex, pos.xy, OffsetX = 0.5, OffsetY = -0.5, UseComputedLOD=false + tfetch2D lumaNwNeSwSe.__y_, tex, pos.xy, OffsetX = -0.5, OffsetY = 0.5, UseComputedLOD=false + tfetch2D lumaNwNeSwSe.___y, tex, pos.xy, OffsetX = 0.5, OffsetY = 0.5, UseComputedLOD=false + }; + #endif +/*--------------------------------------------------------------------------*/ + lumaNwNeSwSe.y += 1.0/384.0; + float2 lumaMinTemp = min(lumaNwNeSwSe.xy, lumaNwNeSwSe.zw); + float2 lumaMaxTemp = max(lumaNwNeSwSe.xy, lumaNwNeSwSe.zw); + float lumaMin = min(lumaMinTemp.x, lumaMinTemp.y); + float lumaMax = max(lumaMaxTemp.x, lumaMaxTemp.y); +/*--------------------------------------------------------------------------*/ + float4 rgbyM = tex2Dlod(tex, float4(pos.xy, 0.0, 0.0)); + #if (FXAA_GREEN_AS_LUMA == 0) + float lumaMinM = min(lumaMin, rgbyM.w); + float lumaMaxM = max(lumaMax, rgbyM.w); + #else + float lumaMinM = min(lumaMin, rgbyM.y); + float lumaMaxM = max(lumaMax, rgbyM.y); + #endif + if((lumaMaxM - lumaMinM) < max(fxaaConsoleEdgeThresholdMin, lumaMax * fxaaConsoleEdgeThreshold)) return rgbyM; +/*--------------------------------------------------------------------------*/ + float2 dir; + dir.x = dot(lumaNwNeSwSe, fxaaConsole360ConstDir.yyxx); + dir.y = dot(lumaNwNeSwSe, fxaaConsole360ConstDir.xyxy); + dir = normalize(dir); +/*--------------------------------------------------------------------------*/ + float4 dir1 = dir.xyxy * fxaaConsoleRcpFrameOpt.xyzw; +/*--------------------------------------------------------------------------*/ + float4 dir2; + float dirAbsMinTimesC = min(abs(dir.x), abs(dir.y)) * fxaaConsoleEdgeSharpness; + dir2 = saturate(fxaaConsole360ConstDir.zzww * dir.xyxy / dirAbsMinTimesC + 0.5); + dir2 = dir2 * fxaaConsole360RcpFrameOpt2.xyxy + fxaaConsole360RcpFrameOpt2.zwzw; +/*--------------------------------------------------------------------------*/ + float4 rgbyN1 = tex2Dlod(fxaaConsole360TexExpBiasNegOne, float4(pos.xy + dir1.xy, 0.0, 0.0)); + float4 rgbyP1 = tex2Dlod(fxaaConsole360TexExpBiasNegOne, float4(pos.xy + dir1.zw, 0.0, 0.0)); + float4 rgbyN2 = tex2Dlod(fxaaConsole360TexExpBiasNegTwo, float4(pos.xy + dir2.xy, 0.0, 0.0)); + float4 rgbyP2 = tex2Dlod(fxaaConsole360TexExpBiasNegTwo, float4(pos.xy + dir2.zw, 0.0, 0.0)); +/*--------------------------------------------------------------------------*/ + float4 rgbyA = rgbyN1 + rgbyP1; + float4 rgbyB = rgbyN2 + rgbyP2 + rgbyA * 0.5; +/*--------------------------------------------------------------------------*/ + float4 rgbyR = ((FxaaLuma(rgbyB) - lumaMax) > 0.0) ? rgbyA : rgbyB; + rgbyR = ((FxaaLuma(rgbyB) - lumaMin) > 0.0) ? rgbyR : rgbyA; + return rgbyR; } +/*==========================================================================*/ +#endif + + + +/*============================================================================ + + FXAA3 CONSOLE - OPTIMIZED PS3 PIXEL SHADER (NO EARLY EXIT) + +============================================================================== +The code below does not exactly match the assembly. +I have a feeling that 12 cycles is possible, but was not able to get there. +Might have to increase register count to get full performance. +Note this shader does not use perspective interpolation. + +Use the following cgc options, + + --fenable-bx2 --fastmath --fastprecision --nofloatbindings + +------------------------------------------------------------------------------ + NVSHADERPERF OUTPUT +------------------------------------------------------------------------------ +For reference and to aid in debug, output of NVShaderPerf should match this, + +Shader to schedule: + 0: texpkb h0.w(TRUE), v5.zyxx, #0 + 2: addh h2.z(TRUE), h0.w, constant(0.001953, 0.000000, 0.000000, 0.000000).x + 4: texpkb h0.w(TRUE), v5.xwxx, #0 + 6: addh h0.z(TRUE), -h2, h0.w + 7: texpkb h1.w(TRUE), v5, #0 + 9: addh h0.x(TRUE), h0.z, -h1.w + 10: addh h3.w(TRUE), h0.z, h1 + 11: texpkb h2.w(TRUE), v5.zwzz, #0 + 13: addh h0.z(TRUE), h3.w, -h2.w + 14: addh h0.x(TRUE), h2.w, h0 + 15: nrmh h1.xz(TRUE), h0_n + 16: minh_m8 h0.x(TRUE), |h1|, |h1.z| + 17: maxh h4.w(TRUE), h0, h1 + 18: divx h2.xy(TRUE), h1_n.xzzw, h0_n + 19: movr r1.zw(TRUE), v4.xxxy + 20: madr r2.xz(TRUE), -h1, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w).zzww, r1.zzww + 22: minh h5.w(TRUE), h0, h1 + 23: texpkb h0(TRUE), r2.xzxx, #0 + 25: madr r0.zw(TRUE), h1.xzxz, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w), r1 + 27: maxh h4.x(TRUE), h2.z, h2.w + 28: texpkb h1(TRUE), r0.zwzz, #0 + 30: addh_d2 h1(TRUE), h0, h1 + 31: madr r0.xy(TRUE), -h2, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w).xyxx, r1.zwzz + 33: texpkb h0(TRUE), r0, #0 + 35: minh h4.z(TRUE), h2, h2.w + 36: fenct TRUE + 37: madr r1.xy(TRUE), h2, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w).xyxx, r1.zwzz + 39: texpkb h2(TRUE), r1, #0 + 41: addh_d2 h0(TRUE), h0, h2 + 42: maxh h2.w(TRUE), h4, h4.x + 43: minh h2.x(TRUE), h5.w, h4.z + 44: addh_d2 h0(TRUE), h0, h1 + 45: slth h2.x(TRUE), h0.w, h2 + 46: sgth h2.w(TRUE), h0, h2 + 47: movh h0(TRUE), h0 + 48: addx.c0 rc(TRUE), h2, h2.w + 49: movh h0(c0.NE.x), h1 + +IPU0 ------ Simplified schedule: -------- +Pass | Unit | uOp | PC: Op +-----+--------+------+------------------------- + 1 | SCT0/1 | mov | 0: TXLr h0.w, g[TEX1].zyxx, const.xxxx, TEX0; + | TEX | txl | 0: TXLr h0.w, g[TEX1].zyxx, const.xxxx, TEX0; + | SCB1 | add | 2: ADDh h2.z, h0.--w-, const.--x-; + | | | + 2 | SCT0/1 | mov | 4: TXLr h0.w, g[TEX1].xwxx, const.xxxx, TEX0; + | TEX | txl | 4: TXLr h0.w, g[TEX1].xwxx, const.xxxx, TEX0; + | SCB1 | add | 6: ADDh h0.z,-h2, h0.--w-; + | | | + 3 | SCT0/1 | mov | 7: TXLr h1.w, g[TEX1], const.xxxx, TEX0; + | TEX | txl | 7: TXLr h1.w, g[TEX1], const.xxxx, TEX0; + | SCB0 | add | 9: ADDh h0.x, h0.z---,-h1.w---; + | SCB1 | add | 10: ADDh h3.w, h0.---z, h1; + | | | + 4 | SCT0/1 | mov | 11: TXLr h2.w, g[TEX1].zwzz, const.xxxx, TEX0; + | TEX | txl | 11: TXLr h2.w, g[TEX1].zwzz, const.xxxx, TEX0; + | SCB0 | add | 14: ADDh h0.x, h2.w---, h0; + | SCB1 | add | 13: ADDh h0.z, h3.--w-,-h2.--w-; + | | | + 5 | SCT1 | mov | 15: NRMh h1.xz, h0; + | SRB | nrm | 15: NRMh h1.xz, h0; + | SCB0 | min | 16: MINh*8 h0.x, |h1|, |h1.z---|; + | SCB1 | max | 17: MAXh h4.w, h0, h1; + | | | + 6 | SCT0 | div | 18: DIVx h2.xy, h1.xz--, h0; + | SCT1 | mov | 19: MOVr r1.zw, g[TEX0].--xy; + | SCB0 | mad | 20: MADr r2.xz,-h1, const.z-w-, r1.z-w-; + | SCB1 | min | 22: MINh h5.w, h0, h1; + | | | + 7 | SCT0/1 | mov | 23: TXLr h0, r2.xzxx, const.xxxx, TEX0; + | TEX | txl | 23: TXLr h0, r2.xzxx, const.xxxx, TEX0; + | SCB0 | max | 27: MAXh h4.x, h2.z---, h2.w---; + | SCB1 | mad | 25: MADr r0.zw, h1.--xz, const, r1; + | | | + 8 | SCT0/1 | mov | 28: TXLr h1, r0.zwzz, const.xxxx, TEX0; + | TEX | txl | 28: TXLr h1, r0.zwzz, const.xxxx, TEX0; + | SCB0/1 | add | 30: ADDh/2 h1, h0, h1; + | | | + 9 | SCT0 | mad | 31: MADr r0.xy,-h2, const.xy--, r1.zw--; + | SCT1 | mov | 33: TXLr h0, r0, const.zzzz, TEX0; + | TEX | txl | 33: TXLr h0, r0, const.zzzz, TEX0; + | SCB1 | min | 35: MINh h4.z, h2, h2.--w-; + | | | + 10 | SCT0 | mad | 37: MADr r1.xy, h2, const.xy--, r1.zw--; + | SCT1 | mov | 39: TXLr h2, r1, const.zzzz, TEX0; + | TEX | txl | 39: TXLr h2, r1, const.zzzz, TEX0; + | SCB0/1 | add | 41: ADDh/2 h0, h0, h2; + | | | + 11 | SCT0 | min | 43: MINh h2.x, h5.w---, h4.z---; + | SCT1 | max | 42: MAXh h2.w, h4, h4.---x; + | SCB0/1 | add | 44: ADDh/2 h0, h0, h1; + | | | + 12 | SCT0 | set | 45: SLTh h2.x, h0.w---, h2; + | SCT1 | set | 46: SGTh h2.w, h0, h2; + | SCB0/1 | mul | 47: MOVh h0, h0; + | | | + 13 | SCT0 | mad | 48: ADDxc0_s rc, h2, h2.w---; + | SCB0/1 | mul | 49: MOVh h0(NE0.xxxx), h1; + +Pass SCT TEX SCB + 1: 0% 100% 25% + 2: 0% 100% 25% + 3: 0% 100% 50% + 4: 0% 100% 50% + 5: 0% 0% 50% + 6: 100% 0% 75% + 7: 0% 100% 75% + 8: 0% 100% 100% + 9: 0% 100% 25% + 10: 0% 100% 100% + 11: 50% 0% 100% + 12: 50% 0% 100% + 13: 25% 0% 100% + +MEAN: 17% 61% 67% + +Pass SCT0 SCT1 TEX SCB0 SCB1 + 1: 0% 0% 100% 0% 100% + 2: 0% 0% 100% 0% 100% + 3: 0% 0% 100% 100% 100% + 4: 0% 0% 100% 100% 100% + 5: 0% 0% 0% 100% 100% + 6: 100% 100% 0% 100% 100% + 7: 0% 0% 100% 100% 100% + 8: 0% 0% 100% 100% 100% + 9: 0% 0% 100% 0% 100% + 10: 0% 0% 100% 100% 100% + 11: 100% 100% 0% 100% 100% + 12: 100% 100% 0% 100% 100% + 13: 100% 0% 0% 100% 100% + +MEAN: 30% 23% 61% 76% 100% +Fragment Performance Setup: Driver RSX Compiler, GPU RSX, Flags 0x5 +Results 13 cycles, 3 r regs, 923,076,923 pixels/s +============================================================================*/ +#if (FXAA_PS3 == 1) && (FXAA_EARLY_EXIT == 0) +/*--------------------------------------------------------------------------*/ +#pragma regcount 7 +#pragma disablepc all +#pragma option O3 +#pragma option OutColorPrec=fp16 +#pragma texformat default RGBA8 +/*==========================================================================*/ +half4 FxaaPixelShader( + // See FXAA Quality FxaaPixelShader() source for docs on Inputs! + FxaaFloat2 pos, + FxaaFloat4 fxaaConsolePosPos, + FxaaTex tex, + FxaaTex fxaaConsole360TexExpBiasNegOne, + FxaaTex fxaaConsole360TexExpBiasNegTwo, + FxaaFloat2 fxaaQualityRcpFrame, + FxaaFloat4 fxaaConsoleRcpFrameOpt, + FxaaFloat4 fxaaConsoleRcpFrameOpt2, + FxaaFloat4 fxaaConsole360RcpFrameOpt2, + FxaaFloat fxaaQualitySubpix, + FxaaFloat fxaaQualityEdgeThreshold, + FxaaFloat fxaaQualityEdgeThresholdMin, + FxaaFloat fxaaConsoleEdgeSharpness, + FxaaFloat fxaaConsoleEdgeThreshold, + FxaaFloat fxaaConsoleEdgeThresholdMin, + FxaaFloat4 fxaaConsole360ConstDir +) { +/*--------------------------------------------------------------------------*/ +// (1) + half4 dir; + half4 lumaNe = h4tex2Dlod(tex, half4(fxaaConsolePosPos.zy, 0, 0)); + #if (FXAA_GREEN_AS_LUMA == 0) + lumaNe.w += half(1.0/512.0); + dir.x = -lumaNe.w; + dir.z = -lumaNe.w; + #else + lumaNe.y += half(1.0/512.0); + dir.x = -lumaNe.y; + dir.z = -lumaNe.y; + #endif +/*--------------------------------------------------------------------------*/ +// (2) + half4 lumaSw = h4tex2Dlod(tex, half4(fxaaConsolePosPos.xw, 0, 0)); + #if (FXAA_GREEN_AS_LUMA == 0) + dir.x += lumaSw.w; + dir.z += lumaSw.w; + #else + dir.x += lumaSw.y; + dir.z += lumaSw.y; + #endif +/*--------------------------------------------------------------------------*/ +// (3) + half4 lumaNw = h4tex2Dlod(tex, half4(fxaaConsolePosPos.xy, 0, 0)); + #if (FXAA_GREEN_AS_LUMA == 0) + dir.x -= lumaNw.w; + dir.z += lumaNw.w; + #else + dir.x -= lumaNw.y; + dir.z += lumaNw.y; + #endif +/*--------------------------------------------------------------------------*/ +// (4) + half4 lumaSe = h4tex2Dlod(tex, half4(fxaaConsolePosPos.zw, 0, 0)); + #if (FXAA_GREEN_AS_LUMA == 0) + dir.x += lumaSe.w; + dir.z -= lumaSe.w; + #else + dir.x += lumaSe.y; + dir.z -= lumaSe.y; + #endif +/*--------------------------------------------------------------------------*/ +// (5) + half4 dir1_pos; + dir1_pos.xy = normalize(dir.xyz).xz; + half dirAbsMinTimesC = min(abs(dir1_pos.x), abs(dir1_pos.y)) * half(FXAA_CONSOLE__PS3_EDGE_SHARPNESS); +/*--------------------------------------------------------------------------*/ +// (6) + half4 dir2_pos; + dir2_pos.xy = clamp(dir1_pos.xy / dirAbsMinTimesC, half(-2.0), half(2.0)); + dir1_pos.zw = pos.xy; + dir2_pos.zw = pos.xy; + half4 temp1N; + temp1N.xy = dir1_pos.zw - dir1_pos.xy * fxaaConsoleRcpFrameOpt.zw; +/*--------------------------------------------------------------------------*/ +// (7) + temp1N = h4tex2Dlod(tex, half4(temp1N.xy, 0.0, 0.0)); + half4 rgby1; + rgby1.xy = dir1_pos.zw + dir1_pos.xy * fxaaConsoleRcpFrameOpt.zw; +/*--------------------------------------------------------------------------*/ +// (8) + rgby1 = h4tex2Dlod(tex, half4(rgby1.xy, 0.0, 0.0)); + rgby1 = (temp1N + rgby1) * 0.5; +/*--------------------------------------------------------------------------*/ +// (9) + half4 temp2N; + temp2N.xy = dir2_pos.zw - dir2_pos.xy * fxaaConsoleRcpFrameOpt2.zw; + temp2N = h4tex2Dlod(tex, half4(temp2N.xy, 0.0, 0.0)); +/*--------------------------------------------------------------------------*/ +// (10) + half4 rgby2; + rgby2.xy = dir2_pos.zw + dir2_pos.xy * fxaaConsoleRcpFrameOpt2.zw; + rgby2 = h4tex2Dlod(tex, half4(rgby2.xy, 0.0, 0.0)); + rgby2 = (temp2N + rgby2) * 0.5; +/*--------------------------------------------------------------------------*/ +// (11) + // compilier moves these scalar ops up to other cycles + #if (FXAA_GREEN_AS_LUMA == 0) + half lumaMin = min(min(lumaNw.w, lumaSw.w), min(lumaNe.w, lumaSe.w)); + half lumaMax = max(max(lumaNw.w, lumaSw.w), max(lumaNe.w, lumaSe.w)); + #else + half lumaMin = min(min(lumaNw.y, lumaSw.y), min(lumaNe.y, lumaSe.y)); + half lumaMax = max(max(lumaNw.y, lumaSw.y), max(lumaNe.y, lumaSe.y)); + #endif + rgby2 = (rgby2 + rgby1) * 0.5; +/*--------------------------------------------------------------------------*/ +// (12) + #if (FXAA_GREEN_AS_LUMA == 0) + bool twoTapLt = rgby2.w < lumaMin; + bool twoTapGt = rgby2.w > lumaMax; + #else + bool twoTapLt = rgby2.y < lumaMin; + bool twoTapGt = rgby2.y > lumaMax; + #endif +/*--------------------------------------------------------------------------*/ +// (13) + if(twoTapLt || twoTapGt) rgby2 = rgby1; +/*--------------------------------------------------------------------------*/ + return rgby2; } +/*==========================================================================*/ +#endif + + + +/*============================================================================ + + FXAA3 CONSOLE - OPTIMIZED PS3 PIXEL SHADER (WITH EARLY EXIT) + +============================================================================== +The code mostly matches the assembly. +I have a feeling that 14 cycles is possible, but was not able to get there. +Might have to increase register count to get full performance. +Note this shader does not use perspective interpolation. + +Use the following cgc options, + + --fenable-bx2 --fastmath --fastprecision --nofloatbindings + +Use of FXAA_GREEN_AS_LUMA currently adds a cycle (16 clks). +Will look at fixing this for FXAA 3.12. +------------------------------------------------------------------------------ + NVSHADERPERF OUTPUT +------------------------------------------------------------------------------ +For reference and to aid in debug, output of NVShaderPerf should match this, + +Shader to schedule: + 0: texpkb h0.w(TRUE), v5.zyxx, #0 + 2: addh h2.y(TRUE), h0.w, constant(0.001953, 0.000000, 0.000000, 0.000000).x + 4: texpkb h1.w(TRUE), v5.xwxx, #0 + 6: addh h0.x(TRUE), h1.w, -h2.y + 7: texpkb h2.w(TRUE), v5.zwzz, #0 + 9: minh h4.w(TRUE), h2.y, h2 + 10: maxh h5.x(TRUE), h2.y, h2.w + 11: texpkb h0.w(TRUE), v5, #0 + 13: addh h3.w(TRUE), -h0, h0.x + 14: addh h0.x(TRUE), h0.w, h0 + 15: addh h0.z(TRUE), -h2.w, h0.x + 16: addh h0.x(TRUE), h2.w, h3.w + 17: minh h5.y(TRUE), h0.w, h1.w + 18: nrmh h2.xz(TRUE), h0_n + 19: minh_m8 h2.w(TRUE), |h2.x|, |h2.z| + 20: divx h4.xy(TRUE), h2_n.xzzw, h2_n.w + 21: movr r1.zw(TRUE), v4.xxxy + 22: maxh h2.w(TRUE), h0, h1 + 23: fenct TRUE + 24: madr r0.xy(TRUE), -h2.xzzw, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w).zwzz, r1.zwzz + 26: texpkb h0(TRUE), r0, #0 + 28: maxh h5.x(TRUE), h2.w, h5 + 29: minh h5.w(TRUE), h5.y, h4 + 30: madr r1.xy(TRUE), h2.xzzw, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w).zwzz, r1.zwzz + 32: texpkb h2(TRUE), r1, #0 + 34: addh_d2 h2(TRUE), h0, h2 + 35: texpkb h1(TRUE), v4, #0 + 37: maxh h5.y(TRUE), h5.x, h1.w + 38: minh h4.w(TRUE), h1, h5 + 39: madr r0.xy(TRUE), -h4, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w).xyxx, r1.zwzz + 41: texpkb h0(TRUE), r0, #0 + 43: addh_m8 h5.z(TRUE), h5.y, -h4.w + 44: madr r2.xy(TRUE), h4, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w).xyxx, r1.zwzz + 46: texpkb h3(TRUE), r2, #0 + 48: addh_d2 h0(TRUE), h0, h3 + 49: addh_d2 h3(TRUE), h0, h2 + 50: movh h0(TRUE), h3 + 51: slth h3.x(TRUE), h3.w, h5.w + 52: sgth h3.w(TRUE), h3, h5.x + 53: addx.c0 rc(TRUE), h3.x, h3 + 54: slth.c0 rc(TRUE), h5.z, h5 + 55: movh h0(c0.NE.w), h2 + 56: movh h0(c0.NE.x), h1 + +IPU0 ------ Simplified schedule: -------- +Pass | Unit | uOp | PC: Op +-----+--------+------+------------------------- + 1 | SCT0/1 | mov | 0: TXLr h0.w, g[TEX1].zyxx, const.xxxx, TEX0; + | TEX | txl | 0: TXLr h0.w, g[TEX1].zyxx, const.xxxx, TEX0; + | SCB0 | add | 2: ADDh h2.y, h0.-w--, const.-x--; + | | | + 2 | SCT0/1 | mov | 4: TXLr h1.w, g[TEX1].xwxx, const.xxxx, TEX0; + | TEX | txl | 4: TXLr h1.w, g[TEX1].xwxx, const.xxxx, TEX0; + | SCB0 | add | 6: ADDh h0.x, h1.w---,-h2.y---; + | | | + 3 | SCT0/1 | mov | 7: TXLr h2.w, g[TEX1].zwzz, const.xxxx, TEX0; + | TEX | txl | 7: TXLr h2.w, g[TEX1].zwzz, const.xxxx, TEX0; + | SCB0 | max | 10: MAXh h5.x, h2.y---, h2.w---; + | SCB1 | min | 9: MINh h4.w, h2.---y, h2; + | | | + 4 | SCT0/1 | mov | 11: TXLr h0.w, g[TEX1], const.xxxx, TEX0; + | TEX | txl | 11: TXLr h0.w, g[TEX1], const.xxxx, TEX0; + | SCB0 | add | 14: ADDh h0.x, h0.w---, h0; + | SCB1 | add | 13: ADDh h3.w,-h0, h0.---x; + | | | + 5 | SCT0 | mad | 16: ADDh h0.x, h2.w---, h3.w---; + | SCT1 | mad | 15: ADDh h0.z,-h2.--w-, h0.--x-; + | SCB0 | min | 17: MINh h5.y, h0.-w--, h1.-w--; + | | | + 6 | SCT1 | mov | 18: NRMh h2.xz, h0; + | SRB | nrm | 18: NRMh h2.xz, h0; + | SCB1 | min | 19: MINh*8 h2.w, |h2.---x|, |h2.---z|; + | | | + 7 | SCT0 | div | 20: DIVx h4.xy, h2.xz--, h2.ww--; + | SCT1 | mov | 21: MOVr r1.zw, g[TEX0].--xy; + | SCB1 | max | 22: MAXh h2.w, h0, h1; + | | | + 8 | SCT0 | mad | 24: MADr r0.xy,-h2.xz--, const.zw--, r1.zw--; + | SCT1 | mov | 26: TXLr h0, r0, const.xxxx, TEX0; + | TEX | txl | 26: TXLr h0, r0, const.xxxx, TEX0; + | SCB0 | max | 28: MAXh h5.x, h2.w---, h5; + | SCB1 | min | 29: MINh h5.w, h5.---y, h4; + | | | + 9 | SCT0 | mad | 30: MADr r1.xy, h2.xz--, const.zw--, r1.zw--; + | SCT1 | mov | 32: TXLr h2, r1, const.xxxx, TEX0; + | TEX | txl | 32: TXLr h2, r1, const.xxxx, TEX0; + | SCB0/1 | add | 34: ADDh/2 h2, h0, h2; + | | | + 10 | SCT0/1 | mov | 35: TXLr h1, g[TEX0], const.xxxx, TEX0; + | TEX | txl | 35: TXLr h1, g[TEX0], const.xxxx, TEX0; + | SCB0 | max | 37: MAXh h5.y, h5.-x--, h1.-w--; + | SCB1 | min | 38: MINh h4.w, h1, h5; + | | | + 11 | SCT0 | mad | 39: MADr r0.xy,-h4, const.xy--, r1.zw--; + | SCT1 | mov | 41: TXLr h0, r0, const.zzzz, TEX0; + | TEX | txl | 41: TXLr h0, r0, const.zzzz, TEX0; + | SCB0 | mad | 44: MADr r2.xy, h4, const.xy--, r1.zw--; + | SCB1 | add | 43: ADDh*8 h5.z, h5.--y-,-h4.--w-; + | | | + 12 | SCT0/1 | mov | 46: TXLr h3, r2, const.xxxx, TEX0; + | TEX | txl | 46: TXLr h3, r2, const.xxxx, TEX0; + | SCB0/1 | add | 48: ADDh/2 h0, h0, h3; + | | | + 13 | SCT0/1 | mad | 49: ADDh/2 h3, h0, h2; + | SCB0/1 | mul | 50: MOVh h0, h3; + | | | + 14 | SCT0 | set | 51: SLTh h3.x, h3.w---, h5.w---; + | SCT1 | set | 52: SGTh h3.w, h3, h5.---x; + | SCB0 | set | 54: SLThc0 rc, h5.z---, h5; + | SCB1 | add | 53: ADDxc0_s rc, h3.---x, h3; + | | | + 15 | SCT0/1 | mul | 55: MOVh h0(NE0.wwww), h2; + | SCB0/1 | mul | 56: MOVh h0(NE0.xxxx), h1; + +Pass SCT TEX SCB + 1: 0% 100% 25% + 2: 0% 100% 25% + 3: 0% 100% 50% + 4: 0% 100% 50% + 5: 50% 0% 25% + 6: 0% 0% 25% + 7: 100% 0% 25% + 8: 0% 100% 50% + 9: 0% 100% 100% + 10: 0% 100% 50% + 11: 0% 100% 75% + 12: 0% 100% 100% + 13: 100% 0% 100% + 14: 50% 0% 50% + 15: 100% 0% 100% + +MEAN: 26% 60% 56% + +Pass SCT0 SCT1 TEX SCB0 SCB1 + 1: 0% 0% 100% 100% 0% + 2: 0% 0% 100% 100% 0% + 3: 0% 0% 100% 100% 100% + 4: 0% 0% 100% 100% 100% + 5: 100% 100% 0% 100% 0% + 6: 0% 0% 0% 0% 100% + 7: 100% 100% 0% 0% 100% + 8: 0% 0% 100% 100% 100% + 9: 0% 0% 100% 100% 100% + 10: 0% 0% 100% 100% 100% + 11: 0% 0% 100% 100% 100% + 12: 0% 0% 100% 100% 100% + 13: 100% 100% 0% 100% 100% + 14: 100% 100% 0% 100% 100% + 15: 100% 100% 0% 100% 100% + +MEAN: 33% 33% 60% 86% 80% +Fragment Performance Setup: Driver RSX Compiler, GPU RSX, Flags 0x5 +Results 15 cycles, 3 r regs, 800,000,000 pixels/s +============================================================================*/ +#if (FXAA_PS3 == 1) && (FXAA_EARLY_EXIT == 1) +/*--------------------------------------------------------------------------*/ +#pragma regcount 7 +#pragma disablepc all +#pragma option O2 +#pragma option OutColorPrec=fp16 +#pragma texformat default RGBA8 +/*==========================================================================*/ +half4 FxaaPixelShader( + // See FXAA Quality FxaaPixelShader() source for docs on Inputs! + FxaaFloat2 pos, + FxaaFloat4 fxaaConsolePosPos, + FxaaTex tex, + FxaaTex fxaaConsole360TexExpBiasNegOne, + FxaaTex fxaaConsole360TexExpBiasNegTwo, + FxaaFloat2 fxaaQualityRcpFrame, + FxaaFloat4 fxaaConsoleRcpFrameOpt, + FxaaFloat4 fxaaConsoleRcpFrameOpt2, + FxaaFloat4 fxaaConsole360RcpFrameOpt2, + FxaaFloat fxaaQualitySubpix, + FxaaFloat fxaaQualityEdgeThreshold, + FxaaFloat fxaaQualityEdgeThresholdMin, + FxaaFloat fxaaConsoleEdgeSharpness, + FxaaFloat fxaaConsoleEdgeThreshold, + FxaaFloat fxaaConsoleEdgeThresholdMin, + FxaaFloat4 fxaaConsole360ConstDir +) { +/*--------------------------------------------------------------------------*/ +// (1) + half4 rgbyNe = h4tex2Dlod(tex, half4(fxaaConsolePosPos.zy, 0, 0)); + #if (FXAA_GREEN_AS_LUMA == 0) + half lumaNe = rgbyNe.w + half(1.0/512.0); + #else + half lumaNe = rgbyNe.y + half(1.0/512.0); + #endif +/*--------------------------------------------------------------------------*/ +// (2) + half4 lumaSw = h4tex2Dlod(tex, half4(fxaaConsolePosPos.xw, 0, 0)); + #if (FXAA_GREEN_AS_LUMA == 0) + half lumaSwNegNe = lumaSw.w - lumaNe; + #else + half lumaSwNegNe = lumaSw.y - lumaNe; + #endif +/*--------------------------------------------------------------------------*/ +// (3) + half4 lumaNw = h4tex2Dlod(tex, half4(fxaaConsolePosPos.xy, 0, 0)); + #if (FXAA_GREEN_AS_LUMA == 0) + half lumaMaxNwSw = max(lumaNw.w, lumaSw.w); + half lumaMinNwSw = min(lumaNw.w, lumaSw.w); + #else + half lumaMaxNwSw = max(lumaNw.y, lumaSw.y); + half lumaMinNwSw = min(lumaNw.y, lumaSw.y); + #endif +/*--------------------------------------------------------------------------*/ +// (4) + half4 lumaSe = h4tex2Dlod(tex, half4(fxaaConsolePosPos.zw, 0, 0)); + #if (FXAA_GREEN_AS_LUMA == 0) + half dirZ = lumaNw.w + lumaSwNegNe; + half dirX = -lumaNw.w + lumaSwNegNe; + #else + half dirZ = lumaNw.y + lumaSwNegNe; + half dirX = -lumaNw.y + lumaSwNegNe; + #endif +/*--------------------------------------------------------------------------*/ +// (5) + half3 dir; + dir.y = 0.0; + #if (FXAA_GREEN_AS_LUMA == 0) + dir.x = lumaSe.w + dirX; + dir.z = -lumaSe.w + dirZ; + half lumaMinNeSe = min(lumaNe, lumaSe.w); + #else + dir.x = lumaSe.y + dirX; + dir.z = -lumaSe.y + dirZ; + half lumaMinNeSe = min(lumaNe, lumaSe.y); + #endif +/*--------------------------------------------------------------------------*/ +// (6) + half4 dir1_pos; + dir1_pos.xy = normalize(dir).xz; + half dirAbsMinTimes8 = min(abs(dir1_pos.x), abs(dir1_pos.y)) * half(FXAA_CONSOLE__PS3_EDGE_SHARPNESS); +/*--------------------------------------------------------------------------*/ +// (7) + half4 dir2_pos; + dir2_pos.xy = clamp(dir1_pos.xy / dirAbsMinTimes8, half(-2.0), half(2.0)); + dir1_pos.zw = pos.xy; + dir2_pos.zw = pos.xy; + #if (FXAA_GREEN_AS_LUMA == 0) + half lumaMaxNeSe = max(lumaNe, lumaSe.w); + #else + half lumaMaxNeSe = max(lumaNe, lumaSe.y); + #endif +/*--------------------------------------------------------------------------*/ +// (8) + half4 temp1N; + temp1N.xy = dir1_pos.zw - dir1_pos.xy * fxaaConsoleRcpFrameOpt.zw; + temp1N = h4tex2Dlod(tex, half4(temp1N.xy, 0.0, 0.0)); + half lumaMax = max(lumaMaxNwSw, lumaMaxNeSe); + half lumaMin = min(lumaMinNwSw, lumaMinNeSe); +/*--------------------------------------------------------------------------*/ +// (9) + half4 rgby1; + rgby1.xy = dir1_pos.zw + dir1_pos.xy * fxaaConsoleRcpFrameOpt.zw; + rgby1 = h4tex2Dlod(tex, half4(rgby1.xy, 0.0, 0.0)); + rgby1 = (temp1N + rgby1) * 0.5; +/*--------------------------------------------------------------------------*/ +// (10) + half4 rgbyM = h4tex2Dlod(tex, half4(pos.xy, 0.0, 0.0)); + #if (FXAA_GREEN_AS_LUMA == 0) + half lumaMaxM = max(lumaMax, rgbyM.w); + half lumaMinM = min(lumaMin, rgbyM.w); + #else + half lumaMaxM = max(lumaMax, rgbyM.y); + half lumaMinM = min(lumaMin, rgbyM.y); + #endif +/*--------------------------------------------------------------------------*/ +// (11) + half4 temp2N; + temp2N.xy = dir2_pos.zw - dir2_pos.xy * fxaaConsoleRcpFrameOpt2.zw; + temp2N = h4tex2Dlod(tex, half4(temp2N.xy, 0.0, 0.0)); + half4 rgby2; + rgby2.xy = dir2_pos.zw + dir2_pos.xy * fxaaConsoleRcpFrameOpt2.zw; + half lumaRangeM = (lumaMaxM - lumaMinM) / FXAA_CONSOLE__PS3_EDGE_THRESHOLD; +/*--------------------------------------------------------------------------*/ +// (12) + rgby2 = h4tex2Dlod(tex, half4(rgby2.xy, 0.0, 0.0)); + rgby2 = (temp2N + rgby2) * 0.5; +/*--------------------------------------------------------------------------*/ +// (13) + rgby2 = (rgby2 + rgby1) * 0.5; +/*--------------------------------------------------------------------------*/ +// (14) + #if (FXAA_GREEN_AS_LUMA == 0) + bool twoTapLt = rgby2.w < lumaMin; + bool twoTapGt = rgby2.w > lumaMax; + #else + bool twoTapLt = rgby2.y < lumaMin; + bool twoTapGt = rgby2.y > lumaMax; + #endif + bool earlyExit = lumaRangeM < lumaMax; + bool twoTap = twoTapLt || twoTapGt; +/*--------------------------------------------------------------------------*/ +// (15) + if(twoTap) rgby2 = rgby1; + if(earlyExit) rgby2 = rgbyM; +/*--------------------------------------------------------------------------*/ + return rgby2; } +/*==========================================================================*/ +#endif diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/fxaa/fxaaP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/fxaa/fxaaP.hlsl new file mode 100644 index 000000000..269bfea67 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/fxaa/fxaaP.hlsl @@ -0,0 +1,143 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../shaderModel.hlsl" + +#define FXAA_PC 1 +#if (TORQUE_SM <= 30) +#define FXAA_HLSL_3 1 +#elif TORQUE_SM < 49 +#define FXAA_HLSL_4 1 +#elif TORQUE_SM >=50 +#define FXAA_HLSL_5 1 +#endif +#define FXAA_QUALITY__PRESET 12 +#define FXAA_GREEN_AS_LUMA 1 + +#include "Fxaa3_11.h" + +struct VertToPix +{ + float4 hpos : TORQUE_POSITION; + float2 uv0 : TEXCOORD0; +}; + +TORQUE_UNIFORM_SAMPLER2D(colorTex, 0); + +uniform float2 oneOverTargetSize; + + +float4 main( VertToPix IN ) : TORQUE_TARGET0 +{ +#if (TORQUE_SM >= 10 && TORQUE_SM <=30) + FxaaTex tex = colorTex; +#elif TORQUE_SM >=40 + FxaaTex tex; + tex.smpl = colorTex; + tex.tex = texture_colorTex; +#endif + + return FxaaPixelShader( + + IN.uv0, // vertex position + + 0, // Unused... console stuff + + tex, // The color back buffer + + tex, // Used for 360 optimization + + tex, // Used for 360 optimization + + oneOverTargetSize, + + 0, // Unused... console stuff + + 0, // Unused... console stuff + + 0, // Unused... console stuff + + // + // Only used on FXAA Quality. + // This used to be the FXAA_QUALITY__SUBPIX define. + // It is here now to allow easier tuning. + // Choose the amount of sub-pixel aliasing removal. + // This can effect sharpness. + // 1.00 - upper limit (softer) + // 0.75 - default amount of filtering + // 0.50 - lower limit (sharper, less sub-pixel aliasing removal) + // 0.25 - almost off + // 0.00 - completely off + 0.75, + + // + // Only used on FXAA Quality. + // This used to be the FXAA_QUALITY__EDGE_THRESHOLD define. + // It is here now to allow easier tuning. + // The minimum amount of local contrast required to apply algorithm. + // 0.333 - too little (faster) + // 0.250 - low quality + // 0.166 - default + // 0.125 - high quality + // 0.063 - overkill (slower) + 0.166, + + // + // Only used on FXAA Quality. + // This used to be the FXAA_QUALITY__EDGE_THRESHOLD_MIN define. + // It is here now to allow easier tuning. + // Trims the algorithm from processing darks. + // 0.0833 - upper limit (default, the start of visible unfiltered edges) + // 0.0625 - high quality (faster) + // 0.0312 - visible limit (slower) + // Special notes when using FXAA_GREEN_AS_LUMA, + // Likely want to set this to zero. + // As colors that are mostly not-green + // will appear very dark in the green channel! + // Tune by looking at mostly non-green content, + // then start at zero and increase until aliasing is a problem. + 0, + + // + // Only used on FXAA Console. + // This used to be the FXAA_CONSOLE__EDGE_SHARPNESS define. + // It is here now to allow easier tuning. + // This does not effect PS3, as this needs to be compiled in. + // Use FXAA_CONSOLE__PS3_EDGE_SHARPNESS for PS3. + // Due to the PS3 being ALU bound, + // there are only three safe values here: 2 and 4 and 8. + // These options use the shaders ability to a free *|/ by 2|4|8. + // For all other platforms can be a non-power of two. + // 8.0 is sharper (default!!!) + // 4.0 is softer + // 2.0 is really soft (good only for vector graphics inputs) + 8, + + 0, // Unused... console stuff + + 0, // Unused... console stuff + + 0 // Unused... console stuff + + ); +} + diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/fxaa/fxaaV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/fxaa/fxaaV.hlsl new file mode 100644 index 000000000..f2974c587 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/fxaa/fxaaV.hlsl @@ -0,0 +1,42 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "./../../torque.hlsl" +#include "./../postFx.hlsl" + +struct VertToPix +{ + float4 hpos : TORQUE_POSITION; + float2 uv0 : TEXCOORD0; +}; + +uniform float4 rtParams0; + +VertToPix main( PFXVert IN ) +{ + VertToPix OUT; + + OUT.hpos = float4(IN.pos,1); + OUT.uv0 = viewportCoordToRenderTarget( IN.uv, rtParams0 ); + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/fxaa/gl/fxaaP.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/fxaa/gl/fxaaP.glsl new file mode 100644 index 000000000..19d76ef42 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/fxaa/gl/fxaaP.glsl @@ -0,0 +1,125 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#define FXAA_PC 1 +#define FXAA_GLSL_130 1 +#define FXAA_QUALITY__PRESET 12 +#define FXAA_GREEN_AS_LUMA 1 + +#include "../Fxaa3_11.h" +#include "../../../gl/hlslCompat.glsl" + +uniform sampler2D colorTex ; +uniform vec2 oneOverTargetSize; + +in vec4 hpos; +in vec2 uv0; + +out vec4 OUT_col; + +void main() +{ + OUT_col = FxaaPixelShader( + + uv0, // vertex position + + vec4(0), // Unused... console stuff + + colorTex, // The color back buffer + + colorTex, // Used for 360 optimization + + colorTex, // Used for 360 optimization + + oneOverTargetSize, + + vec4(0), // Unused... console stuff + + vec4(0), // Unused... console stuff + + vec4(0), // Unused... console stuff + + // + // Only used on FXAA Quality. + // This used to be the FXAA_QUALITY__SUBPIX define. + // It is here now to allow easier tuning. + // Choose the amount of sub-pixel aliasing removal. + // This can effect sharpness. + // 1.00 - upper limit (softer) + // 0.75 - default amount of filtering + // 0.50 - lower limit (sharper, less sub-pixel aliasing removal) + // 0.25 - almost off + // 0.00 - completely off + 0.75, + + // + // Only used on FXAA Quality. + // This used to be the FXAA_QUALITY__EDGE_THRESHOLD define. + // It is here now to allow easier tuning. + // The minimum amount of local contrast required to apply algorithm. + // 0.333 - too little (faster) + // 0.250 - low quality + // 0.166 - default + // 0.125 - high quality + // 0.063 - overkill (slower) + 0.166, + + // + // Only used on FXAA Quality. + // This used to be the FXAA_QUALITY__EDGE_THRESHOLD_MIN define. + // It is here now to allow easier tuning. + // Trims the algorithm from processing darks. + // 0.0833 - upper limit (default, the start of visible unfiltered edges) + // 0.0625 - high quality (faster) + // 0.0312 - visible limit (slower) + // Special notes when using FXAA_GREEN_AS_LUMA, + // Likely want to set this to zero. + // As colors that are mostly not-green + // will appear very dark in the green channel! + // Tune by looking at mostly non-green content, + // then start at zero and increase until aliasing is a problem. + 0, + + // + // Only used on FXAA Console. + // This used to be the FXAA_CONSOLE__EDGE_SHARPNESS define. + // It is here now to allow easier tuning. + // This does not effect PS3, as this needs to be compiled in. + // Use FXAA_CONSOLE__PS3_EDGE_SHARPNESS for PS3. + // Due to the PS3 being ALU bound, + // there are only three safe values here: 2 and 4 and 8. + // These options use the shaders ability to a free *|/ by 2|4|8. + // For all other platforms can be a non-power of two. + // 8.0 is sharper (default!!!) + // 4.0 is softer + // 2.0 is really soft (good only for vector graphics inputs) + 8, + + 0, // Unused... console stuff + + 0, // Unused... console stuff + + vec4(0) // Unused... console stuff + + ); +} + diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/fxaa/gl/fxaaV.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/fxaa/gl/fxaaV.glsl new file mode 100644 index 000000000..55d445d91 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/fxaa/gl/fxaaV.glsl @@ -0,0 +1,40 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- +#include "../../../gl/hlslCompat.glsl" +#include "../../../gl/torque.glsl" + +in vec4 vPosition; +in vec2 vTexCoord0; + +uniform vec4 rtParams0; + +out vec4 hpos; +out vec2 uv0; + +void main() +{ + gl_Position = vPosition; + hpos = gl_Position; + uv0 = viewportCoordToRenderTarget( vTexCoord0, rtParams0 ); + + correctSSP(gl_Position); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/gammaP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/gammaP.hlsl new file mode 100644 index 000000000..1e13d068b --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/gammaP.hlsl @@ -0,0 +1,50 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "shadergen:/autogenConditioners.h" +#include "./postFx.hlsl" +#include "../torque.hlsl" + +TORQUE_UNIFORM_SAMPLER2D(backBuffer, 0); +TORQUE_UNIFORM_SAMPLER1D(colorCorrectionTex, 1); + +uniform float OneOverGamma; +uniform float Brightness; +uniform float Contrast; + +float4 main( PFXVertToPix IN ) : TORQUE_TARGET0 +{ + float4 color = TORQUE_TEX2D(backBuffer, IN.uv0.xy); + + // Apply the color correction. + color.r = TORQUE_TEX1D( colorCorrectionTex, color.r ).r; + color.g = TORQUE_TEX1D( colorCorrectionTex, color.g ).g; + color.b = TORQUE_TEX1D( colorCorrectionTex, color.b ).b; + + // Apply contrast + color.rgb = ((color.rgb - 0.5f) * Contrast) + 0.5f; + + // Apply brightness + color.rgb += Brightness; + + return color; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/gl/VolFogGlowP.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/gl/VolFogGlowP.glsl new file mode 100644 index 000000000..01b072dd9 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/gl/VolFogGlowP.glsl @@ -0,0 +1,67 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 R.G.S. - Richards Game Studio, the Netherlands +// http://www.richardsgamestudio.com/ +// +// If you find this code useful or you are feeling particularly generous I +// would ask that you please go to http://www.richardsgamestudio.com/ then +// choose Donations from the menu on the left side and make a donation to +// Richards Game Studio. It will be highly appreciated. +// +// The MIT License: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// Volumetric Fog Glow postFx pixel shader V1.00 + +uniform sampler2D diffuseMap; +uniform float strength; + +out vec4 OUT_col; + +in vec2 uv0; +in vec2 uv1; +in vec2 uv2; +in vec2 uv3; + +in vec2 uv4; +in vec2 uv5; +in vec2 uv6; +in vec2 uv7; + +void main() +{ + vec4 kernel = vec4( 0.175, 0.275, 0.375, 0.475 ) * strength; + + OUT_col = vec4(0); + OUT_col += texture( diffuseMap, uv0 ) * kernel.x; + OUT_col += texture( diffuseMap, uv1 ) * kernel.y; + OUT_col += texture( diffuseMap, uv2 ) * kernel.z; + OUT_col += texture( diffuseMap, uv3 ) * kernel.w; + + OUT_col += texture( diffuseMap, uv4 ) * kernel.x; + OUT_col += texture( diffuseMap, uv5 ) * kernel.y; + OUT_col += texture( diffuseMap, uv6 ) * kernel.z; + OUT_col += texture( diffuseMap, uv7 ) * kernel.w; + + // Calculate a lumenance value in the alpha so we + // can use alpha test to save fillrate. + vec3 rgb2lum = vec3( 0.30, 0.59, 0.11 ); + OUT_col.a = dot( OUT_col.rgb, rgb2lum ); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/gl/chromaticLens.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/gl/chromaticLens.glsl new file mode 100644 index 000000000..fdb85ba00 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/gl/chromaticLens.glsl @@ -0,0 +1,62 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// Based on 'Cubic Lens Distortion HLSL Shader' by François Tarlier +// www.francois-tarlier.com/blog/index.php/2009/11/cubic-lens-distortion-shader + +#include "./postFX.glsl" +#include "../../gl/torque.glsl" +#include "../../gl/hlslCompat.glsl" + +uniform sampler2D backBuffer; +uniform float distCoeff; +uniform float cubeDistort; +uniform vec3 colorDistort; + +out vec4 OUT_col; + +void main() +{ + vec2 tex = IN_uv0; + + float f = 0; + float r2 = (tex.x - 0.5) * (tex.x - 0.5) + (tex.y - 0.5) * (tex.y - 0.5); + + // Only compute the cubic distortion if necessary. + if ( cubeDistort == 0.0 ) + f = 1 + r2 * distCoeff; + else + f = 1 + r2 * (distCoeff + cubeDistort * sqrt(r2)); + + // Distort each color channel seperately to get a chromatic distortion effect. + vec3 outColor; + vec3 distort = vec3(f) + colorDistort; + + for ( int i=0; i < 3; i++ ) + { + float x = distort[i] * ( tex.x - 0.5 ) + 0.5; + float y = distort[i] * ( tex.y - 0.5 ) + 0.5; + outColor[i] = tex2Dlod( backBuffer, vec4(x,y,0,0) )[i]; + } + + OUT_col = vec4( outColor.rgb, 1 ); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/gl/flashP.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/gl/flashP.glsl new file mode 100644 index 000000000..fc5072e6d --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/gl/flashP.glsl @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "./postFX.glsl" +#include "../../gl/torque.glsl" +#include "../../gl/hlslCompat.glsl" + +uniform float damageFlash; +uniform float whiteOut; +uniform sampler2D backBuffer; + +out vec4 OUT_col; + +void main() +{ + vec4 color1 = texture(backBuffer, IN_uv0); + vec4 color2 = color1 * MUL_COLOR; + vec4 damage = mix(color1,color2,damageFlash); + OUT_col = mix(damage,WHITE_COLOR,whiteOut); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/gl/fogP.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/gl/fogP.glsl new file mode 100644 index 000000000..c2fe32fe4 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/gl/fogP.glsl @@ -0,0 +1,52 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../gl/hlslCompat.glsl" + +#include "shadergen:/autogenConditioners.h" +#include "../../gl/torque.glsl" + +uniform sampler2D deferredTex ; +uniform vec3 eyePosWorld; +uniform vec4 fogColor; +uniform vec3 fogData; +uniform vec4 rtParams0; + +in vec2 uv0; +in vec3 wsEyeRay; + +out vec4 OUT_col; + +void main() +{ + //vec2 deferredCoord = ( uv0.xy * rtParams0.zw ) + rtParams0.xy; + float depth = deferredUncondition( deferredTex, uv0 ).w; + //return vec4( depth, 0, 0, 0.7 ); + + float factor = computeSceneFog( eyePosWorld, + eyePosWorld + ( wsEyeRay * depth ), + fogData.x, + fogData.y, + fogData.z ); + + OUT_col = hdrEncode( vec4( fogColor.rgb, 1.0 - saturate( factor ) ) ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/gl/gammaP.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/gl/gammaP.glsl new file mode 100644 index 000000000..04533e494 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/gl/gammaP.glsl @@ -0,0 +1,54 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../gl/hlslCompat.glsl" +#include "../../gl/torque.glsl" +#include "shadergen:/autogenConditioners.h" + +uniform sampler2D backBuffer; +uniform sampler1D colorCorrectionTex; + +uniform float OneOverGamma; +uniform float Brightness; +uniform float Contrast; + +in vec2 uv0; + +out vec4 OUT_col; + +void main() +{ + vec4 color = texture(backBuffer, uv0.xy); + + // Apply the color correction. + color.r = texture( colorCorrectionTex, color.r ).r; + color.g = texture( colorCorrectionTex, color.g ).g; + color.b = texture( colorCorrectionTex, color.b ).b; + + // Apply contrast + color.rgb = ((color.rgb - 0.5f) * Contrast) + 0.5f; + + // Apply brightness + color.rgb += Brightness; + + OUT_col = color; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/gl/glowBlurP.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/gl/glowBlurP.glsl new file mode 100644 index 000000000..9ebca32fa --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/gl/glowBlurP.glsl @@ -0,0 +1,59 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../gl/hlslCompat.glsl" + +uniform sampler2D diffuseMap ; + +in vec4 hpos; //POSITION; +in vec2 uv0; //TEXCOORD0; +in vec2 uv1; //TEXCOORD1; +in vec2 uv2; //TEXCOORD2; +in vec2 uv3; //TEXCOORD3; +in vec2 uv4; //TEXCOORD4; +in vec2 uv5; //TEXCOORD5; +in vec2 uv6; //TEXCOORD6; +in vec2 uv7; //TEXCOORD7; + +out vec4 OUT_col; + +void main() +{ + vec4 kernel = vec4( 0.175, 0.275, 0.375, 0.475 ) * 0.5f; + + OUT_col = vec4(0); + OUT_col += texture( diffuseMap, uv0 ) * kernel.x; + OUT_col += texture( diffuseMap, uv1 ) * kernel.y; + OUT_col += texture( diffuseMap, uv2 ) * kernel.z; + OUT_col += texture( diffuseMap, uv3 ) * kernel.w; + + OUT_col += texture( diffuseMap, uv4 ) * kernel.x; + OUT_col += texture( diffuseMap, uv5 ) * kernel.y; + OUT_col += texture( diffuseMap, uv6 ) * kernel.z; + OUT_col += texture( diffuseMap, uv7 ) * kernel.w; + + // Calculate a lumenance value in the alpha so we + // can use alpha test to save fillrate. + vec3 rgb2lum = vec3( 0.30, 0.59, 0.11 ); + OUT_col.a = dot( OUT_col.rgb, rgb2lum ); + +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/gl/glowBlurV.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/gl/glowBlurV.glsl new file mode 100644 index 000000000..70445d7fe --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/gl/glowBlurV.glsl @@ -0,0 +1,59 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../gl/hlslCompat.glsl" +#include "../../gl/torque.glsl" + +in vec4 vPosition; +in vec2 vTexCoord0; + +uniform vec2 texSize0; + +out vec4 hpos; //POSITION; +out vec2 uv0; //TEXCOORD0; +out vec2 uv1; //TEXCOORD1; +out vec2 uv2; //TEXCOORD2; +out vec2 uv3; //TEXCOORD3; +out vec2 uv4; //TEXCOORD4; +out vec2 uv5; //TEXCOORD5; +out vec2 uv6; //TEXCOORD6; +out vec2 uv7; //TEXCOORD7; + +void main() +{ + gl_Position = vPosition; + hpos = gl_Position; + + vec2 uv = vTexCoord0 + (0.5f / texSize0); + + uv0 = uv + ( ( BLUR_DIR * 3.5f ) / texSize0 ); + uv1 = uv + ( ( BLUR_DIR * 2.5f ) / texSize0 ); + uv2 = uv + ( ( BLUR_DIR * 1.5f ) / texSize0 ); + uv3 = uv + ( ( BLUR_DIR * 0.5f ) / texSize0 ); + + uv4 = uv - ( ( BLUR_DIR * 3.5f ) / texSize0 ); + uv5 = uv - ( ( BLUR_DIR * 2.5f ) / texSize0 ); + uv6 = uv - ( ( BLUR_DIR * 1.5f ) / texSize0 ); + uv7 = uv - ( ( BLUR_DIR * 0.5f ) / texSize0 ); + + correctSSP(gl_Position); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/gl/motionBlurP.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/gl/motionBlurP.glsl new file mode 100644 index 000000000..8077d4124 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/gl/motionBlurP.glsl @@ -0,0 +1,78 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../gl/hlslCompat.glsl" +#include "../../gl/torque.glsl" +#include "shadergen:/autogenConditioners.h" +#include "postFX.glsl" + +#undef IN_uv0 +#define _IN_uv0 uv0 + +uniform mat4 matPrevScreenToWorld; +uniform mat4 matWorldToScreen; + +// Passed in from setShaderConsts() +uniform float velocityMultiplier; + +uniform sampler2D backBuffer; +uniform sampler2D deferredTex; + +out vec4 OUT_col; + +void main() +{ + vec2 IN_uv0 = _IN_uv0; + float samples = 5; + + // First get the deferred texture for uv channel 0 + vec4 deferred = deferredUncondition( deferredTex, IN_uv0 ); + + // Next extract the depth + float depth = deferred.a; + + // Create the screen position + vec4 screenPos = vec4(IN_uv0.x*2-1, IN_uv0.y*2-1, depth*2-1, 1); + + // Calculate the world position + vec4 D = tMul(screenPos, matWorldToScreen); + vec4 worldPos = D / D.w; + + // Now calculate the previous screen position + vec4 previousPos = tMul( worldPos, matPrevScreenToWorld ); + previousPos /= previousPos.w; + + // Calculate the XY velocity + vec2 velocity = ((screenPos - previousPos) / velocityMultiplier).xy; + + // Generate the motion blur + vec4 color = texture(backBuffer, IN_uv0); + IN_uv0 += velocity; + + for(int i = 1; i 0 ) + { + rayStart.z -= ( startSide ); + //return vec4( 1, 0, 0, 1 ); + } + + vec3 hitPos; + vec3 ray = rayEnd - rayStart; + float rayLen = length( ray ); + vec3 rayDir = normalize( ray ); + + float endSide = dot( plane.xyz, rayEnd ) + plane.w; + float planeDist; + + if ( endSide < -0.005 ) + { + //return vec4( 0, 0, 1, 1 ); + hitPos = rayEnd; + planeDist = endSide; + } + else + { + //return vec4( 0, 0, 0, 0 ); + float den = dot( ray, plane.xyz ); + + // Parallal to the plane, return the endPnt. + //if ( den == 0.0f ) + // return endPnt; + + float dist = -( dot( plane.xyz, rayStart ) + plane.w ) / den; + if ( dist < 0.0 ) + dist = 0.0; + //return vec4( 1, 0, 0, 1 ); + //return vec4( ( dist ).rrr, 1 ); + + + hitPos = mix( rayStart, rayEnd, dist ); + + planeDist = dist; + } + + float delta = length( hitPos - rayStart ); + + float fogAmt = 1.0 - saturate( exp( -FOG_DENSITY * ( delta - FOG_DENSITY_OFFSET ) ) ); + //return vec4( fogAmt.rrr, 1 ); + + // Calculate the water "base" color based on depth. + vec4 fogColor = waterColor * texture( waterDepthGradMap, saturate( delta / waterDepthGradMax ) ); + // Modulate baseColor by the ambientColor. + fogColor *= vec4( ambientColor.rgb, 1 ); + + vec3 inColor = hdrDecode( texture( backbuffer, IN_uv0 ).rgb ); + inColor.rgb *= 1.0 - saturate( abs( planeDist ) / WET_DEPTH ) * WET_DARKENING; + //return vec4( inColor, 1 ); + + vec3 outColor = mix( inColor, fogColor.rgb, fogAmt ); + + OUT_col = vec4( hdrEncode( outColor ), 1 ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/glowBlurP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/glowBlurP.hlsl new file mode 100644 index 000000000..80f8ed02d --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/glowBlurP.hlsl @@ -0,0 +1,63 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "./postFx.hlsl" + +TORQUE_UNIFORM_SAMPLER2D(diffuseMap, 0); + +struct VertToPix +{ + float4 hpos : TORQUE_POSITION; + + float2 uv0 : TEXCOORD0; + float2 uv1 : TEXCOORD1; + float2 uv2 : TEXCOORD2; + float2 uv3 : TEXCOORD3; + + float2 uv4 : TEXCOORD4; + float2 uv5 : TEXCOORD5; + float2 uv6 : TEXCOORD6; + float2 uv7 : TEXCOORD7; +}; + +float4 main( VertToPix IN ) : TORQUE_TARGET0 +{ + float4 kernel = float4( 0.175, 0.275, 0.375, 0.475 ) * 0.5f; + + float4 OUT = 0; + OUT += TORQUE_TEX2D( diffuseMap, IN.uv0 ) * kernel.x; + OUT += TORQUE_TEX2D( diffuseMap, IN.uv1 ) * kernel.y; + OUT += TORQUE_TEX2D( diffuseMap, IN.uv2 ) * kernel.z; + OUT += TORQUE_TEX2D( diffuseMap, IN.uv3 ) * kernel.w; + + OUT += TORQUE_TEX2D( diffuseMap, IN.uv4 ) * kernel.x; + OUT += TORQUE_TEX2D( diffuseMap, IN.uv5 ) * kernel.y; + OUT += TORQUE_TEX2D( diffuseMap, IN.uv6 ) * kernel.z; + OUT += TORQUE_TEX2D( diffuseMap, IN.uv7 ) * kernel.w; + + // Calculate a lumenance value in the alpha so we + // can use alpha test to save fillrate. + float3 rgb2lum = float3( 0.30, 0.59, 0.11 ); + OUT.a = dot( OUT.rgb, rgb2lum ); + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/glowBlurV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/glowBlurV.hlsl new file mode 100644 index 000000000..b8f5cf9c2 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/glowBlurV.hlsl @@ -0,0 +1,63 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "./postFx.hlsl" +#include "./../torque.hlsl" + + +uniform float2 texSize0; + +struct VertToPix +{ + float4 hpos : TORQUE_POSITION; + + float2 uv0 : TEXCOORD0; + float2 uv1 : TEXCOORD1; + float2 uv2 : TEXCOORD2; + float2 uv3 : TEXCOORD3; + + float2 uv4 : TEXCOORD4; + float2 uv5 : TEXCOORD5; + float2 uv6 : TEXCOORD6; + float2 uv7 : TEXCOORD7; +}; + +VertToPix main( PFXVert IN ) +{ + VertToPix OUT; + + OUT.hpos = float4(IN.pos,1.0); + + float2 uv = IN.uv + (0.5f / texSize0); + + OUT.uv0 = uv + ( ( BLUR_DIR * 3.5f ) / texSize0 ); + OUT.uv1 = uv + ( ( BLUR_DIR * 2.5f ) / texSize0 ); + OUT.uv2 = uv + ( ( BLUR_DIR * 1.5f ) / texSize0 ); + OUT.uv3 = uv + ( ( BLUR_DIR * 0.5f ) / texSize0 ); + + OUT.uv4 = uv - ( ( BLUR_DIR * 3.5f ) / texSize0 ); + OUT.uv5 = uv - ( ( BLUR_DIR * 2.5f ) / texSize0 ); + OUT.uv6 = uv - ( ( BLUR_DIR * 1.5f ) / texSize0 ); + OUT.uv7 = uv - ( ( BLUR_DIR * 0.5f ) / texSize0 ); + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/bloomGaussBlurHP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/bloomGaussBlurHP.hlsl new file mode 100644 index 000000000..77f4b9915 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/bloomGaussBlurHP.hlsl @@ -0,0 +1,68 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../postFx.hlsl" + +TORQUE_UNIFORM_SAMPLER2D(inputTex, 0); +uniform float2 oneOverTargetSize; +uniform float gaussMultiplier; +uniform float gaussMean; +uniform float gaussStdDev; + +#define PI 3.141592654 + +float computeGaussianValue( float x, float mean, float std_deviation ) +{ + // The gaussian equation is defined as such: + /* + -(x - mean)^2 + ------------- + 1.0 2*std_dev^2 + f(x,mean,std_dev) = -------------------- * e^ + sqrt(2*pi*std_dev^2) + + */ + + float tmp = ( 1.0f / sqrt( 2.0f * PI * std_deviation * std_deviation ) ); + float tmp2 = exp( ( -( ( x - mean ) * ( x - mean ) ) ) / ( 2.0f * std_deviation * std_deviation ) ); + return tmp * tmp2; +} + +float4 main( PFXVertToPix IN ) : TORQUE_TARGET0 +{ + float4 color = { 0.0f, 0.0f, 0.0f, 0.0f }; + float offset = 0; + float weight = 0; + float x = 0; + float fI = 0; + + for( int i = 0; i < 9; i++ ) + { + fI = (float)i; + offset = (i - 4.0) * oneOverTargetSize.x; + x = (i - 4.0) / 4.0; + weight = gaussMultiplier * computeGaussianValue( x, gaussMean, gaussStdDev ); + color += (TORQUE_TEX2D( inputTex, IN.uv0 + float2( offset, 0.0f ) ) * weight ); + } + + return float4( color.rgb, 1.0f ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/bloomGaussBlurVP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/bloomGaussBlurVP.hlsl new file mode 100644 index 000000000..8381f6a5d --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/bloomGaussBlurVP.hlsl @@ -0,0 +1,67 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../postFx.hlsl" + +TORQUE_UNIFORM_SAMPLER2D(inputTex, 0); +uniform float2 oneOverTargetSize; +uniform float gaussMultiplier; +uniform float gaussMean; +uniform float gaussStdDev; + +#define D3DX_PI 3.141592654 + +float computeGaussianValue( float x, float mean, float std_deviation ) +{ + // The gaussian equation is defined as such: + /* + -(x - mean)^2 + ------------- + 1.0 2*std_dev^2 + f(x,mean,std_dev) = -------------------- * e^ + sqrt(2*pi*std_dev^2) + + */ + float tmp = ( 1.0f / sqrt( 2.0f * D3DX_PI * std_deviation * std_deviation ) ); + float tmp2 = exp( ( -( ( x - mean ) * ( x - mean ) ) ) / ( 2.0f * std_deviation * std_deviation ) ); + return tmp * tmp2; +} + +float4 main( PFXVertToPix IN ) : TORQUE_TARGET0 +{ + float4 color = { 0.0f, 0.0f, 0.0f, 0.0f }; + float offset = 0; + float weight = 0; + float x = 0; + float fI = 0; + + for( int i = 0; i < 9; i++ ) + { + fI = (float)i; + offset = (fI - 4.0) * oneOverTargetSize.y; + x = (fI - 4.0) / 4.0; + weight = gaussMultiplier * computeGaussianValue( x, gaussMean, gaussStdDev ); + color += (TORQUE_TEX2D( inputTex, IN.uv0 + float2( 0.0f, offset ) ) * weight ); + } + + return float4( color.rgb, 1.0f ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/brightPassFilterP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/brightPassFilterP.hlsl new file mode 100644 index 000000000..9a8a93e97 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/brightPassFilterP.hlsl @@ -0,0 +1,62 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../postFx.hlsl" +#include "../../torque.hlsl" + + +TORQUE_UNIFORM_SAMPLER2D(inputTex, 0); +TORQUE_UNIFORM_SAMPLER2D(luminanceTex, 1); +uniform float2 oneOverTargetSize; +uniform float brightPassThreshold; +uniform float g_fMiddleGray; + +static const float3 LUMINANCE_VECTOR = float3(0.3125f, 0.6154f, 0.0721f); + + +static float2 gTapOffsets[4] = +{ + { -0.5, 0.5 }, { 0.5, -0.5 }, + { -0.5, -0.5 }, { 0.5, 0.5 } +}; + +float4 main( PFXVertToPix IN ) : TORQUE_TARGET0 +{ + float4 average = { 0.0f, 0.0f, 0.0f, 0.0f }; + + // Combine and average 4 samples from the source HDR texture. + for( int i = 0; i < 4; i++ ) + average += hdrDecode( TORQUE_TEX2D( inputTex, IN.uv0 + ( gTapOffsets[i] * oneOverTargetSize ) ) ); + average *= 0.25f; + + // Determine the brightness of this particular pixel. + float adaptedLum = TORQUE_TEX2D( luminanceTex, float2( 0.5f, 0.5f ) ).r; + float lum = (g_fMiddleGray / (adaptedLum + 0.0001)) * hdrLuminance( average.rgb ); + //float lum = hdrLuminance( average.rgb ); + + // Determine whether this pixel passes the test... + if ( lum < brightPassThreshold ) + average = float4( 0.0f, 0.0f, 0.0f, 1.0f ); + + // Write the colour to the bright-pass render target + return hdrEncode( average ); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/calculateAdaptedLumP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/calculateAdaptedLumP.hlsl new file mode 100644 index 000000000..0f895070a --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/calculateAdaptedLumP.hlsl @@ -0,0 +1,44 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../postFx.hlsl" + +TORQUE_UNIFORM_SAMPLER2D(currLum, 0); +TORQUE_UNIFORM_SAMPLER2D(lastAdaptedLum, 1); + +uniform float adaptRate; +uniform float deltaTime; + +float4 main( PFXVertToPix IN ) : TORQUE_TARGET0 +{ + float fAdaptedLum = TORQUE_TEX2D( lastAdaptedLum, float2(0.5f, 0.5f) ).r; + float fCurrentLum = TORQUE_TEX2D( currLum, float2(0.5f, 0.5f) ).r; + + // The user's adapted luminance level is simulated by closing the gap between + // adapted luminance and current luminance by 2% every frame, based on a + // 30 fps rate. This is not an accurate model of human adaptation, which can + // take longer than half an hour. + float diff = fCurrentLum - fAdaptedLum; + float fNewAdaptation = fAdaptedLum + ( diff * ( 1.0 - exp( -deltaTime * adaptRate ) ) ); + + return float4( fNewAdaptation, 0.0, 0.0, 1.0f ); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/downScale4x4P.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/downScale4x4P.hlsl new file mode 100644 index 000000000..01998af0b --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/downScale4x4P.hlsl @@ -0,0 +1,53 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#define IN_HLSL +#include "../../shdrConsts.h" +#include "../postFx.hlsl" + +//----------------------------------------------------------------------------- +// Data +//----------------------------------------------------------------------------- +struct VertIn +{ + float4 hpos : TORQUE_POSITION; + float4 texCoords[8] : TEXCOORD0; +}; + +TORQUE_UNIFORM_SAMPLER2D(inputTex, 0); + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +float4 main( VertIn IN) : TORQUE_TARGET0 +{ + // We calculate the texture coords + // in the vertex shader as an optimization. + float4 sample = 0.0f; + for ( int i = 0; i < 8; i++ ) + { + sample += TORQUE_TEX2D( inputTex, IN.texCoords[i].xy ); + sample += TORQUE_TEX2D( inputTex, IN.texCoords[i].zw ); + } + + return sample / 16; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/downScale4x4V.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/downScale4x4V.hlsl new file mode 100644 index 000000000..c9a34b7f4 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/downScale4x4V.hlsl @@ -0,0 +1,138 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#define IN_HLSL +#include "../../shdrConsts.h" +#include "../postFx.hlsl" +//----------------------------------------------------------------------------- +// Constants +//----------------------------------------------------------------------------- + +struct Conn +{ + float4 hpos : TORQUE_POSITION; + float4 texCoords[8] : TEXCOORD0; +}; + +uniform float2 targetSize; + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +Conn main( PFXVert In ) +{ + Conn Out; + + Out.hpos = float4(In.pos,1.0); + + // Sample from the 16 surrounding points. Since the center point will be in + // the exact center of 16 texels, a 0.5f offset is needed to specify a texel + // center. + float2 texSize = float2( 1.0 / (targetSize.x - 1.0), 1.0 / (targetSize.y - 1.0) ); + + float4 uv; + uv.xy = In.uv.xy; + uv.zw = In.uv.xy; + + Out.texCoords[0] = uv; + Out.texCoords[0].x += texSize.x; + Out.texCoords[0].y += texSize.y; + Out.texCoords[0].z += texSize.x; + Out.texCoords[0].w += texSize.y; + Out.texCoords[0].x += ( 0 - 1.5 ) * texSize.x; + Out.texCoords[0].y += ( 0 - 1.5 ) * texSize.y; + Out.texCoords[0].z += ( 1 - 1.5 ) * texSize.x; + Out.texCoords[0].w += ( 0 - 1.5 ) * texSize.y; + + Out.texCoords[1] = uv; + Out.texCoords[1].x += texSize.x; + Out.texCoords[1].y += texSize.y; + Out.texCoords[1].z += texSize.x; + Out.texCoords[1].w += texSize.y; + Out.texCoords[1].x += ( 2 - 1.5 ) * texSize.x; + Out.texCoords[1].y += ( 0 - 1.5 ) * texSize.y; + Out.texCoords[1].z += ( 3 - 1.5 ) * texSize.x; + Out.texCoords[1].w += ( 0 - 1.5 ) * texSize.y; + + Out.texCoords[2] = uv; + Out.texCoords[2].x += texSize.x; + Out.texCoords[2].y += texSize.y; + Out.texCoords[2].z += texSize.x; + Out.texCoords[2].w += texSize.y; + Out.texCoords[2].x += ( 0 - 1.5 ) * texSize.x; + Out.texCoords[2].y += ( 1 - 1.5 ) * texSize.y; + Out.texCoords[2].z += ( 1 - 1.5 ) * texSize.x; + Out.texCoords[2].w += ( 1 - 1.5 ) * texSize.y; + + Out.texCoords[3] = uv; + Out.texCoords[3].x += texSize.x; + Out.texCoords[3].y += texSize.y; + Out.texCoords[3].z += texSize.x; + Out.texCoords[3].w += texSize.y; + Out.texCoords[3].x += ( 2 - 1.5 ) * texSize.x; + Out.texCoords[3].y += ( 1 - 1.5 ) * texSize.y; + Out.texCoords[3].z += ( 3 - 1.5 ) * texSize.x; + Out.texCoords[3].w += ( 1 - 1.5 ) * texSize.y; + + Out.texCoords[4] = uv; + Out.texCoords[4].x += texSize.x; + Out.texCoords[4].y += texSize.y; + Out.texCoords[4].z += texSize.x; + Out.texCoords[4].w += texSize.y; + Out.texCoords[4].x += ( 0 - 1.5 ) * texSize.x; + Out.texCoords[4].y += ( 2 - 1.5 ) * texSize.y; + Out.texCoords[4].z += ( 1 - 1.5 ) * texSize.x; + Out.texCoords[4].w += ( 2 - 1.5 ) * texSize.y; + + Out.texCoords[5] = uv; + Out.texCoords[5].x += texSize.x; + Out.texCoords[5].y += texSize.y; + Out.texCoords[5].z += texSize.x; + Out.texCoords[5].w += texSize.y; + Out.texCoords[5].x += ( 2 - 1.5 ) * texSize.x; + Out.texCoords[5].y += ( 2 - 1.5 ) * texSize.y; + Out.texCoords[5].z += ( 3 - 1.5 ) * texSize.x; + Out.texCoords[5].w += ( 2 - 1.5 ) * texSize.y; + + Out.texCoords[6] = uv; + Out.texCoords[6].x += texSize.x; + Out.texCoords[6].y += texSize.y; + Out.texCoords[6].z += texSize.x; + Out.texCoords[6].w += texSize.y; + Out.texCoords[6].x += ( 0 - 1.5 ) * texSize.x; + Out.texCoords[6].y += ( 3 - 1.5 ) * texSize.y; + Out.texCoords[6].z += ( 1 - 1.5 ) * texSize.x; + Out.texCoords[6].w += ( 3 - 1.5 ) * texSize.y; + + Out.texCoords[7] = uv; + Out.texCoords[7].x += texSize.x; + Out.texCoords[7].y += texSize.y; + Out.texCoords[7].z += texSize.x; + Out.texCoords[7].w += texSize.y; + Out.texCoords[7].x += ( 2 - 1.5 ) * texSize.x; + Out.texCoords[7].y += ( 3 - 1.5 ) * texSize.y; + Out.texCoords[7].z += ( 3 - 1.5 ) * texSize.x; + Out.texCoords[7].w += ( 3 - 1.5 ) * texSize.y; + + return Out; +} + diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/finalPassCombineP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/finalPassCombineP.hlsl new file mode 100644 index 000000000..07f7276c3 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/finalPassCombineP.hlsl @@ -0,0 +1,92 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../torque.hlsl" +#include "../postFx.hlsl" +#include "../../shaderModelAutoGen.hlsl" + +TORQUE_UNIFORM_SAMPLER2D(sceneTex, 0); +TORQUE_UNIFORM_SAMPLER2D(luminanceTex, 1); +TORQUE_UNIFORM_SAMPLER2D(bloomTex, 2); +TORQUE_UNIFORM_SAMPLER1D(colorCorrectionTex, 3); + +uniform float2 texSize0; +uniform float2 texSize2; + +uniform float g_fEnableToneMapping; +uniform float g_fMiddleGray; +uniform float g_fWhiteCutoff; +uniform float g_fEnableBlueShift; + +uniform float3 g_fBlueShiftColor; +uniform float g_fBloomScale; +uniform float g_fOneOverGamma; +uniform float Brightness; +uniform float Contrast; + +float4 main( PFXVertToPix IN ) : TORQUE_TARGET0 +{ + float4 sample = hdrDecode( TORQUE_TEX2D( sceneTex, IN.uv0 ) ); + float adaptedLum = TORQUE_TEX2D( luminanceTex, float2( 0.5f, 0.5f ) ).r; + float4 bloom = TORQUE_TEX2D( bloomTex, IN.uv0 ); + + // For very low light conditions, the rods will dominate the perception + // of light, and therefore color will be desaturated and shifted + // towards blue. + if ( g_fEnableBlueShift > 0.0f ) + { + const float3 LUMINANCE_VECTOR = float3(0.2125f, 0.7154f, 0.0721f); + + // Define a linear blending from -1.5 to 2.6 (log scale) which + // determines the lerp amount for blue shift + float coef = 1.0f - ( adaptedLum + 1.5 ) / 4.1; + coef = saturate( coef * g_fEnableBlueShift ); + + // Lerp between current color and blue, desaturated copy + float3 rodColor = dot( sample.rgb, LUMINANCE_VECTOR ) * g_fBlueShiftColor; + sample.rgb = lerp( sample.rgb, rodColor, coef ); + + rodColor = dot( bloom.rgb, LUMINANCE_VECTOR ) * g_fBlueShiftColor; + bloom.rgb = lerp( bloom.rgb, rodColor, coef ); + } + + // Add the bloom effect. + sample += g_fBloomScale * bloom; + + // Map the high range of color values into a range appropriate for + // display, taking into account the user's adaptation level, + // white point, and selected value for for middle gray. + if ( g_fEnableToneMapping > 0.0f ) + { + float Lp = (g_fMiddleGray / (adaptedLum + 0.0001)) * hdrLuminance( sample.rgb ); + //float toneScalar = ( Lp * ( 1.0 + ( Lp / ( g_fWhiteCutoff ) ) ) ) / ( 1.0 + Lp ); + float toneScalar = Lp; + sample.rgb = lerp( sample.rgb, sample.rgb * toneScalar, g_fEnableToneMapping ); + } + + // Apply the color correction. + sample.r = TORQUE_TEX1D( colorCorrectionTex, sample.r ).r; + sample.g = TORQUE_TEX1D( colorCorrectionTex, sample.g ).g; + sample.b = TORQUE_TEX1D( colorCorrectionTex, sample.b ).b; + + return sample; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/bloomGaussBlurHP.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/bloomGaussBlurHP.glsl new file mode 100644 index 000000000..1d9a2df3e --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/bloomGaussBlurHP.glsl @@ -0,0 +1,72 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" +#include "shadergen:/autogenConditioners.h" +#include "../../gl/postFX.glsl" + +uniform sampler2D inputTex ; +uniform vec2 oneOverTargetSize; +uniform float gaussMultiplier; +uniform float gaussMean; +uniform float gaussStdDev; + +out vec4 OUT_col; + +#define PI 3.141592654 + +float computeGaussianValue( float x, float mean, float std_deviation ) +{ + // The gaussian equation is defined as such: + /* + -(x - mean)^2 + ------------- + 1.0 2*std_dev^2 + f(x,mean,std_dev) = -------------------- * e^ + sqrt(2*pi*std_dev^2) + + */ + + float tmp = ( 1.0f / sqrt( 2.0f * PI * std_deviation * std_deviation ) ); + float tmp2 = exp( ( -( ( x - mean ) * ( x - mean ) ) ) / ( 2.0f * std_deviation * std_deviation ) ); + return tmp * tmp2; +} + +void main() +{ + vec4 color = vec4( 0.0f, 0.0f, 0.0f, 0.0f ); + float offset = 0; + float weight = 0; + float x = 0; + float fI = 0; + + for( int i = 0; i < 9; i++ ) + { + fI = float(i); + offset = (i - 4.0) * oneOverTargetSize.x; + x = (i - 4.0) / 4.0; + weight = gaussMultiplier * computeGaussianValue( x, gaussMean, gaussStdDev ); + color += (texture( inputTex, IN_uv0 + vec2( offset, 0.0f ) ) * weight ); + } + + OUT_col = vec4( color.rgb, 1.0f ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/bloomGaussBlurVP.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/bloomGaussBlurVP.glsl new file mode 100644 index 000000000..68f34b164 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/bloomGaussBlurVP.glsl @@ -0,0 +1,71 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" +#include "shadergen:/autogenConditioners.h" +#include "../../gl/postFX.glsl" + +uniform sampler2D inputTex ; +uniform vec2 oneOverTargetSize; +uniform float gaussMultiplier; +uniform float gaussMean; +uniform float gaussStdDev; + +out vec4 OUT_col; + +#define D3DX_PI 3.141592654 + +float computeGaussianValue( float x, float mean, float std_deviation ) +{ + // The gaussian equation is defined as such: + /* + -(x - mean)^2 + ------------- + 1.0 2*std_dev^2 + f(x,mean,std_dev) = -------------------- * e^ + sqrt(2*pi*std_dev^2) + + */ + float tmp = ( 1.0f / sqrt( 2.0f * D3DX_PI * std_deviation * std_deviation ) ); + float tmp2 = exp( ( -( ( x - mean ) * ( x - mean ) ) ) / ( 2.0f * std_deviation * std_deviation ) ); + return tmp * tmp2; +} + +void main() +{ + vec4 color = vec4( 0.0f, 0.0f, 0.0f, 0.0f ); + float offset = 0; + float weight = 0; + float x = 0; + float fI = 0; + + for( int i = 0; i < 9; i++ ) + { + fI = float(i); + offset = (fI - 4.0) * oneOverTargetSize.y; + x = (fI - 4.0) / 4.0; + weight = gaussMultiplier * computeGaussianValue( x, gaussMean, gaussStdDev ); + color += (texture( inputTex, IN_uv0 + vec2( 0.0f, offset ) ) * weight ); + } + + OUT_col = vec4( color.rgb, 1.0f ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/brightPassFilterP.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/brightPassFilterP.glsl new file mode 100644 index 000000000..f220ca1e7 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/brightPassFilterP.glsl @@ -0,0 +1,65 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/torque.glsl" +#include "../../../gl/hlslCompat.glsl" +#include "shadergen:/autogenConditioners.h" +#include "../../gl/postFX.glsl" + +uniform sampler2D inputTex ; +uniform sampler2D luminanceTex ; +uniform vec2 oneOverTargetSize; +uniform float brightPassThreshold; +uniform float g_fMiddleGray; + +const vec3 LUMINANCE_VECTOR = vec3(0.3125f, 0.6154f, 0.0721f); + +out vec4 OUT_col; + + +const vec2 gTapOffsets[4] = vec2[] +( + vec2( -0.5, 0.5 ), vec2( 0.5, -0.5 ), + vec2( -0.5, -0.5 ), vec2( 0.5, 0.5 ) +); + +void main() +{ + vec4 average = vec4( 0.0f, 0.0f, 0.0f, 0.0f ); + + // Combine and average 4 samples from the source HDR texture. + for( int i = 0; i < 4; i++ ) + average += hdrDecode( texture( inputTex, IN_uv0 + ( gTapOffsets[i] * oneOverTargetSize ) ) ); + average *= 0.25f; + + // Determine the brightness of this particular pixel. + float adaptedLum = texture( luminanceTex, vec2( 0.5f, 0.5f ) ).r; + float lum = (g_fMiddleGray / (adaptedLum + 0.0001)) * hdrLuminance( average.rgb ); + //float lum = hdrLuminance( average.rgb ); + + // Determine whether this pixel passes the test... + if ( lum < brightPassThreshold ) + average = vec4( 0.0f, 0.0f, 0.0f, 1.0f ); + + // Write the colour to the bright-pass render target + OUT_col = hdrEncode( average ); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/calculateAdaptedLumP.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/calculateAdaptedLumP.glsl new file mode 100644 index 000000000..96ee9d6df --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/calculateAdaptedLumP.glsl @@ -0,0 +1,48 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" +#include "shadergen:/autogenConditioners.h" +#include "../../gl/postFX.glsl" + +uniform sampler2D currLum; +uniform sampler2D lastAdaptedLum; + +uniform float adaptRate; +uniform float deltaTime; + +out vec4 OUT_col; + +void main() +{ + float fAdaptedLum = texture( lastAdaptedLum, vec2(0.5f, 0.5f) ).r; + float fCurrentLum = texture( currLum, vec2(0.5f, 0.5f) ).r; + + // The user's adapted luminance level is simulated by closing the gap between + // adapted luminance and current luminance by 2% every frame, based on a + // 30 fps rate. This is not an accurate model of human adaptation, which can + // take longer than half an hour. + float diff = fCurrentLum - fAdaptedLum; + float fNewAdaptation = fAdaptedLum + ( diff * ( 1.0 - exp( -deltaTime * adaptRate ) ) ); + + OUT_col = vec4( fNewAdaptation, 0.0, 0.0, 1.0f ); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/downScale4x4P.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/downScale4x4P.glsl new file mode 100644 index 000000000..131671760 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/downScale4x4P.glsl @@ -0,0 +1,50 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#define IN_GLSL +#include "../../../shdrConsts.h" +#include "../../../gl/hlslCompat.glsl" +#include "shadergen:/autogenConditioners.h" + +in vec4 texCoords[8]; +#define IN_texCoords texCoords + +uniform sampler2D inputTex; + +out vec4 OUT_col; + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +void main() +{ + // We calculate the texture coords + // in the vertex shader as an optimization. + vec4 _sample = vec4(0.0f); + for ( int i = 0; i < 8; i++ ) + { + _sample += texture( inputTex, IN_texCoords[i].xy ); + _sample += texture( inputTex, IN_texCoords[i].zw ); + } + + OUT_col = _sample / 16; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/downScale4x4V.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/downScale4x4V.glsl new file mode 100644 index 000000000..51f1da896 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/downScale4x4V.glsl @@ -0,0 +1,141 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#define IN_GLSL +#include "../../../shdrConsts.h" +#include "../../../gl/hlslCompat.glsl" + +in vec4 vPosition; +in vec2 vTexCoord0; + +#define In_pos vPosition +#define In_uv vTexCoord0 + +//----------------------------------------------------------------------------- +// Constants +//----------------------------------------------------------------------------- +out vec4 texCoords[8]; +#define Out_texCoords texCoords + +#define Out_hpos gl_Position + +uniform vec2 targetSize; + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +void main() +{ + Out_hpos = In_pos; + + // Sample from the 16 surrounding points. Since the center point will be in + // the exact center of 16 texels, a 0.5f offset is needed to specify a texel + // center. + vec2 texSize = vec2( 1.0 / (targetSize.x - 1.0), 1.0 / (targetSize.y - 1.0) ); + + vec4 uv; + uv.xy = In_uv.xy; + uv.zw = In_uv.xy; + + Out_texCoords[0] = uv; + Out_texCoords[0].x += texSize.x; + Out_texCoords[0].y += texSize.y; + Out_texCoords[0].z += texSize.x; + Out_texCoords[0].w += texSize.y; + Out_texCoords[0].x += ( 0 - 1.5 ) * texSize.x; + Out_texCoords[0].y += ( 0 - 1.5 ) * texSize.y; + Out_texCoords[0].z += ( 1 - 1.5 ) * texSize.x; + Out_texCoords[0].w += ( 0 - 1.5 ) * texSize.y; + + Out_texCoords[1] = uv; + Out_texCoords[1].x += texSize.x; + Out_texCoords[1].y += texSize.y; + Out_texCoords[1].z += texSize.x; + Out_texCoords[1].w += texSize.y; + Out_texCoords[1].x += ( 2 - 1.5 ) * texSize.x; + Out_texCoords[1].y += ( 0 - 1.5 ) * texSize.y; + Out_texCoords[1].z += ( 3 - 1.5 ) * texSize.x; + Out_texCoords[1].w += ( 0 - 1.5 ) * texSize.y; + + Out_texCoords[2] = uv; + Out_texCoords[2].x += texSize.x; + Out_texCoords[2].y += texSize.y; + Out_texCoords[2].z += texSize.x; + Out_texCoords[2].w += texSize.y; + Out_texCoords[2].x += ( 0 - 1.5 ) * texSize.x; + Out_texCoords[2].y += ( 1 - 1.5 ) * texSize.y; + Out_texCoords[2].z += ( 1 - 1.5 ) * texSize.x; + Out_texCoords[2].w += ( 1 - 1.5 ) * texSize.y; + + Out_texCoords[3] = uv; + Out_texCoords[3].x += texSize.x; + Out_texCoords[3].y += texSize.y; + Out_texCoords[3].z += texSize.x; + Out_texCoords[3].w += texSize.y; + Out_texCoords[3].x += ( 2 - 1.5 ) * texSize.x; + Out_texCoords[3].y += ( 1 - 1.5 ) * texSize.y; + Out_texCoords[3].z += ( 3 - 1.5 ) * texSize.x; + Out_texCoords[3].w += ( 1 - 1.5 ) * texSize.y; + + Out_texCoords[4] = uv; + Out_texCoords[4].x += texSize.x; + Out_texCoords[4].y += texSize.y; + Out_texCoords[4].z += texSize.x; + Out_texCoords[4].w += texSize.y; + Out_texCoords[4].x += ( 0 - 1.5 ) * texSize.x; + Out_texCoords[4].y += ( 2 - 1.5 ) * texSize.y; + Out_texCoords[4].z += ( 1 - 1.5 ) * texSize.x; + Out_texCoords[4].w += ( 2 - 1.5 ) * texSize.y; + + Out_texCoords[5] = uv; + Out_texCoords[5].x += texSize.x; + Out_texCoords[5].y += texSize.y; + Out_texCoords[5].z += texSize.x; + Out_texCoords[5].w += texSize.y; + Out_texCoords[5].x += ( 2 - 1.5 ) * texSize.x; + Out_texCoords[5].y += ( 2 - 1.5 ) * texSize.y; + Out_texCoords[5].z += ( 3 - 1.5 ) * texSize.x; + Out_texCoords[5].w += ( 2 - 1.5 ) * texSize.y; + + Out_texCoords[6] = uv; + Out_texCoords[6].x += texSize.x; + Out_texCoords[6].y += texSize.y; + Out_texCoords[6].z += texSize.x; + Out_texCoords[6].w += texSize.y; + Out_texCoords[6].x += ( 0 - 1.5 ) * texSize.x; + Out_texCoords[6].y += ( 3 - 1.5 ) * texSize.y; + Out_texCoords[6].z += ( 1 - 1.5 ) * texSize.x; + Out_texCoords[6].w += ( 3 - 1.5 ) * texSize.y; + + Out_texCoords[7] = uv; + Out_texCoords[7].x += texSize.x; + Out_texCoords[7].y += texSize.y; + Out_texCoords[7].z += texSize.x; + Out_texCoords[7].w += texSize.y; + Out_texCoords[7].x += ( 2 - 1.5 ) * texSize.x; + Out_texCoords[7].y += ( 3 - 1.5 ) * texSize.y; + Out_texCoords[7].z += ( 3 - 1.5 ) * texSize.x; + Out_texCoords[7].w += ( 3 - 1.5 ) * texSize.y; + + correctSSP(gl_Position); +} + diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/finalPassCombineP.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/finalPassCombineP.glsl new file mode 100644 index 000000000..4b173d4d3 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/finalPassCombineP.glsl @@ -0,0 +1,97 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/torque.glsl" +#include "../../../gl/hlslCompat.glsl" +#include "../../gl/postFX.glsl" +#include "shadergen:/autogenConditioners.h" + +uniform sampler2D sceneTex; +uniform sampler2D luminanceTex; +uniform sampler2D bloomTex; +uniform sampler1D colorCorrectionTex; + +uniform vec2 texSize0; +uniform vec2 texSize2; + +uniform float g_fEnableToneMapping; +uniform float g_fMiddleGray; +uniform float g_fWhiteCutoff; + +uniform float g_fEnableBlueShift; +uniform vec3 g_fBlueShiftColor; + +uniform float g_fBloomScale; + +uniform float g_fOneOverGamma; +uniform float Brightness; +uniform float Contrast; + +out vec4 OUT_col; + +void main() +{ + vec4 _sample = hdrDecode( texture( sceneTex, IN_uv0 ) ); + float adaptedLum = texture( luminanceTex, vec2( 0.5f, 0.5f ) ).r; + vec4 bloom = texture( bloomTex, IN_uv0 ); + + // For very low light conditions, the rods will dominate the perception + // of light, and therefore color will be desaturated and shifted + // towards blue. + if ( g_fEnableBlueShift > 0.0f ) + { + const vec3 LUMINANCE_VECTOR = vec3(0.2125f, 0.7154f, 0.0721f); + + // Define a linear blending from -1.5 to 2.6 (log scale) which + // determines the mix amount for blue shift + float coef = 1.0f - ( adaptedLum + 1.5 ) / 4.1; + coef = saturate( coef * g_fEnableBlueShift ); + + // Lerp between current color and blue, desaturated copy + vec3 rodColor = dot( _sample.rgb, LUMINANCE_VECTOR ) * g_fBlueShiftColor; + _sample.rgb = mix( _sample.rgb, rodColor, coef ); + + rodColor = dot( bloom.rgb, LUMINANCE_VECTOR ) * g_fBlueShiftColor; + bloom.rgb = mix( bloom.rgb, rodColor, coef ); + } + + // Add the bloom effect. + _sample += g_fBloomScale * bloom; + + // Map the high range of color values into a range appropriate for + // display, taking into account the user's adaptation level, + // white point, and selected value for for middle gray. + if ( g_fEnableToneMapping > 0.0f ) + { + float Lp = (g_fMiddleGray / (adaptedLum + 0.0001)) * hdrLuminance( _sample.rgb ); + //float toneScalar = ( Lp * ( 1.0 + ( Lp / ( g_fWhiteCutoff ) ) ) ) / ( 1.0 + Lp ); + float toneScalar = Lp; + _sample.rgb = mix( _sample.rgb, _sample.rgb * toneScalar, g_fEnableToneMapping ); + } + + // Apply the color correction. + _sample.r = texture( colorCorrectionTex, _sample.r ).r; + _sample.g = texture( colorCorrectionTex, _sample.g ).g; + _sample.b = texture( colorCorrectionTex, _sample.b ).b; + + OUT_col = _sample; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/luminanceVisP.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/luminanceVisP.glsl new file mode 100644 index 000000000..ee9c28c87 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/luminanceVisP.glsl @@ -0,0 +1,42 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/torque.glsl" +#include "../../../gl/hlslCompat.glsl" +#include "shadergen:/autogenConditioners.h" +#include "../../gl/postFX.glsl" + +uniform sampler2D inputTex; +uniform float brightPassThreshold; + +out vec4 OUT_col; + +void main() +{ + vec4 _sample = hdrDecode( texture( inputTex, IN_uv0 ) ); + + // Determine the brightness of this particular pixel. + float lum = hdrLuminance( _sample.rgb ); + + // Write the colour to the bright-pass render target + OUT_col = ( vec4( lum.rrr, 1 ) ); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/sampleLumInitialP.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/sampleLumInitialP.glsl new file mode 100644 index 000000000..8a2b9b318 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/sampleLumInitialP.glsl @@ -0,0 +1,62 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/torque.glsl" +#include "../../../gl/hlslCompat.glsl" +#include "../../gl/postFX.glsl" + +uniform sampler2D inputTex; +uniform vec2 texSize0; + +uniform float g_fMinLuminace; + +out vec4 OUT_col; + +const vec2 gTapOffsets[9] = vec2[] +( + vec2( -1.0, -1.0 ), vec2( 0.0, -1.0 ), vec2( 1.0, -1.0 ), + vec2( -1.0, 0.0 ), vec2( 0.0, 0.0 ), vec2( 1.0, 0.0 ), + vec2( -1.0, 1.0 ), vec2( 0.0, 1.0 ), vec2( 1.0, 1.0 ) +); + + +void main() +{ + vec2 tsize = 1.0 / texSize0; + + vec3 _sample; + float average = 0.0; + + for ( int i = 0; i < 9; i++ ) + { + // Decode the hdr value. + _sample = hdrDecode( texture( inputTex, IN_uv0 + ( gTapOffsets[i] * tsize ) ).rgb ); + + // Get the luminance and add it to the average. + float lum = max( hdrLuminance( _sample ), g_fMinLuminace ); + average += log( lum ); + } + + average = exp( average / 9.0 ); + + OUT_col = vec4( average, 0.0, 0.0, 1.0 ); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/sampleLumIterativeP.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/sampleLumIterativeP.glsl new file mode 100644 index 000000000..2e800d612 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/gl/sampleLumIterativeP.glsl @@ -0,0 +1,52 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" +#include "../../gl/postFX.glsl" + +uniform sampler2D inputTex; +uniform vec2 oneOverTargetSize; + +out vec4 OUT_col; + +const vec2 gTapOffsets[16] = vec2[] +( + vec2( -1.5, -1.5 ), vec2( -0.5, -1.5 ), vec2( 0.5, -1.5 ), vec2( 1.5, -1.5 ), + vec2( -1.5, -0.5 ), vec2( -0.5, -0.5 ), vec2( 0.5, -0.5 ), vec2( 1.5, -0.5 ), + vec2( -1.5, 0.5 ), vec2( -0.5, 0.5 ), vec2( 0.5, 0.5 ), vec2( 1.5, 0.5 ), + vec2( -1.5, 1.5 ), vec2( -0.5, 1.5 ), vec2( 0.5, 1.5 ), vec2( 1.5, 1.5 ) +); + +void main() +{ + vec2 pixelSize = oneOverTargetSize; + + float average = 0.0; + + for ( int i = 0; i < 16; i++ ) + { + float lum = texture( inputTex, IN_uv0 + ( gTapOffsets[i] * pixelSize ) ).r; + average += lum; + } + + OUT_col = vec4( average / 16.0, 0.0, 0.0, 1.0 ); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/luminanceVisP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/luminanceVisP.hlsl new file mode 100644 index 000000000..505d1b825 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/luminanceVisP.hlsl @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../postFx.hlsl" +#include "../../torque.hlsl" + + +TORQUE_UNIFORM_SAMPLER2D(inputTex, 0); +uniform float brightPassThreshold; + +float4 main( PFXVertToPix IN ) : TORQUE_TARGET0 +{ + float4 sample = hdrDecode( TORQUE_TEX2D( inputTex, IN.uv0 ) ); + + // Determine the brightness of this particular pixel. + float lum = hdrLuminance( sample.rgb ); + + // Write the colour to the bright-pass render target + return ( float4( lum.rrr, 1 ) ); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/sampleLumInitialP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/sampleLumInitialP.hlsl new file mode 100644 index 000000000..2e23ece1f --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/sampleLumInitialP.hlsl @@ -0,0 +1,59 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../torque.hlsl" +#include "../postFx.hlsl" + +TORQUE_UNIFORM_SAMPLER2D(inputTex, 0); +uniform float2 texSize0; + +uniform float g_fMinLuminace; + +static float2 gTapOffsets[9] = +{ + { -1.0, -1.0 }, { 0.0, -1.0 }, { 1.0, -1.0 }, + { -1.0, 0.0 }, { 0.0, 0.0 }, { 1.0, 0.0 }, + { -1.0, 1.0 }, { 0.0, 1.0 }, { 1.0, 1.0 } +}; + + +float4 main( PFXVertToPix IN ) : TORQUE_TARGET0 +{ + float2 tsize = 1.0 / texSize0; + + float3 sample; + float average = 0.0; + + for ( int i = 0; i < 9; i++ ) + { + // Decode the hdr value. + sample = hdrDecode( TORQUE_TEX2D( inputTex, IN.uv0 + ( gTapOffsets[i] * tsize ) ).rgb ); + + // Get the luminance and add it to the average. + float lum = max( hdrLuminance( sample ), g_fMinLuminace ); + average += log( lum ); + } + + average = exp( average / 9.0 ); + + return float4( average, 0.0, 0.0, 1.0 ); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/sampleLumIterativeP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/sampleLumIterativeP.hlsl new file mode 100644 index 000000000..46ed6fc70 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/hdr/sampleLumIterativeP.hlsl @@ -0,0 +1,50 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../postFx.hlsl" + +TORQUE_UNIFORM_SAMPLER2D(inputTex, 0); +uniform float2 oneOverTargetSize; + + +static float2 gTapOffsets[16] = +{ + { -1.5, -1.5 }, { -0.5, -1.5 }, { 0.5, -1.5 }, { 1.5, -1.5 }, + { -1.5, -0.5 }, { -0.5, -0.5 }, { 0.5, -0.5 }, { 1.5, -0.5 }, + { -1.5, 0.5 }, { -0.5, 0.5 }, { 0.5, 0.5 }, { 1.5, 0.5 }, + { -1.5, 1.5 }, { -0.5, 1.5 }, { 0.5, 1.5 }, { 1.5, 1.5 } +}; + +float4 main( PFXVertToPix IN ) : TORQUE_TARGET0 +{ + float2 pixelSize = oneOverTargetSize; + + float average = 0.0; + + for ( int i = 0; i < 16; i++ ) + { + float lum = TORQUE_TEX2D( inputTex, IN.uv0 + ( gTapOffsets[i] * pixelSize ) ).r; + average += lum; + } + + return float4( average / 16.0, 0.0, 0.0, 1.0 ); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/lightRay/gl/lightRayOccludeP.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/lightRay/gl/lightRayOccludeP.glsl new file mode 100644 index 000000000..59f5f4bbf --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/lightRay/gl/lightRayOccludeP.glsl @@ -0,0 +1,55 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" +#include "shadergen:/autogenConditioners.h" +#include "../../gl/postFX.glsl" + +uniform sampler2D backBuffer; // The original backbuffer. +uniform sampler2D deferredTex; // The pre-pass depth and normals. + +uniform float brightScalar; + +const vec3 LUMINANCE_VECTOR = vec3(0.3125f, 0.6154f, 0.0721f); + +out vec4 OUT_col; + +void main() +{ + vec4 col = vec4( 0, 0, 0, 1 ); + + // Get the depth at this pixel. + float depth = deferredUncondition( deferredTex, IN_uv0 ).w; + + // If the depth is equal to 1.0, read from the backbuffer + // and perform the exposure calculation on the result. + if ( depth >= 0.999 ) + { + col = texture( backBuffer, IN_uv0 ); + + //col = 1 - exp(-120000 * col); + col += dot( vec3(col), LUMINANCE_VECTOR ) + 0.0001f; + col *= brightScalar; + } + + OUT_col = col; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/lightRay/gl/lightRayP.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/lightRay/gl/lightRayP.glsl new file mode 100644 index 000000000..6d78f4eae --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/lightRay/gl/lightRayP.glsl @@ -0,0 +1,94 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" +#include "../../gl/postFX.glsl" + +uniform sampler2D frameSampler; +uniform sampler2D backBuffer; + +uniform vec3 camForward; +uniform vec3 lightDirection; +uniform vec2 screenSunPos; +uniform vec2 oneOverTargetSize; +uniform int numSamples; +uniform float density; +uniform float weight; +uniform float decay; +uniform float exposure; + +out vec4 OUT_col; + +void main() +{ + vec4 texCoord = vec4( IN_uv0.xy, 0, 0 ); + + // Store initial sample. + half3 color = half3(texture( frameSampler, texCoord.xy ).rgb); + + // Store original bb color. + vec4 bbCol = texture( backBuffer, IN_uv1 ); + + // Set up illumination decay factor. + half illuminationDecay = 1.0; + + float amount = saturate( dot( -lightDirection, camForward ) ); + + int samples = int(numSamples * amount); + + if ( samples <= 0 ) + { + OUT_col = bbCol; + return; + } + + // Calculate vector from pixel to light source in screen space. + half2 deltaTexCoord = half2( texCoord.xy - screenSunPos ); + + // Divide by number of samples and scale by control factor. + deltaTexCoord *= 1.0 / half(samples * density); + + // Evaluate summation from Equation 3 NUM_SAMPLES iterations. + for ( int i = 0; i < samples; i++ ) + { + // Step sample location along ray. + texCoord.xy -= deltaTexCoord; + + // Retrieve sample at new location. + half3 sample_ = half3(tex2Dlod( frameSampler, texCoord )); + + // Apply sample attenuation scale/decay factors. + sample_ *= illuminationDecay * weight; + + // Accumulate combined color. + color += sample_; + + // Update exponential decay factor. + illuminationDecay *= decay; + } + + //return saturate( amount ) * color * Exposure; + //return bbCol * decay; + + // Output final color with a further scale control factor. + OUT_col = saturate( amount ) * vec4( color * exposure, 1 ) + bbCol; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/lightRay/lightRayOccludeP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/lightRay/lightRayOccludeP.hlsl new file mode 100644 index 000000000..5db6ecb5b --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/lightRay/lightRayOccludeP.hlsl @@ -0,0 +1,53 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../shaderModelAutoGen.hlsl" +#include "../postFx.hlsl" + +TORQUE_UNIFORM_SAMPLER2D(backBuffer, 0); +TORQUE_UNIFORM_SAMPLER2D(deferredTex, 1); + +uniform float brightScalar; + +static const float3 LUMINANCE_VECTOR = float3(0.3125f, 0.6154f, 0.0721f); + + +float4 main( PFXVertToPix IN ) : TORQUE_TARGET0 +{ + float4 col = float4( 0, 0, 0, 1 ); + + // Get the depth at this pixel. + float depth = TORQUE_DEFERRED_UNCONDITION( deferredTex, IN.uv0 ).w; + + // If the depth is equal to 1.0, read from the backbuffer + // and perform the exposure calculation on the result. + if ( depth >= 0.999 ) + { + col = TORQUE_TEX2D( backBuffer, IN.uv0 ); + + //col = 1 - exp(-120000 * col); + col += dot( col.rgb, LUMINANCE_VECTOR ) + 0.0001f; + col *= brightScalar; + } + + return col; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/lightRay/lightRayP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/lightRay/lightRayP.hlsl new file mode 100644 index 000000000..032894710 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/lightRay/lightRayP.hlsl @@ -0,0 +1,89 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../postFx.hlsl" + +TORQUE_UNIFORM_SAMPLER2D(frameSampler, 0); +TORQUE_UNIFORM_SAMPLER2D(backBuffer, 1); + + +uniform float3 camForward; +uniform int numSamples; +uniform float3 lightDirection; +uniform float density; +uniform float2 screenSunPos; +uniform float2 oneOverTargetSize; +uniform float weight; +uniform float decay; +uniform float exposure; + +float4 main( PFXVertToPix IN ) : TORQUE_TARGET0 +{ + float4 texCoord = float4( IN.uv0.xy, 0, 0 ); + + // Store initial sample. + half3 color = (half3)TORQUE_TEX2D( frameSampler, texCoord.xy ).rgb; + + // Store original bb color. + float4 bbCol = TORQUE_TEX2D( backBuffer, IN.uv1 ); + + // Set up illumination decay factor. + half illuminationDecay = 1.0; + + float amount = saturate( dot( -lightDirection, camForward ) ); + + int samples = numSamples * amount; + + if ( samples <= 0 ) + return bbCol; + + // Calculate vector from pixel to light source in screen space. + half2 deltaTexCoord = (half2)( texCoord.xy - screenSunPos ); + + // Divide by number of samples and scale by control factor. + deltaTexCoord *= (half)(1.0 / samples * density); + + // Evaluate summation from Equation 3 NUM_SAMPLES iterations. + for ( int i = 0; i < samples; i++ ) + { + // Step sample location along ray. + texCoord.xy -= deltaTexCoord; + + // Retrieve sample at new location. + half3 sample = (half3)TORQUE_TEX2DLOD( frameSampler, texCoord ); + + // Apply sample attenuation scale/decay factors. + sample *= half(illuminationDecay * weight); + + // Accumulate combined color. + color += sample; + + // Update exponential decay factor. + illuminationDecay *= half(decay); + } + + //return saturate( amount ) * color * Exposure; + //return bbCol * decay; + + // Output final color with a further scale control factor. + return saturate( amount ) * float4( color * exposure, 1 ) + bbCol; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/blendWeightCalculationP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/blendWeightCalculationP.hlsl new file mode 100644 index 000000000..2c4777c36 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/blendWeightCalculationP.hlsl @@ -0,0 +1,78 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// An implementation of "Practical Morphological Anti-Aliasing" from +// GPU Pro 2 by Jorge Jimenez, Belen Masia, Jose I. Echevarria, +// Fernando Navarro, and Diego Gutierrez. +// +// http://www.iryoku.com/mlaa/ + + +uniform sampler2D edgesMap : register(S0); +uniform sampler2D edgesMapL : register(S1); +uniform sampler2D areaMap : register(S2); + +#include "./functions.hlsl" + + +float4 main(float2 texcoord : TEXCOORD0) : COLOR0 +{ + float4 areas = 0.0; + + float2 e = tex2D(edgesMap, texcoord).rg; + + [branch] + if (e.g) // Edge at north + { + // Search distances to the left and to the right: + float2 d = float2(SearchXLeft(texcoord), SearchXRight(texcoord)); + + // Now fetch the crossing edges. Instead of sampling between edgels, we + // sample at -0.25, to be able to discern what value has each edgel: + float4 coords = mad(float4(d.x, -0.25, d.y + 1.0, -0.25), + PIXEL_SIZE.xyxy, texcoord.xyxy); + float e1 = tex2Dlevel0(edgesMapL, coords.xy).r; + float e2 = tex2Dlevel0(edgesMapL, coords.zw).r; + + // Ok, we know how this pattern looks like, now it is time for getting + // the actual area: + areas.rg = Area(abs(d), e1, e2); + } + + [branch] + if (e.r) // Edge at west + { + // Search distances to the top and to the bottom: + float2 d = float2(SearchYUp(texcoord), SearchYDown(texcoord)); + + // Now fetch the crossing edges (yet again): + float4 coords = mad(float4(-0.25, d.x, -0.25, d.y + 1.0), + PIXEL_SIZE.xyxy, texcoord.xyxy); + float e1 = tex2Dlevel0(edgesMapL, coords.xy).g; + float e2 = tex2Dlevel0(edgesMapL, coords.zw).g; + + // Get the area for this direction: + areas.ba = Area(abs(d), e1, e2); + } + + return areas; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/edgeDetectionP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/edgeDetectionP.hlsl new file mode 100644 index 000000000..7d5c7f057 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/edgeDetectionP.hlsl @@ -0,0 +1,72 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// An implementation of "Practical Morphological Anti-Aliasing" from +// GPU Pro 2 by Jorge Jimenez, Belen Masia, Jose I. Echevarria, +// Fernando Navarro, and Diego Gutierrez. +// +// http://www.iryoku.com/mlaa/ + +#include "shadergen:/autogenConditioners.h" + +uniform sampler2D colorMapG : register(S0); +uniform sampler2D deferredMap : register(S1); + +uniform float3 lumaCoefficients; +uniform float threshold; +uniform float depthThreshold; + + +float4 main( float2 texcoord : TEXCOORD0, + float4 offset[2]: TEXCOORD1) : COLOR0 +{ + // Luma calculation requires gamma-corrected colors (texture 'colorMapG'). + // + // Note that there is a lot of overlapped luma calculations; performance + // can be improved if this luma calculation is performed in the main pass, + // which may give you an edge if used in conjunction with a z deferred. + + float L = dot(tex2D(colorMapG, texcoord).rgb, lumaCoefficients); + + float Lleft = dot(tex2D(colorMapG, offset[0].xy).rgb, lumaCoefficients); + float Ltop = dot(tex2D(colorMapG, offset[0].zw).rgb, lumaCoefficients); + float Lright = dot(tex2D(colorMapG, offset[1].xy).rgb, lumaCoefficients); + float Lbottom = dot(tex2D(colorMapG, offset[1].zw).rgb, lumaCoefficients); + + float4 delta = abs(L.xxxx - float4(Lleft, Ltop, Lright, Lbottom)); + float4 edges = step(threshold, delta); + + // Add depth edges to color edges + float D = deferredUncondition(deferredMap, texcoord).w; + float Dleft = deferredUncondition(deferredMap, offset[0].xy).w; + float Dtop = deferredUncondition(deferredMap, offset[0].zw).w; + float Dright = deferredUncondition(deferredMap, offset[1].xy).w; + float Dbottom = deferredUncondition(deferredMap, offset[1].zw).w; + + delta = abs(D.xxxx - float4(Dleft, Dtop, Dright, Dbottom)); + edges += step(depthThreshold, delta); + + if (dot(edges, 1.0) == 0.0) + discard; + + return edges; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/functions.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/functions.hlsl new file mode 100644 index 000000000..9935a5e30 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/functions.hlsl @@ -0,0 +1,145 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// An implementation of "Practical Morphological Anti-Aliasing" from +// GPU Pro 2 by Jorge Jimenez, Belen Masia, Jose I. Echevarria, +// Fernando Navarro, and Diego Gutierrez. +// +// http://www.iryoku.com/mlaa/ + + +uniform float2 texSize0; + +#if !defined(PIXEL_SIZE) +#define PIXEL_SIZE (1.0 / texSize0) +#define MAX_SEARCH_STEPS 8 +#define MAX_DISTANCE 33 +#endif + +// Typical Multiply-Add operation to ease translation to assembly code. + +float4 mad(float4 m, float4 a, float4 b) +{ + #if defined(XBOX) + float4 result; + asm { + mad result, m, a, b + }; + return result; + #else + return m * a + b; + #endif +} + + +// This one just returns the first level of a mip map chain, which allow us to +// avoid the nasty ddx/ddy warnings, even improving the performance a little +// bit. +float4 tex2Dlevel0(sampler2D map, float2 texcoord) +{ + return tex2Dlod(map, float4(texcoord, 0.0, 0.0)); +} + + +// Same as above, this eases translation to assembly code; +float4 tex2Doffset(sampler2D map, float2 texcoord, float2 offset) +{ + #if defined(XBOX) && MAX_SEARCH_STEPS < 6 + float4 result; + float x = offset.x; + float y = offset.y; + asm { + tfetch2D result, texcoord, map, OffsetX = x, OffsetY = y + }; + return result; + #else + return tex2Dlevel0(map, texcoord + PIXEL_SIZE * offset); + #endif +} + + +// Ok, we have the distance and both crossing edges, can you please return +// the float2 blending weights? +float2 Area(float2 distance, float e1, float e2) +{ + // * By dividing by areaSize - 1.0 below we are implicitely offsetting to + // always fall inside of a pixel + // * Rounding prevents bilinear access precision problems + float areaSize = MAX_DISTANCE * 5.0; + float2 pixcoord = MAX_DISTANCE * round(4.0 * float2(e1, e2)) + distance; + float2 texcoord = pixcoord / (areaSize - 1.0); + return tex2Dlevel0(areaMap, texcoord).rg; +} + + +// Search functions for the 2nd pass. +float SearchXLeft(float2 texcoord) +{ + // We compare with 0.9 to prevent bilinear access precision problems. + float i; + float e = 0.0; + for (i = -1.5; i > -2.0 * MAX_SEARCH_STEPS; i -= 2.0) + { + e = tex2Doffset(edgesMapL, texcoord, float2(i, 0.0)).g; + [flatten] if (e < 0.9) break; + } + return max(i + 1.5 - 2.0 * e, -2.0 * MAX_SEARCH_STEPS); +} + +// Search functions for the 2nd pass. +float SearchXRight(float2 texcoord) +{ + float i; + float e = 0.0; + for (i = 1.5; i < 2.0 * MAX_SEARCH_STEPS; i += 2.0) + { + e = tex2Doffset(edgesMapL, texcoord, float2(i, 0.0)).g; + [flatten] if (e < 0.9) break; + } + return min(i - 1.5 + 2.0 * e, 2.0 * MAX_SEARCH_STEPS); +} + +// Search functions for the 2nd pass. +float SearchYUp(float2 texcoord) +{ + float i; + float e = 0.0; + for (i = -1.5; i > -2.0 * MAX_SEARCH_STEPS; i -= 2.0) + { + e = tex2Doffset(edgesMapL, texcoord, float2(i, 0.0).yx).r; + [flatten] if (e < 0.9) break; + } + return max(i + 1.5 - 2.0 * e, -2.0 * MAX_SEARCH_STEPS); +} + +// Search functions for the 2nd pass. +float SearchYDown(float2 texcoord) +{ + float i; + float e = 0.0; + for (i = 1.5; i < 2.0 * MAX_SEARCH_STEPS; i += 2.0) + { + e = tex2Doffset(edgesMapL, texcoord, float2(i, 0.0).yx).r; + [flatten] if (e < 0.9) break; + } + return min(i - 1.5 + 2.0 * e, 2.0 * MAX_SEARCH_STEPS); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/gl/blendWeightCalculationP.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/gl/blendWeightCalculationP.glsl new file mode 100644 index 000000000..af01ce6f9 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/gl/blendWeightCalculationP.glsl @@ -0,0 +1,83 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// An implementation of "Practical Morphological Anti-Aliasing" from +// GPU Pro 2 by Jorge Jimenez, Belen Masia, Jose I. Echevarria, +// Fernando Navarro, and Diego Gutierrez. +// +// http://www.iryoku.com/mlaa/ + +#include "../../../gl/hlslCompat.glsl" + +in vec2 texcoord; + +uniform sampler2D edgesMap; +uniform sampler2D edgesMapL; +uniform sampler2D areaMap; + +out vec4 OUT_col; + +#include "./functions.glsl" + + +void main() +{ + vec4 areas = vec4(0.0); + + vec2 e = texture(edgesMap, texcoord).rg; + + //[branch] + if (bool(e.g)) // Edge at north + { + // Search distances to the left and to the right: + vec2 d = vec2(SearchXLeft(texcoord), SearchXRight(texcoord)); + + // Now fetch the crossing edges. Instead of sampling between edgels, we + // sample at -0.25, to be able to discern what value has each edgel: + vec4 coords = mad(vec4(d.x, -0.25, d.y + 1.0, -0.25), + PIXEL_SIZE.xyxy, texcoord.xyxy); + float e1 = tex2Dlevel0(edgesMapL, coords.xy).r; + float e2 = tex2Dlevel0(edgesMapL, coords.zw).r; + + // Ok, we know how this pattern looks like, now it is time for getting + // the actual area: + areas.rg = Area(abs(d), e1, e2); + } + + //[branch] + if (bool(e.r)) // Edge at west + { + // Search distances to the top and to the bottom: + vec2 d = vec2(SearchYUp(texcoord), SearchYDown(texcoord)); + + // Now fetch the crossing edges (yet again): + vec4 coords = mad(vec4(-0.25, d.x, -0.25, d.y + 1.0), + PIXEL_SIZE.xyxy, texcoord.xyxy); + float e1 = tex2Dlevel0(edgesMapL, coords.xy).g; + float e2 = tex2Dlevel0(edgesMapL, coords.zw).g; + + // Get the area for this direction: + areas.ba = Area(abs(d), e1, e2); + } + + OUT_col = areas; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/gl/edgeDetectionP.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/gl/edgeDetectionP.glsl new file mode 100644 index 000000000..d964a28a4 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/gl/edgeDetectionP.glsl @@ -0,0 +1,76 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// An implementation of "Practical Morphological Anti-Aliasing" from +// GPU Pro 2 by Jorge Jimenez, Belen Masia, Jose I. Echevarria, +// Fernando Navarro, and Diego Gutierrez. +// +// http://www.iryoku.com/mlaa/ + +#include "../../../gl/hlslCompat.glsl" +#include "shadergen:/autogenConditioners.h" + +uniform sampler2D colorMapG; +uniform sampler2D deferredMap; + +uniform vec3 lumaCoefficients; +uniform float threshold; +uniform float depthThreshold; + +in vec2 texcoord; +in vec4 offset[2]; + +out vec4 OUT_col; + +void main() +{ + // Luma calculation requires gamma-corrected colors (texture 'colorMapG'). + // + // Note that there is a lot of overlapped luma calculations; performance + // can be improved if this luma calculation is performed in the main pass, + // which may give you an edge if used in conjunction with a z deferred. + + float L = dot(texture(colorMapG, texcoord).rgb, lumaCoefficients); + + float Lleft = dot(texture(colorMapG, offset[0].xy).rgb, lumaCoefficients); + float Ltop = dot(texture(colorMapG, offset[0].zw).rgb, lumaCoefficients); + float Lright = dot(texture(colorMapG, offset[1].xy).rgb, lumaCoefficients); + float Lbottom = dot(texture(colorMapG, offset[1].zw).rgb, lumaCoefficients); + + vec4 delta = abs(vec4(L) - vec4(Lleft, Ltop, Lright, Lbottom)); + vec4 edges = step(threshold, delta); + + // Add depth edges to color edges + float D = deferredUncondition(deferredMap, texcoord).w; + float Dleft = deferredUncondition(deferredMap, offset[0].xy).w; + float Dtop = deferredUncondition(deferredMap, offset[0].zw).w; + float Dright = deferredUncondition(deferredMap, offset[1].xy).w; + float Dbottom = deferredUncondition(deferredMap, offset[1].zw).w; + + delta = abs(vec4(D) - vec4(Dleft, Dtop, Dright, Dbottom)); + edges += step(depthThreshold, delta); + + if (dot(edges, vec4(1.0)) == 0.0) + discard; + + OUT_col = edges; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/gl/functions.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/gl/functions.glsl new file mode 100644 index 000000000..3ff56fb1a --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/gl/functions.glsl @@ -0,0 +1,145 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// An implementation of "Practical Morphological Anti-Aliasing" from +// GPU Pro 2 by Jorge Jimenez, Belen Masia, Jose I. Echevarria, +// Fernando Navarro, and Diego Gutierrez. +// +// http://www.iryoku.com/mlaa/ + + +uniform vec2 texSize0; + +#if !defined(PIXEL_SIZE) +#define PIXEL_SIZE (1.0 / texSize0) +#define MAX_SEARCH_STEPS 8 +#define MAX_DISTANCE 33 +#endif + +// Typical Multiply-Add operation to ease translation to assembly code. + +vec4 mad(vec4 m, vec4 a, vec4 b) +{ + #if defined(XBOX) + vec4 result; + asm { + mad result, m, a, b + }; + return result; + #else + return m * a + b; + #endif +} + + +// This one just returns the first level of a mip map chain, which allow us to +// avoid the nasty ddx/ddy warnings, even improving the performance a little +// bit. +vec4 tex2Dlevel0(sampler2D map, vec2 texcoord) +{ + return tex2Dlod(map, vec4(texcoord, 0.0, 0.0)); +} + + +// Same as above, this eases translation to assembly code; +vec4 tex2Doffset(sampler2D map, vec2 texcoord, vec2 offset) +{ + #if defined(XBOX) && MAX_SEARCH_STEPS < 6 + vec4 result; + float x = offset.x; + float y = offset.y; + asm { + tfetch2D result, texcoord, map, OffsetX = x, OffsetY = y + }; + return result; + #else + return tex2Dlevel0(map, texcoord + PIXEL_SIZE * offset); + #endif +} + + +// Ok, we have the distance and both crossing edges, can you please return +// the vec2 blending weights? +vec2 Area(vec2 distance, float e1, float e2) +{ + // * By dividing by areaSize - 1.0 below we are implicitely offsetting to + // always fall inside of a pixel + // * Rounding prevents bilinear access precision problems + float areaSize = MAX_DISTANCE * 5.0; + vec2 pixcoord = MAX_DISTANCE * round(4.0 * vec2(e1, e2)) + distance; + vec2 texcoord = pixcoord / (areaSize - 1.0); + return tex2Dlevel0(areaMap, texcoord).rg; +} + + +// Search functions for the 2nd pass. +float SearchXLeft(vec2 texcoord) +{ + // We compare with 0.9 to prevent bilinear access precision problems. + float i; + float e = 0.0; + for (i = -1.5; i > -2.0 * MAX_SEARCH_STEPS; i -= 2.0) + { + e = tex2Doffset(edgesMapL, texcoord, vec2(i, 0.0)).g; + /*[flatten]*/ if (e < 0.9) break; + } + return max(i + 1.5 - 2.0 * e, -2.0 * MAX_SEARCH_STEPS); +} + +// Search functions for the 2nd pass. +float SearchXRight(vec2 texcoord) +{ + float i; + float e = 0.0; + for (i = 1.5; i < 2.0 * MAX_SEARCH_STEPS; i += 2.0) + { + e = tex2Doffset(edgesMapL, texcoord, vec2(i, 0.0)).g; + /*[flatten]*/ if (e < 0.9) break; + } + return min(i - 1.5 + 2.0 * e, 2.0 * MAX_SEARCH_STEPS); +} + +// Search functions for the 2nd pass. +float SearchYUp(vec2 texcoord) +{ + float i; + float e = 0.0; + for (i = -1.5; i > -2.0 * MAX_SEARCH_STEPS; i -= 2.0) + { + e = tex2Doffset(edgesMapL, texcoord, vec2(i, 0.0).yx).r; + /*[flatten]*/ if (e < 0.9) break; + } + return max(i + 1.5 - 2.0 * e, -2.0 * MAX_SEARCH_STEPS); +} + +// Search functions for the 2nd pass. +float SearchYDown(vec2 texcoord) +{ + float i; + float e = 0.0; + for (i = 1.5; i < 2.0 * MAX_SEARCH_STEPS; i += 2.0) + { + e = tex2Doffset(edgesMapL, texcoord, vec2(i, 0.0).yx).r; + /*[flatten]*/ if (e < 0.9) break; + } + return min(i - 1.5 + 2.0 * e, 2.0 * MAX_SEARCH_STEPS); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/gl/neighborhoodBlendingP.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/gl/neighborhoodBlendingP.glsl new file mode 100644 index 000000000..eddbcc47c --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/gl/neighborhoodBlendingP.glsl @@ -0,0 +1,88 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// An implementation of "Practical Morphological Anti-Aliasing" from +// GPU Pro 2 by Jorge Jimenez, Belen Masia, Jose I. Echevarria, +// Fernando Navarro, and Diego Gutierrez. +// +// http://www.iryoku.com/mlaa/ + +#include "../../../gl/hlslCompat.glsl" + +in vec2 texcoord; +in vec4 offset[2]; + +uniform sampler2D blendMap; +uniform sampler2D colorMapL; +uniform sampler2D colorMap; + +// Dummy sampers to please include. +uniform sampler2D areaMap; +uniform sampler2D edgesMapL; +#include "./functions.glsl" + +out vec4 OUT_col; + +void main() +{ + // Fetch the blending weights for current pixel: + vec4 topLeft = texture(blendMap, texcoord); + float bottom = texture(blendMap, offset[1].zw).g; + float right = texture(blendMap, offset[1].xy).a; + vec4 a = vec4(topLeft.r, bottom, topLeft.b, right); + + // Up to 4 lines can be crossing a pixel (one in each edge). So, we perform + // a weighted average, where the weight of each line is 'a' cubed, which + // favors blending and works well in practice. + vec4 w = a * a * a; + + // There is some blending weight with a value greater than 0.0? + float sum = dot(w, vec4(1.0)); + if (sum < 1e-5) + discard; + + vec4 color = vec4(0.0); + + // Add the contributions of the possible 4 lines that can cross this pixel: + #ifdef BILINEAR_FILTER_TRICK + vec4 coords = mad(vec4( 0.0, -a.r, 0.0, a.g), PIXEL_SIZE.yyyy, texcoord.xyxy); + color = mad(texture(colorMapL, coords.xy), vec4(w.r), color); + color = mad(texture(colorMapL, coords.zw), vec4(w.g), color); + + coords = mad(vec4(-a.b, 0.0, a.a, 0.0), PIXEL_SIZE.xxxx, texcoord.xyxy); + color = mad(texture(colorMapL, coords.xy), vec4(w.b), color); + color = mad(texture(colorMapL, coords.zw), vec4(w.a), color); + #else + vec4 C = texture(colorMap, texcoord); + vec4 Cleft = texture(colorMap, offset[0].xy); + vec4 Ctop = texture(colorMap, offset[0].zw); + vec4 Cright = texture(colorMap, offset[1].xy); + vec4 Cbottom = texture(colorMap, offset[1].zw); + color = mad(mix(C, Ctop, a.r), vec4(w.r), color); + color = mad(mix(C, Cbottom, a.g), vec4(w.g), color); + color = mad(mix(C, Cleft, a.b), vec4(w.b), color); + color = mad(mix(C, Cright, a.a), vec4(w.a), color); + #endif + + // Normalize the resulting color and we are finished! + OUT_col = color / sum; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/gl/offsetV.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/gl/offsetV.glsl new file mode 100644 index 000000000..53d927c29 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/gl/offsetV.glsl @@ -0,0 +1,57 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// An implementation of "Practical Morphological Anti-Aliasing" from +// GPU Pro 2 by Jorge Jimenez, Belen Masia, Jose I. Echevarria, +// Fernando Navarro, and Diego Gutierrez. +// +// http://www.iryoku.com/mlaa/ + +#include "../../../gl/hlslCompat.glsl" + +in vec4 vPosition; +in vec2 vTexCoord0; + +#define IN_position vPosition +#define IN_texcoord vTexCoord0 + +#define OUT_position gl_Position +out vec2 texcoord; +#define OUT_texcoord texcoord +out vec4 offset[2]; +#define OUT_offset offset + +uniform vec2 texSize0; + +void main() +{ + OUT_position = IN_position; + vec2 PIXEL_SIZE = 1.0 / texSize0; + + OUT_texcoord = IN_texcoord; + OUT_texcoord.xy += PIXEL_SIZE * 0.5; + + OUT_offset[0] = OUT_texcoord.xyxy + PIXEL_SIZE.xyxy * vec4(-1.0, 0.0, 0.0, -1.0); + OUT_offset[1] = OUT_texcoord.xyxy + PIXEL_SIZE.xyxy * vec4( 1.0, 0.0, 0.0, 1.0); + + correctSSP(gl_Position); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/gl/passthruV.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/gl/passthruV.glsl new file mode 100644 index 000000000..1aa64112c --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/gl/passthruV.glsl @@ -0,0 +1,52 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// An implementation of "Practical Morphological Anti-Aliasing" from +// GPU Pro 2 by Jorge Jimenez, Belen Masia, Jose I. Echevarria, +// Fernando Navarro, and Diego Gutierrez. +// +// http://www.iryoku.com/mlaa/ + +#include "../../../gl/hlslCompat.glsl" + +in vec4 vPosition; +in vec2 vTexCoord0; + +#define IN_position vPosition +#define IN_texcoord vTexCoord0 + +#define OUT_position gl_Position +out vec2 texcoord; +#define OUT_texcoord texcoord + +uniform vec2 texSize0; + +void main() +{ + OUT_position = IN_position; + vec2 PIXEL_SIZE = 1.0 / texSize0; + + OUT_texcoord = IN_texcoord; + texcoord.xy += PIXEL_SIZE * 0.5; + + correctSSP(gl_Position); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/neighborhoodBlendingP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/neighborhoodBlendingP.hlsl new file mode 100644 index 000000000..aaaacafe2 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/neighborhoodBlendingP.hlsl @@ -0,0 +1,84 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// An implementation of "Practical Morphological Anti-Aliasing" from +// GPU Pro 2 by Jorge Jimenez, Belen Masia, Jose I. Echevarria, +// Fernando Navarro, and Diego Gutierrez. +// +// http://www.iryoku.com/mlaa/ + + +uniform sampler2D blendMap : register(S0); +uniform sampler2D colorMapL : register(S1); +uniform sampler2D colorMap : register(S2); + +// Dummy sampers to please include. +sampler2D areaMap; +sampler2D edgesMapL; +#include "./functions.hlsl" + + +float4 main( float2 texcoord : TEXCOORD0, + float4 offset[2]: TEXCOORD1 ) : COLOR0 +{ + // Fetch the blending weights for current pixel: + float4 topLeft = tex2D(blendMap, texcoord); + float bottom = tex2D(blendMap, offset[1].zw).g; + float right = tex2D(blendMap, offset[1].xy).a; + float4 a = float4(topLeft.r, bottom, topLeft.b, right); + + // Up to 4 lines can be crossing a pixel (one in each edge). So, we perform + // a weighted average, where the weight of each line is 'a' cubed, which + // favors blending and works well in practice. + float4 w = a * a * a; + + // There is some blending weight with a value greater than 0.0? + float sum = dot(w, 1.0); + if (sum < 1e-5) + discard; + + float4 color = 0.0; + + // Add the contributions of the possible 4 lines that can cross this pixel: + #ifdef BILINEAR_FILTER_TRICK + float4 coords = mad(float4( 0.0, -a.r, 0.0, a.g), PIXEL_SIZE.yyyy, texcoord.xyxy); + color = mad(tex2D(colorMapL, coords.xy), w.r, color); + color = mad(tex2D(colorMapL, coords.zw), w.g, color); + + coords = mad(float4(-a.b, 0.0, a.a, 0.0), PIXEL_SIZE.xxxx, texcoord.xyxy); + color = mad(tex2D(colorMapL, coords.xy), w.b, color); + color = mad(tex2D(colorMapL, coords.zw), w.a, color); + #else + float4 C = tex2D(colorMap, texcoord); + float4 Cleft = tex2D(colorMap, offset[0].xy); + float4 Ctop = tex2D(colorMap, offset[0].zw); + float4 Cright = tex2D(colorMap, offset[1].xy); + float4 Cbottom = tex2D(colorMap, offset[1].zw); + color = mad(lerp(C, Ctop, a.r), w.r, color); + color = mad(lerp(C, Cbottom, a.g), w.g, color); + color = mad(lerp(C, Cleft, a.b), w.b, color); + color = mad(lerp(C, Cright, a.a), w.a, color); + #endif + + // Normalize the resulting color and we are finished! + return color / sum; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/offsetV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/offsetV.hlsl new file mode 100644 index 000000000..d9c922afd --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/offsetV.hlsl @@ -0,0 +1,42 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// An implementation of "Practical Morphological Anti-Aliasing" from +// GPU Pro 2 by Jorge Jimenez, Belen Masia, Jose I. Echevarria, +// Fernando Navarro, and Diego Gutierrez. +// +// http://www.iryoku.com/mlaa/ + + +uniform float2 texSize0; + +void main( inout float4 position : POSITION0, + inout float2 texcoord : TEXCOORD0, + out float4 offset[2] : TEXCOORD1 ) +{ + float2 PIXEL_SIZE = 1.0 / texSize0; + + texcoord.xy += PIXEL_SIZE * 0.5; + + offset[0] = texcoord.xyxy + PIXEL_SIZE.xyxy * float4(-1.0, 0.0, 0.0, -1.0); + offset[1] = texcoord.xyxy + PIXEL_SIZE.xyxy * float4( 1.0, 0.0, 0.0, 1.0); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/passthruV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/passthruV.hlsl new file mode 100644 index 000000000..24ef534fd --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/mlaa/passthruV.hlsl @@ -0,0 +1,37 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// An implementation of "Practical Morphological Anti-Aliasing" from +// GPU Pro 2 by Jorge Jimenez, Belen Masia, Jose I. Echevarria, +// Fernando Navarro, and Diego Gutierrez. +// +// http://www.iryoku.com/mlaa/ + + +uniform float2 texSize0; + +void main( inout float4 position : POSITION0, + inout float2 texcoord : TEXCOORD0) +{ + float2 PIXEL_SIZE = 1.0 / texSize0; + texcoord.xy += PIXEL_SIZE * 0.5; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/motionBlurP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/motionBlurP.hlsl new file mode 100644 index 000000000..90b8f6f25 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/motionBlurP.hlsl @@ -0,0 +1,70 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "./postFx.hlsl" +#include "../torque.hlsl" +#include "../shaderModelAutoGen.hlsl" + +uniform float4x4 matPrevScreenToWorld; +uniform float4x4 matWorldToScreen; + +// Passed in from setShaderConsts() +uniform float velocityMultiplier; +TORQUE_UNIFORM_SAMPLER2D(backBuffer, 0); +TORQUE_UNIFORM_SAMPLER2D(deferredTex, 1); + +float4 main(PFXVertToPix IN) : TORQUE_TARGET0 +{ + float samples = 5; + + // First get the deferred texture for uv channel 0 + float4 deferred = TORQUE_DEFERRED_UNCONDITION( deferredTex, IN.uv0 ); + + // Next extract the depth + float depth = deferred.a; + + // Create the screen position + float4 screenPos = float4(IN.uv0.x*2-1, IN.uv0.y*2-1, depth*2-1, 1); + + // Calculate the world position + float4 D = mul(screenPos, matWorldToScreen); + float4 worldPos = D / D.w; + + // Now calculate the previous screen position + float4 previousPos = mul( worldPos, matPrevScreenToWorld ); + previousPos /= previousPos.w; + + // Calculate the XY velocity + float2 velocity = ((screenPos - previousPos) / velocityMultiplier).xy; + + // Generate the motion blur + float4 color = TORQUE_TEX2D(backBuffer, IN.uv0); + IN.uv0 += velocity; + + for(int i = 1; i blurNormalTol ) + { + usedCount++; + total += weight; + occlusion += TORQUE_TEX2D( occludeMap, uv ).r * weight; + } + } +} + +float4 main( VertToPix IN ) : TORQUE_TARGET0 +{ + //float4 centerTap; + float4 centerTap = TORQUE_DEFERRED_UNCONDITION( deferredMap, IN.uv0.zw ); + + //return centerTap; + + //float centerOcclude = TORQUE_TEX2D( occludeMap, IN.uv0.zw ).r; + //return float4( centerOcclude.rrr, 1 ); + + float4 kernel = float4( 0.175, 0.275, 0.375, 0.475 ); //25f; + + float occlusion = 0; + int usedCount = 0; + float total = 0.0; + + sample( IN.uv0.xy, kernel.x, centerTap, usedCount, occlusion, total ); + sample( IN.uv1, kernel.y, centerTap, usedCount, occlusion, total ); + sample( IN.uv2, kernel.z, centerTap, usedCount, occlusion, total ); + sample( IN.uv3, kernel.w, centerTap, usedCount, occlusion, total ); + + sample( IN.uv4, kernel.x, centerTap, usedCount, occlusion, total ); + sample( IN.uv5, kernel.y, centerTap, usedCount, occlusion, total ); + sample( IN.uv6, kernel.z, centerTap, usedCount, occlusion, total ); + sample( IN.uv7, kernel.w, centerTap, usedCount, occlusion, total ); + + occlusion += TORQUE_TEX2D( occludeMap, IN.uv0.zw ).r * 0.5; + total += 0.5; + //occlusion /= 3.0; + + //occlusion /= (float)usedCount / 8.0; + occlusion /= total; + + return float4( occlusion.rrr, 1 ); + + + //return float4( 0,0,0,occlusion ); + + //float3 color = TORQUE_TEX2D( colorMap, IN.uv0.zw ); + + //return float4( color, occlusion ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/ssao/SSAO_Blur_V.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/ssao/SSAO_Blur_V.hlsl new file mode 100644 index 000000000..6ab278900 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/ssao/SSAO_Blur_V.hlsl @@ -0,0 +1,86 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "./../postFx.hlsl" +#include "./../../torque.hlsl" + + +uniform float2 texSize0; +uniform float2 oneOverTargetSize; +uniform float4 rtParams0; + +struct VertToPix +{ + float4 hpos : TORQUE_POSITION; + + float4 uv0 : TEXCOORD0; + float2 uv1 : TEXCOORD1; + float2 uv2 : TEXCOORD2; + float2 uv3 : TEXCOORD3; + + float2 uv4 : TEXCOORD4; + float2 uv5 : TEXCOORD5; + float2 uv6 : TEXCOORD6; + float2 uv7 : TEXCOORD7; +}; + +VertToPix main( PFXVert IN ) +{ + VertToPix OUT; + + OUT.hpos = float4(IN.pos,1.0); + + IN.uv = viewportCoordToRenderTarget( IN.uv, rtParams0 ); + + //float4 step = float4( 3.5, 2.5, 1.5, 0.5 ); + //float4 step = float4( 4.0, 3.0, 2.0, 1.0 ); + float4 step = float4( 9.0, 5.0, 2.5, 0.5 ); + + // I don't know why this offset is necessary, but it is. + //IN.uv = IN.uv * oneOverTargetSize; + + OUT.uv0.xy = IN.uv + ( ( BLUR_DIR * step.x ) / texSize0 ); + OUT.uv1 = IN.uv + ( ( BLUR_DIR * step.y ) / texSize0 ); + OUT.uv2 = IN.uv + ( ( BLUR_DIR * step.z ) / texSize0 ); + OUT.uv3 = IN.uv + ( ( BLUR_DIR * step.w ) / texSize0 ); + + OUT.uv4 = IN.uv - ( ( BLUR_DIR * step.x ) / texSize0 ); + OUT.uv5 = IN.uv - ( ( BLUR_DIR * step.y ) / texSize0 ); + OUT.uv6 = IN.uv - ( ( BLUR_DIR * step.z ) / texSize0 ); + OUT.uv7 = IN.uv - ( ( BLUR_DIR * step.w ) / texSize0 ); + + OUT.uv0.zw = IN.uv; + + /* + OUT.uv0 = viewportCoordToRenderTarget( OUT.uv0, rtParams0 ); + OUT.uv1 = viewportCoordToRenderTarget( OUT.uv1, rtParams0 ); + OUT.uv2 = viewportCoordToRenderTarget( OUT.uv2, rtParams0 ); + OUT.uv3 = viewportCoordToRenderTarget( OUT.uv3, rtParams0 ); + + OUT.uv4 = viewportCoordToRenderTarget( OUT.uv4, rtParams0 ); + OUT.uv5 = viewportCoordToRenderTarget( OUT.uv5, rtParams0 ); + OUT.uv6 = viewportCoordToRenderTarget( OUT.uv6, rtParams0 ); + OUT.uv7 = viewportCoordToRenderTarget( OUT.uv7, rtParams0 ); + */ + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/ssao/SSAO_P.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/ssao/SSAO_P.hlsl new file mode 100644 index 000000000..ff31a4b8b --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/ssao/SSAO_P.hlsl @@ -0,0 +1,272 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../shaderModelAutoGen.hlsl" +#include "./../postFx.hlsl" + +#define DOSMALL +#define DOLARGE + +TORQUE_UNIFORM_SAMPLER2D(deferredMap,0); +TORQUE_UNIFORM_SAMPLER2D(randNormalTex,1); +TORQUE_UNIFORM_SAMPLER1D(powTable,2); + +uniform float2 nearFar; +uniform float2 worldToScreenScale; +uniform float2 texSize0; +uniform float2 texSize1; +uniform float2 targetSize; + +// Script-set constants. + +uniform float overallStrength; + +uniform float sRadius; +uniform float sStrength; +uniform float sDepthMin; +uniform float sDepthMax; +uniform float sDepthPow; +uniform float sNormalTol; +uniform float sNormalPow; + +uniform float lRadius; +uniform float lStrength; +uniform float lDepthMin; +uniform float lDepthMax; +uniform float lDepthPow; +uniform float lNormalTol; +uniform float lNormalPow; + + +#ifndef QUALITY + #define QUALITY 2 +#endif + + +#if QUALITY == 0 + #define sSampleCount 4 + #define totalSampleCount 12 +#elif QUALITY == 1 + #define sSampleCount 6 + #define totalSampleCount 24 +#elif QUALITY == 2 + #define sSampleCount 8 + #define totalSampleCount 32 +#endif + + +float getOcclusion( float depthDiff, float depthMin, float depthMax, float depthPow, + float normalDiff, float dt, float normalTol, float normalPow ) +{ + if ( depthDiff < 0.0 ) + return 0.0; + + float delta = abs( depthDiff ); + + if ( delta < depthMin || delta > depthMax ) + return 0.0; + + delta = saturate( delta / depthMax ); + + if ( dt > 0.0 ) + normalDiff *= dt; + else + normalDiff = 1.0; + + + normalDiff *= 1.0 - ( dt * 0.5 + 0.5 ); + + return ( 1.0 - TORQUE_TEX1D( powTable, delta ).r ) * normalDiff; +} + + +float4 main( PFXVertToPix IN ) : TORQUE_TARGET0 +{ + float3 ptSphere[32] = + { + float3( 0.295184, 0.077723, 0.068429 ), + float3( -0.271976, -0.365221, -0.838363 ), + float3( 0.547713, 0.467576, 0.488515 ), + float3( 0.662808, -0.031733, -0.584758 ), + float3( -0.025717, 0.218955, -0.657094 ), + float3( -0.310153, -0.365223, -0.370701 ), + float3( -0.101407, -0.006313, -0.747665 ), + float3( -0.769138, 0.360399, -0.086847 ), + float3( -0.271988, -0.275140, -0.905353 ), + float3( 0.096740, -0.566901, 0.700151 ), + float3( 0.562872, -0.735136, -0.094647 ), + float3( 0.379877, 0.359278, 0.190061 ), + float3( 0.519064, -0.023055, 0.405068 ), + float3( -0.301036, 0.114696, -0.088885 ), + float3( -0.282922, 0.598305, 0.487214 ), + float3( -0.181859, 0.251670, -0.679702 ), + float3( -0.191463, -0.635818, -0.512919 ), + float3( -0.293655, 0.427423, 0.078921 ), + float3( -0.267983, 0.680534, -0.132880 ), + float3( 0.139611, 0.319637, 0.477439 ), + float3( -0.352086, 0.311040, 0.653913 ), + float3( 0.321032, 0.805279, 0.487345 ), + float3( 0.073516, 0.820734, -0.414183 ), + float3( -0.155324, 0.589983, -0.411460 ), + float3( 0.335976, 0.170782, -0.527627 ), + float3( 0.463460, -0.355658, -0.167689 ), + float3( 0.222654, 0.596550, -0.769406 ), + float3( 0.922138, -0.042070, 0.147555 ), + float3( -0.727050, -0.329192, 0.369826 ), + float3( -0.090731, 0.533820, 0.463767 ), + float3( -0.323457, -0.876559, -0.238524 ), + float3( -0.663277, -0.372384, -0.342856 ) + }; + + // Sample a random normal for reflecting the + // sphere vector later in our loop. + float4 noiseMapUV = float4( ( IN.uv1 * ( targetSize / texSize1 ) ).xy, 0, 0 ); + float3 reflectNormal = normalize( TORQUE_TEX2DLOD( randNormalTex, noiseMapUV ).xyz * 2.0 - 1.0 ); + //return float4( reflectNormal, 1 ); + + float4 deferred = TORQUE_DEFERRED_UNCONDITION( deferredMap, IN.uv0 ); + float3 normal = deferred.xyz; + float depth = deferred.a; + //return float4( ( depth ).xxx, 1 ); + + // Early out if too far away. + if ( depth > 0.99999999 ) + return float4( 0,0,0,0 ); + + // current fragment coords in screen space + float3 ep = float3( IN.uv0, depth ); + + float bl; + float3 baseRay, ray, se, occNorm, projRadius; + float normalDiff = 0; + float depthMin, depthMax, dt, depthDiff; + float4 occluderFragment; + int i; + float sOcclusion = 0.0; + float lOcclusion = 0.0; + + //------------------------------------------------------------ + // Small radius + //------------------------------------------------------------ + +#ifdef DOSMALL + + bl = 0.0; + + projRadius.xy = ( float2( sRadius.rr ) / ( depth * nearFar.y ) ) * ( worldToScreenScale / texSize0 ); + projRadius.z = sRadius / nearFar.y; + + depthMin = projRadius.z * sDepthMin; + depthMax = projRadius.z * sDepthMax; + + //float maxr = 1; + //radiusDepth = clamp( radiusDepth, 0.0001, maxr.rrr ); + //if ( radiusDepth.x < 1.0 / targetSize.x ) + // return color; + //radiusDepth.xyz = 0.0009; + [unroll] + for ( i = 0; i < sSampleCount; i++ ) + { + baseRay = reflect( ptSphere[i], reflectNormal ); + + dt = dot( baseRay.xyz, normal ); + + baseRay *= sign( dt ); + + ray = ( projRadius * baseRay.xzy ); + ray.y = -ray.y; + + se = ep + ray; + + occluderFragment = TORQUE_DEFERRED_UNCONDITION( deferredMap, se.xy ); + + depthDiff = se.z - occluderFragment.a; + + dt = dot( occluderFragment.xyz, baseRay.xyz ); + normalDiff = dot( occluderFragment.xyz, normal ); + + bl += getOcclusion( depthDiff, depthMin, depthMax, sDepthPow, normalDiff, dt, sNormalTol, sNormalPow ); + } + + sOcclusion = sStrength * ( bl / (float)sSampleCount ); + +#endif // DOSMALL + + + //------------------------------------------------------------ + // Large radius + //------------------------------------------------------------ + +#ifdef DOLARGE + + bl = 0.0; + + projRadius.xy = ( float2( lRadius.rr ) / ( depth * nearFar.y ) ) * ( worldToScreenScale / texSize0 ); + projRadius.z = lRadius / nearFar.y; + + depthMin = projRadius.z * lDepthMin; + depthMax = projRadius.z * lDepthMax; + + //projRadius.xy = clamp( projRadius.xy, 0.0, 0.01 ); + //float maxr = 1; + //radiusDepth = clamp( radiusDepth, 0.0001, maxr.rrr ); + //if ( radiusDepth.x < 1.0 / targetSize.x ) + // return color; + //radiusDepth.xyz = 0.0009; + [unroll] + for ( i = sSampleCount; i < totalSampleCount; i++ ) + { + baseRay = reflect( ptSphere[i], reflectNormal ); + + dt = dot( baseRay.xyz, normal ); + + baseRay *= sign( dt ); + + ray = ( projRadius * baseRay.xzy ); + ray.y = -ray.y; + + se = ep + ray; + + occluderFragment = TORQUE_DEFERRED_UNCONDITION( deferredMap, se.xy ); + + depthDiff = se.z - occluderFragment.a; + + normalDiff = dot( occluderFragment.xyz, normal ); + dt = dot( occluderFragment.xyz, baseRay.xyz ); + + bl += getOcclusion( depthDiff, depthMin, depthMax, lDepthPow, normalDiff, dt, lNormalTol, lNormalPow ); + } + + lOcclusion = lStrength * ( bl / (float)( totalSampleCount - sSampleCount ) ); + +#endif // DOLARGE + + float occlusion = saturate( max( sOcclusion, lOcclusion ) * overallStrength ); + + // Note black is unoccluded and white is fully occluded. This + // seems backwards, but it makes it simple to deal with the SSAO + // being disabled in the lighting shaders. + + return occlusion; +} + + diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/ssao/SSAO_PowerTable_P.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/ssao/SSAO_PowerTable_P.hlsl new file mode 100644 index 000000000..696947d3e --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/ssao/SSAO_PowerTable_P.hlsl @@ -0,0 +1,29 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "./../postFx.hlsl" + +float4 main( PFXVertToPix IN ) : TORQUE_TARGET0 +{ + float power = pow( max( IN.uv0.x, 0 ), 0.1 ); + return float4( power, 0, 0, 1 ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/ssao/SSAO_PowerTable_V.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/ssao/SSAO_PowerTable_V.hlsl new file mode 100644 index 000000000..76f67e711 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/ssao/SSAO_PowerTable_V.hlsl @@ -0,0 +1,45 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "./../postFx.hlsl" +#include "./../../torque.hlsl" + + +uniform float4 rtParams0; +uniform float4 rtParams1; +uniform float4 rtParams2; +uniform float4 rtParams3; + +PFXVertToPix main( PFXVert IN ) +{ + PFXVertToPix OUT; + + OUT.hpos = float4(IN.pos,1.0); + OUT.uv0 = IN.uv; //viewportCoordToRenderTarget( IN.uv, rtParams0 ); + OUT.uv1 = IN.uv; //viewportCoordToRenderTarget( IN.uv, rtParams1 ); + OUT.uv2 = IN.uv; //viewportCoordToRenderTarget( IN.uv, rtParams2 ); + OUT.uv3 = IN.uv; //viewportCoordToRenderTarget( IN.uv, rtParams3 ); + + OUT.wsEyeRay = IN.wsEyeRay; + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/ssao/gl/SSAO_Blur_P.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/ssao/gl/SSAO_Blur_P.glsl new file mode 100644 index 000000000..cae920af8 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/ssao/gl/SSAO_Blur_P.glsl @@ -0,0 +1,108 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" +#include "shadergen:/autogenConditioners.h" + +in vec4 uv0; +#define IN_uv0 uv0 +in vec2 uv1; +#define IN_uv1 uv1 +in vec2 uv2; +#define IN_uv2 uv2 +in vec2 uv3; +#define IN_uv3 uv3 + +in vec2 uv4; +#define IN_uv4 uv4 +in vec2 uv5; +#define IN_uv5 uv5 +in vec2 uv6; +#define IN_uv6 uv6 +in vec2 uv7; +#define IN_uv7 uv7 + +uniform sampler2D occludeMap ; +uniform sampler2D deferredMap ; +uniform float blurDepthTol; +uniform float blurNormalTol; + +out vec4 OUT_col; + +void _sample( vec2 uv, float weight, vec4 centerTap, inout int usedCount, inout float occlusion, inout float total ) +{ + //return; + vec4 tap = deferredUncondition( deferredMap, uv ); + + if ( abs( tap.a - centerTap.a ) < blurDepthTol ) + { + if ( dot( tap.xyz, centerTap.xyz ) > blurNormalTol ) + { + usedCount++; + total += weight; + occlusion += texture( occludeMap, uv ).r * weight; + } + } +} + +void main() +{ + //vec4 centerTap; + vec4 centerTap = deferredUncondition( deferredMap, IN_uv0.zw ); + + //return centerTap; + + //float centerOcclude = texture( occludeMap, IN_uv0.zw ).r; + //return vec4( centerOcclude.rrr, 1 ); + + vec4 kernel = vec4( 0.175, 0.275, 0.375, 0.475 ); //25f; + + float occlusion = 0; + int usedCount = 0; + float total = 0.0; + + _sample( IN_uv0.xy, kernel.x, centerTap, usedCount, occlusion, total ); + _sample( IN_uv1, kernel.y, centerTap, usedCount, occlusion, total ); + _sample( IN_uv2, kernel.z, centerTap, usedCount, occlusion, total ); + _sample( IN_uv3, kernel.w, centerTap, usedCount, occlusion, total ); + + _sample( IN_uv4, kernel.x, centerTap, usedCount, occlusion, total ); + _sample( IN_uv5, kernel.y, centerTap, usedCount, occlusion, total ); + _sample( IN_uv6, kernel.z, centerTap, usedCount, occlusion, total ); + _sample( IN_uv7, kernel.w, centerTap, usedCount, occlusion, total ); + + occlusion += texture( occludeMap, IN_uv0.zw ).r * 0.5; + total += 0.5; + //occlusion /= 3.0; + + //occlusion /= (float)usedCount / 8.0; + occlusion /= total; + + OUT_col = vec4( vec3(occlusion), 1 ); + + + //return vec4( 0,0,0,occlusion ); + + //vec3 color = texture( colorMap, IN_uv0.zw ); + + //return vec4( color, occlusion ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/ssao/gl/SSAO_Blur_V.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/ssao/gl/SSAO_Blur_V.glsl new file mode 100644 index 000000000..45a52e890 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/ssao/gl/SSAO_Blur_V.glsl @@ -0,0 +1,96 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + + +#include "../../../gl/torque.glsl" +#include "../../../gl/hlslCompat.glsl" + +in vec4 vPosition; +in vec2 vTexCoord0; + +#define IN_pos vPosition +#define _IN_uv vTexCoord0 + +uniform vec2 texSize0; +uniform vec4 rtParams0; +uniform vec2 oneOverTargetSize; + +#define OUT_hpos gl_Position + +out vec4 uv0; +#define OUT_uv0 uv0 +out vec2 uv1; +#define OUT_uv1 uv1 +out vec2 uv2; +#define OUT_uv2 uv2 +out vec2 uv3; +#define OUT_uv3 uv3 + +out vec2 uv4; +#define OUT_uv4 uv4 +out vec2 uv5; +#define OUT_uv5 uv5 +out vec2 uv6; +#define OUT_uv6 uv6 +out vec2 uv7; +#define OUT_uv7 uv7 + + +void main() +{ + OUT_hpos = IN_pos; + + vec2 IN_uv = viewportCoordToRenderTarget( _IN_uv, rtParams0 ); + + //vec4 step = vec4( 3.5, 2.5, 1.5, 0.5 ); + //vec4 step = vec4( 4.0, 3.0, 2.0, 1.0 ); + vec4 step = vec4( 9.0, 5.0, 2.5, 0.5 ); + + // I don't know why this offset is necessary, but it is. + //IN_uv = IN_uv * oneOverTargetSize; + + OUT_uv0.xy = IN_uv + ( ( BLUR_DIR * step.x ) / texSize0 ); + OUT_uv1 = IN_uv + ( ( BLUR_DIR * step.y ) / texSize0 ); + OUT_uv2 = IN_uv + ( ( BLUR_DIR * step.z ) / texSize0 ); + OUT_uv3 = IN_uv + ( ( BLUR_DIR * step.w ) / texSize0 ); + + OUT_uv4 = IN_uv - ( ( BLUR_DIR * step.x ) / texSize0 ); + OUT_uv5 = IN_uv - ( ( BLUR_DIR * step.y ) / texSize0 ); + OUT_uv6 = IN_uv - ( ( BLUR_DIR * step.z ) / texSize0 ); + OUT_uv7 = IN_uv - ( ( BLUR_DIR * step.w ) / texSize0 ); + + OUT_uv0.zw = IN_uv; + + /* + OUT_uv0 = viewportCoordToRenderTarget( OUT_uv0, rtParams0 ); + OUT_uv1 = viewportCoordToRenderTarget( OUT_uv1, rtParams0 ); + OUT_uv2 = viewportCoordToRenderTarget( OUT_uv2, rtParams0 ); + OUT_uv3 = viewportCoordToRenderTarget( OUT_uv3, rtParams0 ); + + OUT_uv4 = viewportCoordToRenderTarget( OUT_uv4, rtParams0 ); + OUT_uv5 = viewportCoordToRenderTarget( OUT_uv5, rtParams0 ); + OUT_uv6 = viewportCoordToRenderTarget( OUT_uv6, rtParams0 ); + OUT_uv7 = viewportCoordToRenderTarget( OUT_uv7, rtParams0 ); + */ + + correctSSP(gl_Position); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/ssao/gl/SSAO_P.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/ssao/gl/SSAO_P.glsl new file mode 100644 index 000000000..cfff88381 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/ssao/gl/SSAO_P.glsl @@ -0,0 +1,278 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" +#include "shadergen:/autogenConditioners.h" +#include "../../gl/postFX.glsl" + +#define DOSMALL +#define DOLARGE + +uniform sampler2D deferredMap ; +uniform sampler2D randNormalTex ; +uniform sampler1D powTable ; + +uniform vec2 nearFar; +uniform vec2 worldToScreenScale; +uniform vec2 texSize0; +uniform vec2 texSize1; +uniform vec2 targetSize; + +// Script-set constants. + +uniform float overallStrength; + +uniform float sRadius; +uniform float sStrength; +uniform float sDepthMin; +uniform float sDepthMax; +uniform float sDepthPow; +uniform float sNormalTol; +uniform float sNormalPow; + +uniform float lRadius; +uniform float lStrength; +uniform float lDepthMin; +uniform float lDepthMax; +uniform float lDepthPow; +uniform float lNormalTol; +uniform float lNormalPow; + +out vec4 OUT_col; + + +#ifndef QUALITY + #define QUALITY 2 +#endif + + +#if QUALITY == 0 + #define sSampleCount 4 + #define totalSampleCount 12 +#elif QUALITY == 1 + #define sSampleCount 6 + #define totalSampleCount 24 +#elif QUALITY == 2 + #define sSampleCount 8 + #define totalSampleCount 32 +#endif + + +float getOcclusion( float depthDiff, float depthMin, float depthMax, float depthPow, + float normalDiff, float dt, float normalTol, float normalPow ) +{ + if ( depthDiff < 0.0 ) + return 0.0; + + float delta = abs( depthDiff ); + + if ( delta < depthMin || delta > depthMax ) + return 0.0; + + delta = saturate( delta / depthMax ); + + if ( dt > 0.0 ) + normalDiff *= dt; + else + normalDiff = 1.0; + + + normalDiff *= 1.0 - ( dt * 0.5 + 0.5 ); + + return ( 1.0 - texture( powTable, delta ).r ) * normalDiff; +} + + +void main() +{ + const vec3 ptSphere[32] = vec3[] + ( + vec3( 0.295184, 0.077723, 0.068429 ), + vec3( -0.271976, -0.365221, -0.838363 ), + vec3( 0.547713, 0.467576, 0.488515 ), + vec3( 0.662808, -0.031733, -0.584758 ), + vec3( -0.025717, 0.218955, -0.657094 ), + vec3( -0.310153, -0.365223, -0.370701 ), + vec3( -0.101407, -0.006313, -0.747665 ), + vec3( -0.769138, 0.360399, -0.086847 ), + vec3( -0.271988, -0.275140, -0.905353 ), + vec3( 0.096740, -0.566901, 0.700151 ), + vec3( 0.562872, -0.735136, -0.094647 ), + vec3( 0.379877, 0.359278, 0.190061 ), + vec3( 0.519064, -0.023055, 0.405068 ), + vec3( -0.301036, 0.114696, -0.088885 ), + vec3( -0.282922, 0.598305, 0.487214 ), + vec3( -0.181859, 0.251670, -0.679702 ), + vec3( -0.191463, -0.635818, -0.512919 ), + vec3( -0.293655, 0.427423, 0.078921 ), + vec3( -0.267983, 0.680534, -0.132880 ), + vec3( 0.139611, 0.319637, 0.477439 ), + vec3( -0.352086, 0.311040, 0.653913 ), + vec3( 0.321032, 0.805279, 0.487345 ), + vec3( 0.073516, 0.820734, -0.414183 ), + vec3( -0.155324, 0.589983, -0.411460 ), + vec3( 0.335976, 0.170782, -0.527627 ), + vec3( 0.463460, -0.355658, -0.167689 ), + vec3( 0.222654, 0.596550, -0.769406 ), + vec3( 0.922138, -0.042070, 0.147555 ), + vec3( -0.727050, -0.329192, 0.369826 ), + vec3( -0.090731, 0.533820, 0.463767 ), + vec3( -0.323457, -0.876559, -0.238524 ), + vec3( -0.663277, -0.372384, -0.342856 ) + ); + + // Sample a random normal for reflecting the + // sphere vector later in our loop. + vec4 noiseMapUV = vec4( ( IN_uv1 * ( targetSize / texSize1 ) ).xy, 0, 0 ); + vec3 reflectNormal = normalize( tex2Dlod( randNormalTex, noiseMapUV ).xyz * 2.0 - 1.0 ); + //return vec4( reflectNormal, 1 ); + + vec4 deferred = deferredUncondition( deferredMap, IN_uv0 ); + vec3 normal = deferred.xyz; + float depth = deferred.a; + //return vec4( ( depth ).xxx, 1 ); + + // Early out if too far away. + if ( depth > 0.99999999 ) + { + OUT_col = vec4( 0,0,0,0 ); + return; + } + + // current fragment coords in screen space + vec3 ep = vec3( IN_uv0, depth ); + + float bl; + vec3 baseRay, ray, se, occNorm, projRadius; + float normalDiff = 0; + float depthMin, depthMax, dt, depthDiff; + vec4 occluderFragment; + int i; + float sOcclusion = 0.0; + float lOcclusion = 0.0; + + //------------------------------------------------------------ + // Small radius + //------------------------------------------------------------ + +#ifdef DOSMALL + + bl = 0.0; + + projRadius.xy = ( vec2( sRadius ) / ( depth * nearFar.y ) ) * ( worldToScreenScale / texSize0 ); + projRadius.z = sRadius / nearFar.y; + + depthMin = projRadius.z * sDepthMin; + depthMax = projRadius.z * sDepthMax; + + //float maxr = 1; + //radiusDepth = clamp( radiusDepth, 0.0001, maxr.rrr ); + //if ( radiusDepth.x < 1.0 / targetSize.x ) + // return color; + //radiusDepth.xyz = 0.0009; + + for ( i = 0; i < sSampleCount; i++ ) + { + baseRay = reflect( ptSphere[i], reflectNormal ); + + dt = dot( baseRay.xyz, normal ); + + baseRay *= sign( dt ); + + ray = ( projRadius * baseRay.xzy ); + ray.y = -ray.y; + + se = ep + ray; + + occluderFragment = deferredUncondition( deferredMap, se.xy ); + + depthDiff = se.z - occluderFragment.a; + + dt = dot( occluderFragment.xyz, baseRay.xyz ); + normalDiff = dot( occluderFragment.xyz, normal ); + + bl += getOcclusion( depthDiff, depthMin, depthMax, sDepthPow, normalDiff, dt, sNormalTol, sNormalPow ); + } + + sOcclusion = sStrength * ( bl / float(sSampleCount) ); + +#endif // DOSMALL + + + //------------------------------------------------------------ + // Large radius + //------------------------------------------------------------ + +#ifdef DOLARGE + + bl = 0.0; + + projRadius.xy = ( vec2( lRadius ) / ( depth * nearFar.y ) ) * ( worldToScreenScale / texSize0 ); + projRadius.z = lRadius / nearFar.y; + + depthMin = projRadius.z * lDepthMin; + depthMax = projRadius.z * lDepthMax; + + //projRadius.xy = clamp( projRadius.xy, 0.0, 0.01 ); + //float maxr = 1; + //radiusDepth = clamp( radiusDepth, 0.0001, maxr.rrr ); + //if ( radiusDepth.x < 1.0 / targetSize.x ) + // return color; + //radiusDepth.xyz = 0.0009; + + for ( i = sSampleCount; i < totalSampleCount; i++ ) + { + baseRay = reflect( ptSphere[i], reflectNormal ); + + dt = dot( baseRay.xyz, normal ); + + baseRay *= sign( dt ); + + ray = ( projRadius * baseRay.xzy ); + ray.y = -ray.y; + + se = ep + ray; + + occluderFragment = deferredUncondition( deferredMap, se.xy ); + + depthDiff = se.z - occluderFragment.a; + + normalDiff = dot( occluderFragment.xyz, normal ); + dt = dot( occluderFragment.xyz, baseRay.xyz ); + + bl += getOcclusion( depthDiff, depthMin, depthMax, lDepthPow, normalDiff, dt, lNormalTol, lNormalPow ); + } + + lOcclusion = lStrength * ( bl / float( totalSampleCount - sSampleCount ) ); + +#endif // DOLARGE + + float occlusion = saturate( max( sOcclusion, lOcclusion ) * overallStrength ); + + // Note black is unoccluded and white is fully occluded. This + // seems backwards, but it makes it simple to deal with the SSAO + // being disabled in the lighting shaders. + + OUT_col = vec4(occlusion, vec3(0.0)); +} + + diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/ssao/gl/SSAO_PowerTable_P.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/ssao/gl/SSAO_PowerTable_P.glsl new file mode 100644 index 000000000..4f49479ba --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/ssao/gl/SSAO_PowerTable_P.glsl @@ -0,0 +1,34 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" + +in vec2 uv0; +#define IN_uv0 uv0 + +out vec4 OUT_col; + +void main() +{ + float power = pow( max( IN_uv0.x, 0 ), 0.1 ); + OUT_col = vec4( power, 0, 0, 1 ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/ssao/gl/SSAO_PowerTable_V.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/ssao/gl/SSAO_PowerTable_V.glsl new file mode 100644 index 000000000..a193f63ce --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/ssao/gl/SSAO_PowerTable_V.glsl @@ -0,0 +1,38 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/torque.glsl" +#include "../../../gl/hlslCompat.glsl" +#include "../../gl/postFX.glsl" + +void main() +{ + OUT_hpos = IN_pos; + OUT_uv0 = IN_uv; //viewportCoordToRenderTarget( IN_uv, rtParams0 ); + OUT_uv1 = IN_uv; //viewportCoordToRenderTarget( IN_uv, rtParams1 ); + OUT_uv2 = IN_uv; //viewportCoordToRenderTarget( IN_uv, rtParams2 ); + OUT_uv3 = IN_uv; //viewportCoordToRenderTarget( IN_uv, rtParams3 ); + + OUT_wsEyeRay = IN_wsEyeRay; + + correctSSP(gl_Position); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/turbulenceP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/turbulenceP.hlsl new file mode 100644 index 000000000..c8c572ae7 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/turbulenceP.hlsl @@ -0,0 +1,44 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "./postFx.hlsl" + +uniform float accumTime; +uniform float2 projectionOffset; +uniform float4 targetViewport; +TORQUE_UNIFORM_SAMPLER2D(inputTex, 0); + + +float4 main( PFXVertToPix IN ) : TORQUE_TARGET0 +{ + float speed = 2.0; + float distortion = 6.0; + + float y = IN.uv0.y + (cos((IN.uv0.y+projectionOffset.y) * distortion + accumTime * speed) * 0.01); + float x = IN.uv0.x + (sin((IN.uv0.x+projectionOffset.x) * distortion + accumTime * speed) * 0.01); + + // Clamp the calculated uv values to be within the target's viewport + y = clamp(y, targetViewport.y, targetViewport.w); + x = clamp(x, targetViewport.x, targetViewport.z); + + return TORQUE_TEX2D(inputTex, float2(x, y)); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/underwaterFogP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/underwaterFogP.hlsl new file mode 100644 index 000000000..aab43c45c --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/underwaterFogP.hlsl @@ -0,0 +1,138 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "./postFx.hlsl" +#include "../torque.hlsl" +#include "../shaderModelAutoGen.hlsl" +//----------------------------------------------------------------------------- +// Defines +//----------------------------------------------------------------------------- + +// oceanFogData +#define FOG_DENSITY waterFogData[0] +#define FOG_DENSITY_OFFSET waterFogData[1] +#define WET_DEPTH waterFogData[2] +#define WET_DARKENING waterFogData[3] + +//----------------------------------------------------------------------------- +// Uniforms +//----------------------------------------------------------------------------- + +TORQUE_UNIFORM_SAMPLER2D(deferredTex, 0); +TORQUE_UNIFORM_SAMPLER2D(backbuffer, 1); +TORQUE_UNIFORM_SAMPLER1D(waterDepthGradMap, 2); + +uniform float3 eyePosWorld; +uniform float waterDepthGradMax; +uniform float3 ambientColor; +uniform float4 waterColor; +uniform float4 waterFogData; +uniform float4 waterFogPlane; +uniform float2 nearFar; +uniform float4 rtParams0; + + +float4 main( PFXVertToPix IN ) : TORQUE_TARGET0 +{ + //float2 deferredCoord = IN.uv0; + //IN.uv0 = ( IN.uv0.xy * rtParams0.zw ) + rtParams0.xy; + float depth = TORQUE_DEFERRED_UNCONDITION( deferredTex, IN.uv0 ).w; + //return float4( depth.rrr, 1 ); + + // Skip fogging the extreme far plane so that + // the canvas clear color always appears. + //clip( 0.9 - depth ); + + // We assume that the eye position is below water because + // otherwise this shader/posteffect should not be active. + + depth *= nearFar.y; + + float3 eyeRay = normalize( IN.wsEyeRay ); + + float3 rayStart = eyePosWorld; + float3 rayEnd = eyePosWorld + ( eyeRay * depth ); + //return float4( rayEnd, 1 ); + + float4 plane = waterFogPlane; //float4( 0, 0, 1, -waterHeight ); + //plane.w -= 0.15; + + float startSide = dot( plane.xyz, rayStart ) + plane.w; + if ( startSide > 0 ) + { + rayStart.z -= ( startSide ); + //return float4( 1, 0, 0, 1 ); + } + + float3 hitPos; + float3 ray = rayEnd - rayStart; + float rayLen = length( ray ); + float3 rayDir = normalize( ray ); + + float endSide = dot( plane.xyz, rayEnd ) + plane.w; + float planeDist; + + if ( endSide < -0.005 ) + { + //return float4( 0, 0, 1, 1 ); + hitPos = rayEnd; + planeDist = endSide; + } + else + { + //return float4( 0, 0, 0, 0 ); + float den = dot( ray, plane.xyz ); + + // Parallal to the plane, return the endPnt. + //if ( den == 0.0f ) + // return endPnt; + + float dist = -( dot( plane.xyz, rayStart ) + plane.w ) / den; + if ( dist < 0.0 ) + dist = 0.0; + //return float4( 1, 0, 0, 1 ); + //return float4( ( dist ).rrr, 1 ); + + + hitPos = lerp( rayStart, rayEnd, dist ); + + planeDist = dist; + } + + float delta = length( hitPos - rayStart ); + + float fogAmt = 1.0 - saturate( exp( -FOG_DENSITY * ( delta - FOG_DENSITY_OFFSET ) ) ); + //return float4( fogAmt.rrr, 1 ); + + // Calculate the water "base" color based on depth. + float4 fogColor = waterColor * TORQUE_TEX1D( waterDepthGradMap, saturate( delta / waterDepthGradMax ) ); + // Modulate baseColor by the ambientColor. + fogColor *= float4( ambientColor.rgb, 1 ); + + float3 inColor = hdrDecode( TORQUE_TEX2D( backbuffer, IN.uv0 ).rgb ); + inColor.rgb *= 1.0 - saturate( abs( planeDist ) / WET_DEPTH ) * WET_DARKENING; + //return float4( inColor, 1 ); + + float3 outColor = lerp( inColor, fogColor.rgb, fogAmt ); + + return float4( hdrEncode( outColor ), 1 ); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/vignette/VignetteP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/vignette/VignetteP.hlsl new file mode 100644 index 000000000..c518a2145 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/vignette/VignetteP.hlsl @@ -0,0 +1,35 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../postFx.hlsl" + +TORQUE_UNIFORM_SAMPLER2D(backBuffer, 0); +uniform float Vmax; +uniform float Vmin; + +float4 main(PFXVertToPix IN) : TORQUE_TARGET0 +{ + float4 base = TORQUE_TEX2D(backBuffer, IN.uv0); + float dist = distance(IN.uv0, float2(0.5,0.5)); + base.rgb *= smoothstep(Vmax, Vmin, dist); + return base; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/postFX/vignette/gl/VignetteP.glsl b/Templates/BaseGame/game/core/rendering/shaders/postFX/vignette/gl/VignetteP.glsl new file mode 100644 index 000000000..35de95c34 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/postFX/vignette/gl/VignetteP.glsl @@ -0,0 +1,41 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../../gl/hlslCompat.glsl" +#include "shadergen:/autogenConditioners.h" + +uniform sampler2D backBuffer; +uniform float Vmax; +uniform float Vmin; + +in vec2 uv0; +#define IN_uv0 uv0 + +out vec4 OUT_col; + +void main() +{ + vec4 base = texture(backBuffer, IN_uv0); + float dist = distance(IN_uv0, vec2(0.5,0.5)); + base.rgb *= smoothstep(Vmax, Vmin, dist); + OUT_col = base; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/precipP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/precipP.hlsl new file mode 100644 index 000000000..069ba4992 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/precipP.hlsl @@ -0,0 +1,53 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Structures +//----------------------------------------------------------------------------- + +#include "shaderModel.hlsl" + +struct Conn +{ + float4 position : TORQUE_POSITION; + float2 texCoord : TEXCOORD0; + float4 color : COLOR0; +}; + +struct Frag +{ + float4 col : TORQUE_TARGET0; +}; + +TORQUE_UNIFORM_SAMPLER2D(diffuseMap, 0); + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +Frag main( Conn In) +{ + Frag Out; + + Out.col = TORQUE_TEX2D(diffuseMap, In.texCoord) * In.color; + + return Out; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/precipV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/precipV.hlsl new file mode 100644 index 000000000..3c40942c7 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/precipV.hlsl @@ -0,0 +1,71 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//***************************************************************************** +// Precipitation vertex shader +//***************************************************************************** +//----------------------------------------------------------------------------- +// Constants +//----------------------------------------------------------------------------- + +#include "shaderModel.hlsl" + +struct Vert +{ + float3 position : POSITION; + float2 texCoord : TEXCOORD0; + float4 color : COLOR0; +}; + +struct Conn +{ + float4 position : TORQUE_POSITION; + float2 texCoord : TEXCOORD0; + float4 color : COLOR0; +}; + +uniform float4x4 modelview : register(C0); +uniform float2 fadeStartEnd : register(C4); +uniform float3 cameraPos : register(C5); +uniform float3 ambient : register(C6); + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +Conn main( Vert In ) +{ + Conn Out; + + Out.position = mul(modelview, float4(In.position,1.0)); + Out.texCoord = In.texCoord; + Out.color = float4( ambient.r, ambient.g, ambient.b, 1 ); + + // Do we need to do a distance fade? + if ( fadeStartEnd.x < fadeStartEnd.y ) { + + float distance = length( cameraPos - In.position ); + Out.color.a = abs( clamp( ( distance - fadeStartEnd.x ) / ( fadeStartEnd.y - fadeStartEnd.x ), 0, 1 ) - 1 ); + } + + return Out; +} + diff --git a/Templates/BaseGame/game/core/rendering/shaders/projectedShadowP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/projectedShadowP.hlsl new file mode 100644 index 000000000..88713bd52 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/projectedShadowP.hlsl @@ -0,0 +1,40 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "shaderModel.hlsl" + +struct Conn +{ + float4 position : TORQUE_POSITION; + float4 color : COLOR0; + float2 texCoord : TEXCOORD0; + float fade : TEXCOORD1; +}; + +TORQUE_UNIFORM_SAMPLER2D(inputTex, 0); +uniform float4 ambient; + +float4 main( Conn IN ) : TORQUE_TARGET0 +{ + float shadow = TORQUE_TEX2D( inputTex, IN.texCoord ).a * IN.color.a; + return ( ambient * shadow ) + ( 1 - shadow ); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/projectedShadowV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/projectedShadowV.hlsl new file mode 100644 index 000000000..38b1bd3e2 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/projectedShadowV.hlsl @@ -0,0 +1,60 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "shaderModel.hlsl" + +struct Vert +{ + float3 position : POSITION; + float3 normal : NORMAL; + float3 T : TANGENT; + float4 color : COLOR0; + float2 texCoord : TEXCOORD0; +}; + +struct Conn +{ + float4 position : TORQUE_POSITION; + float4 color : COLOR0; + float2 texCoord : TEXCOORD0; + float fade : TEXCOORD1; +}; + +uniform float4x4 modelview; +uniform float shadowLength; +uniform float3 shadowCasterPosition; + +Conn main( Vert In ) +{ + Conn Out; + + // Decals are in world space. + Out.position = mul( modelview, float4( In.position, 1.0 ) ); + + Out.color = In.color; + Out.texCoord = In.texCoord; + + float fromCasterDist = length( In.position - shadowCasterPosition ) - shadowLength; + Out.fade = 1.0 - saturate( fromCasterDist / shadowLength ); + + return Out; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/ribbons/basicRibbonShaderP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/ribbons/basicRibbonShaderP.hlsl new file mode 100644 index 000000000..f4c6c7b04 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/ribbons/basicRibbonShaderP.hlsl @@ -0,0 +1,19 @@ +#define IN_HLSL +#include "../shdrConsts.h" +#include "../shaderModel.hlsl" + +struct v2f +{ + float4 hpos : TORQUE_POSITION; + float4 color : COLOR0; + float2 texCoord : TEXCOORD0; + float2 shiftdata : TEXCOORD1; +}; + +float4 main(v2f IN) : TORQUE_TARGET0 +{ + float fade = 1.0 - abs(IN.shiftdata.y - 0.5) * 2.0; + IN.color.xyz = IN.color.xyz + pow(fade, 4) / 10; + IN.color.a = IN.color.a * fade; + return IN.color; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/ribbons/basicRibbonShaderV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/ribbons/basicRibbonShaderV.hlsl new file mode 100644 index 000000000..1a6bc85e4 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/ribbons/basicRibbonShaderV.hlsl @@ -0,0 +1,35 @@ +#define IN_HLSL +#include "../shdrConsts.h" +#include "../shaderModel.hlsl" + +struct a2v +{ + float3 position : POSITION; + float3 normal : NORMAL; + float4 color : COLOR0; + float2 texCoord : TEXCOORD0; + float2 shiftdata : TEXCOORD1; +}; + +struct v2f +{ + float4 hpos : TORQUE_POSITION; + float4 color : COLOR0; + float2 texCoord : TEXCOORD0; + float2 shiftdata : TEXCOORD1; +}; + +uniform float4x4 modelview; +uniform float3 eyePos; + +v2f main(a2v IN) +{ + v2f OUT; + + OUT.hpos = mul(modelview, float4(IN.position, 1.0)); + OUT.color = IN.color; + OUT.texCoord = IN.texCoord; + OUT.shiftdata = IN.shiftdata; + + return OUT; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/ribbons/gl/basicRibbonShaderP.glsl b/Templates/BaseGame/game/core/rendering/shaders/ribbons/gl/basicRibbonShaderP.glsl new file mode 100644 index 000000000..f3f83ce30 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/ribbons/gl/basicRibbonShaderP.glsl @@ -0,0 +1,20 @@ +#include "../../gl/hlslCompat.glsl" + +in float4 _hpos; +in float2 _texCoord; +in float2 _shiftdata; +in float4 _color; + +#define IN_hpos _hpos +#define IN_texCoord _texCoord +#define IN_shiftdata _shiftdata +#define IN_color _color + +out float4 OUT_col; + +void main() +{ + float fade = 1.0 - abs(IN_shiftdata.y - 0.5) * 2.0; + OUT_col.xyz = IN_color.xyz + pow(fade, 4) / 10; + OUT_col.a = IN_color.a * fade; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/ribbons/gl/basicRibbonShaderV.glsl b/Templates/BaseGame/game/core/rendering/shaders/ribbons/gl/basicRibbonShaderV.glsl new file mode 100644 index 000000000..9f6826d55 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/ribbons/gl/basicRibbonShaderV.glsl @@ -0,0 +1,37 @@ +#include "../../gl/hlslCompat.glsl" + +in float2 vTexCoord0; +in float2 vTexCoord1; +in float3 vNormal; +in float4 vPosition; +in float4 vColor; + +#define IN_texCoord vTexCoord0 +#define IN_shiftdata vTexCoord1 +#define IN_normal vNormal +#define IN_position vPosition +#define IN_color vColor + +out float4 _hpos; +out float2 _texCoord; +out float2 _shiftdata; +out float4 _color; + +#define OUT_hpos _hpos +#define OUT_texCoord _texCoord +#define OUT_shiftdata _shiftdata +#define OUT_color _color + +uniform float4x4 modelview; +uniform float3 eyePos; + +void main() +{ + OUT_hpos = tMul(modelview, IN_position); + OUT_color = IN_color; + OUT_texCoord = IN_texCoord; + OUT_shiftdata = IN_shiftdata; + + gl_Position = OUT_hpos; + correctSSP(gl_Position); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/ribbons/gl/texRibbonShaderP.glsl b/Templates/BaseGame/game/core/rendering/shaders/ribbons/gl/texRibbonShaderP.glsl new file mode 100644 index 000000000..cd3e72d43 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/ribbons/gl/texRibbonShaderP.glsl @@ -0,0 +1,22 @@ +#include "../../gl/hlslCompat.glsl" +#include "../../gl/torque.glsl" + +in float4 _hpos; +in float2 _texCoord; +in float2 _shiftdata; +in float4 _color; + +#define IN_hpos _hpos +#define IN_texCoord _texCoord +#define IN_shiftdata _shiftdata +#define IN_color _color + +out float4 OUT_col; +uniform sampler2D ribTex; + +void main() +{ + float4 Tex = tex2D(ribTex,IN_texCoord); + Tex.a *= IN_color.a; + OUT_col = hdrEncode(Tex); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/ribbons/gl/texRibbonShaderV.glsl b/Templates/BaseGame/game/core/rendering/shaders/ribbons/gl/texRibbonShaderV.glsl new file mode 100644 index 000000000..9f6826d55 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/ribbons/gl/texRibbonShaderV.glsl @@ -0,0 +1,37 @@ +#include "../../gl/hlslCompat.glsl" + +in float2 vTexCoord0; +in float2 vTexCoord1; +in float3 vNormal; +in float4 vPosition; +in float4 vColor; + +#define IN_texCoord vTexCoord0 +#define IN_shiftdata vTexCoord1 +#define IN_normal vNormal +#define IN_position vPosition +#define IN_color vColor + +out float4 _hpos; +out float2 _texCoord; +out float2 _shiftdata; +out float4 _color; + +#define OUT_hpos _hpos +#define OUT_texCoord _texCoord +#define OUT_shiftdata _shiftdata +#define OUT_color _color + +uniform float4x4 modelview; +uniform float3 eyePos; + +void main() +{ + OUT_hpos = tMul(modelview, IN_position); + OUT_color = IN_color; + OUT_texCoord = IN_texCoord; + OUT_shiftdata = IN_shiftdata; + + gl_Position = OUT_hpos; + correctSSP(gl_Position); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/ribbons/texRibbonShaderP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/ribbons/texRibbonShaderP.hlsl new file mode 100644 index 000000000..55bae76fd --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/ribbons/texRibbonShaderP.hlsl @@ -0,0 +1,21 @@ +#define IN_HLSL +#include "../shdrConsts.h" +#include "../torque.hlsl" + + +TORQUE_UNIFORM_SAMPLER2D(ribTex, 0); + +struct v2f +{ + float4 hpos : TORQUE_POSITION; + float4 color : COLOR0; + float2 texCoord : TEXCOORD0; + float2 shiftdata : TEXCOORD1; +}; + +float4 main(v2f IN) : TORQUE_TARGET0 +{ + float4 Tex = TORQUE_TEX2D(ribTex,IN.texCoord); + Tex.a *= IN.color.a; + return hdrEncode(Tex); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/ribbons/texRibbonShaderV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/ribbons/texRibbonShaderV.hlsl new file mode 100644 index 000000000..2ce4f62fd --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/ribbons/texRibbonShaderV.hlsl @@ -0,0 +1,35 @@ +#define IN_HLSL +#include "../shdrConsts.h" +#include "../shaderModel.hlsl" + +struct a2v +{ + float3 position : POSITION; + float4 color : COLOR0; + float3 normal : NORMAL; + float2 texCoord : TEXCOORD0; + float2 shiftdata : TEXCOORD1; +}; + +struct v2f +{ + float4 hpos : TORQUE_POSITION; + float4 color : COLOR0; + float2 texCoord : TEXCOORD0; + float2 shiftdata : TEXCOORD1; +}; + +uniform float4x4 modelview; +uniform float3 eyePos; + +v2f main(a2v IN) +{ + v2f OUT; + + OUT.hpos = mul(modelview, float4(IN.position,1.0)); + OUT.color = IN.color; + OUT.texCoord = IN.texCoord; + OUT.shiftdata = IN.shiftdata; + + return OUT; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/scatterSkyP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/scatterSkyP.hlsl new file mode 100644 index 000000000..84e0854e0 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/scatterSkyP.hlsl @@ -0,0 +1,69 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "shaderModel.hlsl" +#include "torque.hlsl" + +struct Conn +{ + float4 hpos : TORQUE_POSITION; + float4 rayleighColor : TEXCOORD0; + float4 mieColor : TEXCOORD1; + float3 v3Direction : TEXCOORD2; + float3 pos : TEXCOORD3; +}; + +TORQUE_UNIFORM_SAMPLERCUBE(nightSky, 0); +uniform float4 nightColor; +uniform float2 nightInterpAndExposure; +uniform float useCubemap; +uniform float3 lightDir; +uniform float3 sunDir; + +float4 main( Conn In ) : TORQUE_TARGET0 +{ + + float fCos = dot( lightDir, In.v3Direction ) / length(In.v3Direction); + float fCos2 = fCos*fCos; + + float g = -0.991; + float g2 = -0.991 * -0.991; + + float fMiePhase = 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos2) / pow(abs(1.0 + g2 - 2.0*g*fCos), 1.5); + + float4 color = In.rayleighColor + fMiePhase * In.mieColor; + color.a = color.b; + + float4 Out; + + float4 nightSkyColor = TORQUE_TEXCUBE(nightSky, -In.v3Direction); + nightSkyColor = lerp( nightColor, nightSkyColor, useCubemap ); + + float fac = dot( normalize( In.pos ), sunDir ); + fac = max( nightInterpAndExposure.y, pow( saturate( fac ), 2 ) ); + Out = lerp( color, nightSkyColor, nightInterpAndExposure.y ); + + Out.a = 1; + Out = saturate(Out); + + return hdrEncode( Out ); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/scatterSkyV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/scatterSkyV.hlsl new file mode 100644 index 000000000..2052448db --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/scatterSkyV.hlsl @@ -0,0 +1,157 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "shaderModel.hlsl" + +// The scale equation calculated by Vernier's Graphical Analysis +float vernierScale(float fCos) +{ + float x = 1.0 - fCos; + float x5 = x * 5.25; + float x5p6 = (-6.80 + x5); + float xnew = (3.83 + x * x5p6); + float xfinal = (0.459 + x * xnew); + float xfinal2 = -0.00287 + x * xfinal; + float outx = exp( xfinal2 ); + return 0.25 * outx; +} + +// This is the shader input vertex structure. +struct Vert +{ + // .xyz = point + float3 position : POSITION; +}; + +// This is the shader output data. +struct Conn +{ + float4 position : TORQUE_POSITION; + float4 rayleighColor : TEXCOORD0; + float4 mieColor : TEXCOORD1; + float3 v3Direction : TEXCOORD2; + float3 pos : TEXCOORD3; +}; + +float3 desaturate(const float3 color, const float desaturation) +{ + const float3 gray_conv = float3 (0.30, 0.59, 0.11); + return lerp(color, dot(gray_conv , color), desaturation); +} + +uniform float4x4 modelView; +uniform float4 misc; +uniform float4 sphereRadii; +uniform float4 scatteringCoeffs; +uniform float4 colorize; +uniform float3 camPos; +uniform float3 lightDir; +uniform float4 invWaveLength; + +Conn main( Vert In ) +{ + // Pull some variables out: + float camHeight = misc.x; + float camHeightSqr = misc.y; + + float scale = misc.z; + float scaleOverScaleDepth = misc.w; + + float outerRadius = sphereRadii.x; + float outerRadiusSqr = sphereRadii.y; + + float innerRadius = sphereRadii.z; + float innerRadiusSqr = sphereRadii.w; + + float rayleighBrightness = scatteringCoeffs.x; // Kr * ESun + float rayleigh4PI = scatteringCoeffs.y; // Kr * 4 * PI + + float mieBrightness = scatteringCoeffs.z; // Km * ESun + float mie4PI = scatteringCoeffs.w; // Km * 4 * PI + + // Get the ray from the camera to the vertex, + // and its length (which is the far point of the ray + // passing through the atmosphere). + float4 v3Pos = float4(In.position,1.0) / 6378000.0; // outerRadius; + float3 newCamPos = float3( 0, 0, camHeight ); + v3Pos.z += innerRadius; + float3 v3Ray = v3Pos.xyz - newCamPos; + float fFar = length(v3Ray); + v3Ray /= fFar; + + // Calculate the ray's starting position, + // then calculate its scattering offset. + float3 v3Start = newCamPos; + float fHeight = length(v3Start); + float fDepth = exp(scaleOverScaleDepth * (innerRadius - camHeight)); + float fStartAngle = dot(v3Ray, v3Start) / fHeight; + + float fStartOffset = fDepth * vernierScale( fStartAngle ); + + // Initialize the scattering loop variables. + float fSampleLength = fFar / 2; + float fScaledLength = fSampleLength * scale; + float3 v3SampleRay = v3Ray * fSampleLength; + float3 v3SamplePoint = v3Start + v3SampleRay * 0.5; + + // Now loop through the sample rays + float3 v3FrontColor = float3(0.0, 0.0, 0.0); + for(int i=0; i<2; i++) + { + float fHeight = length(v3SamplePoint); + float fDepth = exp(scaleOverScaleDepth * (innerRadius - fHeight)); + float fLightAngle = dot(lightDir, v3SamplePoint) / fHeight; + float fCameraAngle = dot(v3Ray, v3SamplePoint) / fHeight; + + float vscale3 = vernierScale( fCameraAngle ); + float vscale2 = vernierScale( fLightAngle ); + + float fScatter = (fStartOffset + fDepth*(vscale2 - vscale3)); + float3 v3Attenuate = exp(-fScatter * (invWaveLength.xyz * rayleigh4PI + mie4PI)); + v3FrontColor += v3Attenuate * (fDepth * fScaledLength); + v3SamplePoint += v3SampleRay; + } + + Conn Out; + + // Finally, scale the Mie and Rayleigh colors + // and set up the varying variables for the pixel shader. + Out.position = mul( modelView, float4(In.position,1.0) ); + Out.mieColor.rgb = v3FrontColor * mieBrightness; + Out.mieColor.a = 1.0f; + Out.rayleighColor.rgb = v3FrontColor * (invWaveLength.xyz * rayleighBrightness); + Out.rayleighColor.a = 1.0f; + Out.v3Direction = newCamPos - v3Pos.xyz; + Out.pos = In.position; + +#ifdef USE_COLORIZE + + Out.rayleighColor.rgb = desaturate(Out.rayleighColor.rgb, 1) * colorize.a; + + Out.rayleighColor.r *= colorize.r; + Out.rayleighColor.g *= colorize.g; + Out.rayleighColor.b *= colorize.b; + +#endif + + return Out; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/rendering/shaders/shaderModel.hlsl b/Templates/BaseGame/game/core/rendering/shaders/shaderModel.hlsl new file mode 100644 index 000000000..70ce3a02d --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/shaderModel.hlsl @@ -0,0 +1,97 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2015 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _TORQUE_SHADERMODEL_ +#define _TORQUE_SHADERMODEL_ + +// Portability helpers for different shader models +//Shader model 1.0 - 3.0 +#if (TORQUE_SM >= 10 && TORQUE_SM <=30) + // Semantics + #define TORQUE_POSITION POSITION + #define TORQUE_DEPTH DEPTH + #define TORQUE_TARGET0 COLOR0 + #define TORQUE_TARGET1 COLOR1 + #define TORQUE_TARGET2 COLOR2 + #define TORQUE_TARGET3 COLOR3 + + // Sampler uniforms + #define TORQUE_UNIFORM_SAMPLER1D(tex,regist) uniform sampler1D tex : register(S##regist) + #define TORQUE_UNIFORM_SAMPLER2D(tex,regist) uniform sampler2D tex : register(S##regist) + #define TORQUE_UNIFORM_SAMPLER3D(tex,regist) uniform sampler3D tex : register(S##regist) + #define TORQUE_UNIFORM_SAMPLERCUBE(tex,regist) uniform samplerCUBE tex : register(S##regist) + // Sampling functions + #define TORQUE_TEX1D(tex,coords) tex1D(tex,coords) + #define TORQUE_TEX2D(tex,coords) tex2D(tex,coords) + #define TORQUE_TEX2DPROJ(tex,coords) tex2Dproj(tex,coords) //this really is sm 2 or later + #define TORQUE_TEX3D(tex,coords) tex3D(tex,coords) + #define TORQUE_TEXCUBE(tex,coords) texCUBE(tex,coords) + + //Shader model 3.0 only + #if TORQUE_SM == 30 + #define TORQUE_VPOS VPOS // This is a float2 + // The mipmap LOD is specified in coord.w + #define TORQUE_TEX2DLOD(tex,coords) tex2Dlod(tex,coords) + #endif + + //helper if you want to pass sampler/texture in a function + //2D + #define TORQUE_SAMPLER2D(tex) sampler2D tex + #define TORQUE_SAMPLER2D_MAKEARG(tex) tex + //Cube + #define TORQUE_SAMPLERCUBE(tex) samplerCUBE tex + #define TORQUE_SAMPLERCUBE_MAKEARG(tex) tex +// Shader model 4.0+ +#elif TORQUE_SM >= 40 + #define TORQUE_POSITION SV_Position + #define TORQUE_DEPTH SV_Depth + #define TORQUE_VPOS SV_Position //note float4 compared to SM 3 where it is a float2 + #define TORQUE_TARGET0 SV_Target0 + #define TORQUE_TARGET1 SV_Target1 + #define TORQUE_TARGET2 SV_Target2 + #define TORQUE_TARGET3 SV_Target3 + // Sampler uniforms + //1D is emulated to a 2D for now + #define TORQUE_UNIFORM_SAMPLER1D(tex,regist) uniform Texture2D texture_##tex : register(T##regist); uniform SamplerState tex : register(S##regist) + #define TORQUE_UNIFORM_SAMPLER2D(tex,regist) uniform Texture2D texture_##tex : register(T##regist); uniform SamplerState tex : register(S##regist) + #define TORQUE_UNIFORM_SAMPLER3D(tex,regist) uniform Texture3D texture_##tex : register(T##regist); uniform SamplerState tex : register(S##regist) + #define TORQUE_UNIFORM_SAMPLERCUBE(tex,regist) uniform TextureCube texture_##tex : register(T##regist); uniform SamplerState tex : register(S##regist) + // Sampling functions + #define TORQUE_TEX1D(tex,coords) texture_##tex.Sample(tex,coords) + #define TORQUE_TEX2D(tex,coords) texture_##tex.Sample(tex,coords) + #define TORQUE_TEX2DPROJ(tex,coords) texture_##tex.Sample(tex,coords.xy / coords.w) + #define TORQUE_TEX3D(tex,coords) texture_##tex.Sample(tex,coords) + #define TORQUE_TEXCUBE(tex,coords) texture_##tex.Sample(tex,coords) + // The mipmap LOD is specified in coord.w + #define TORQUE_TEX2DLOD(tex,coords) texture_##tex.SampleLevel(tex,coords.xy,coords.w) + + //helper if you want to pass sampler/texture in a function + //2D + #define TORQUE_SAMPLER2D(tex) Texture2D texture_##tex, SamplerState tex + #define TORQUE_SAMPLER2D_MAKEARG(tex) texture_##tex, tex + //Cube + #define TORQUE_SAMPLERCUBE(tex) TextureCube texture_##tex, SamplerState tex + #define TORQUE_SAMPLERCUBE_MAKEARG(tex) texture_##tex, tex +#endif + +#endif // _TORQUE_SHADERMODEL_ + diff --git a/Templates/BaseGame/game/core/rendering/shaders/shaderModelAutoGen.hlsl b/Templates/BaseGame/game/core/rendering/shaders/shaderModelAutoGen.hlsl new file mode 100644 index 000000000..d70847e46 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/shaderModelAutoGen.hlsl @@ -0,0 +1,35 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2015 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _TORQUE_SHADERMODEL_AUTOGEN_ +#define _TORQUE_SHADERMODEL_AUTOGEN_ + +#include "shadergen:/autogenConditioners.h" + +// Portability helpers for autogenConditioners +#if (TORQUE_SM >= 10 && TORQUE_SM <=30) + #define TORQUE_DEFERRED_UNCONDITION(tex, coords) deferredUncondition(tex, coords) +#elif TORQUE_SM >= 40 + #define TORQUE_DEFERRED_UNCONDITION(tex, coords) deferredUncondition(tex, texture_##tex, coords) +#endif + +#endif //_TORQUE_SHADERMODEL_AUTOGEN_ diff --git a/Templates/BaseGame/game/core/rendering/shaders/shdrConsts.h b/Templates/BaseGame/game/core/rendering/shaders/shdrConsts.h new file mode 100644 index 000000000..8c262b76a --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/shdrConsts.h @@ -0,0 +1,117 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifdef IN_HLSL + +#define VC_WORLD_PROJ C0 + +#define VC_TEX_TRANS1 C4 +#define VC_LIGHT_TRANS C8 +#define VC_OBJ_TRANS C12 + +#define VC_CUBE_TRANS C16 +#define VC_CUBE_EYE_POS C19 // in cubemap space +#define VC_EYE_POS C20 // in object space +#define VC_MAT_SPECPOWER C21 + +#define VC_FOGDATA C22 + +#define VC_LIGHT_POS1 C23 +#define VC_LIGHT_DIR1 C24 +#define VC_LIGHT_DIFFUSE1 C25 +#define VC_LIGHT_SPEC1 C26 + +#define VC_LIGHT_POS2 C27 +//#define VC_LIGHT_DIR2 C28 +//#define VC_LIGHT_DIFFUSE2 C29 +//#define VC_LIGHT_SPEC2 C30 +#define VC_LIGHT_TRANS2 C31 + +//#define VC_LIGHT_POS4 C35 +//#define VC_LIGHT_DIR4 C36 +//#define VC_LIGHT_DIFFUSE4 C37 +//#define VC_LIGHT_SPEC4 C38 + +#define VC_DETAIL_SCALE C40 + + +#define PC_MAT_SPECCOLOR C0 +#define PC_MAT_SPECPOWER C1 +#define PC_DIFF_COLOR C2 +#define PC_AMBIENT_COLOR C3 +#define PC_ACCUM_TIME C4 +#define PC_DIFF_COLOR2 C5 +#define PC_VISIBILITY C6 +#define PC_COLORMULTIPLY C7 + +#define PC_USERDEF1 C8 + +// Mirror of above. Couldn't be cleaner because HLSL doesn't support function macros +#else + +#define VC_WORLD_PROJ 0 + +#define VC_TEX_TRANS1 4 +#define VC_LIGHT_TRANS 8 +#define VC_OBJ_TRANS 12 + +#define VC_CUBE_TRANS 16 +#define VC_CUBE_EYE_POS 19 // in cubemap space +#define VC_EYE_POS 20 // in object space +#define VC_MAT_SPECPOWER 21 + +#define VC_FOGDATA 22 + +#define VC_LIGHT_POS1 23 +#define VC_LIGHT_DIR1 24 +#define VC_LIGHT_DIFFUSE1 25 +#define VC_LIGHT_SPEC1 26 + +#define VC_LIGHT_POS2 27 +//#define VC_LIGHT_DIR2 28 +//#define VC_LIGHT_DIFFUSE2 29 +//#define VC_LIGHT_SPEC2 30 +#define VC_LIGHT_TRANS2 31 + +//#define VC_LIGHT_POS4 35 +//#define VC_LIGHT_DIR4 36 +//#define VC_LIGHT_DIFFUSE4 37 +//#define VC_LIGHT_SPEC4 38 + +#define VC_DETAIL_SCALE 40 + + + +#define PC_MAT_SPECCOLOR 0 +#define PC_MAT_SPECPOWER 1 +#define PC_DIFF_COLOR 2 +#define PC_AMBIENT_COLOR 3 +#define PC_ACCUM_TIME 4 +#define PC_DIFF_COLOR2 5 +#define PC_VISIBILITY 6 +#define PC_COLORMULTIPLY 7 + +#define PC_USERDEF1 8 + +#endif + + diff --git a/Templates/BaseGame/game/core/rendering/shaders/terrain/blendP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/terrain/blendP.hlsl new file mode 100644 index 000000000..aeef9d6e3 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/terrain/blendP.hlsl @@ -0,0 +1,48 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "terrain.hlsl" +#include "../shaderModel.hlsl" + +struct ConnectData +{ + float4 hpos : TORQUE_POSITION; + float2 layerCoord : TEXCOORD0; + float2 texCoord : TEXCOORD1; +}; + +TORQUE_UNIFORM_SAMPLER2D(layerTex, 0); +TORQUE_UNIFORM_SAMPLER2D(textureMap, 1); + +uniform float texId; +uniform float layerSize; + +float4 main( ConnectData IN ) : TORQUE_TARGET0 +{ + float4 layerSample = round( TORQUE_TEX2D( layerTex, IN.layerCoord ) * 255.0f ); + + float blend = calcBlend( texId, IN.layerCoord, layerSize, layerSample ); + + clip( blend - 0.0001 ); + + return float4( TORQUE_TEX2D(textureMap, IN.texCoord).rgb, blend); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/terrain/blendV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/terrain/blendV.hlsl new file mode 100644 index 000000000..9ccd33301 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/terrain/blendV.hlsl @@ -0,0 +1,52 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +/// The vertex shader used in the generation and caching of the +/// base terrain texture. + +#include "../shaderModel.hlsl" + +struct VertData +{ + float3 position : POSITION; + float2 texCoord : TEXCOORD0; +}; + +struct ConnectData +{ + float4 hpos : TORQUE_POSITION; + float2 layerCoord : TEXCOORD0; + float2 texCoord : TEXCOORD1; +}; + +uniform float2 texScale; + +ConnectData main( VertData IN ) +{ + ConnectData OUT; + + OUT.hpos = float4( IN.position, 1 ); + OUT.layerCoord = IN.texCoord; + OUT.texCoord = IN.texCoord * texScale; + + return OUT; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/terrain/gl/blendP.glsl b/Templates/BaseGame/game/core/rendering/shaders/terrain/gl/blendP.glsl new file mode 100644 index 000000000..3189ea01d --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/terrain/gl/blendP.glsl @@ -0,0 +1,48 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../terrain.glsl" +#include "../../gl/hlslCompat.glsl" + +in vec2 layerCoord; +#define IN_layerCoord layerCoord +in vec2 texCoord; +#define IN_texCoord texCoord + +uniform sampler2D layerTex; +uniform sampler2D textureMap; +uniform float texId; +uniform float layerSize; + +out vec4 OUT_col; + +void main() +{ + vec4 layerSample = round(texture( layerTex, IN_layerCoord ) * 255.0); + + float blend = calcBlend( texId, IN_layerCoord, layerSize, layerSample ); + + if(blend - 0.0001 < 0.0) + discard; + + OUT_col = vec4( texture( textureMap, IN_texCoord ).rgb, blend ); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/terrain/gl/blendV.glsl b/Templates/BaseGame/game/core/rendering/shaders/terrain/gl/blendV.glsl new file mode 100644 index 000000000..dc7b7befa --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/terrain/gl/blendV.glsl @@ -0,0 +1,41 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +/// The vertex shader used in the generation and caching of the +/// base terrain texture. + +in vec4 vPosition; +in vec2 vTexCoord0; + +out vec2 layerCoord; +out vec2 texCoord; + +uniform vec2 texScale; + +void main() +{ + gl_Position = vec4(vPosition.xyz, 1.0); + layerCoord = vTexCoord0.st; + texCoord = vTexCoord0.st * texScale; + + gl_Position.y *= -1; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/terrain/terrain.glsl b/Templates/BaseGame/game/core/rendering/shaders/terrain/terrain.glsl new file mode 100644 index 000000000..756edd553 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/terrain/terrain.glsl @@ -0,0 +1,52 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + + +float calcBlend( float texId, vec2 layerCoord, float layerSize, vec4 layerSample ) +{ + // This is here to disable the blend if none of + // the neighbors equal the current id. + // + // We depend on the input layer samples being + // rounded to the correct integer ids. + // + vec4 diff = clamp( abs( layerSample - texId ), 0.0, 1.0 ); + float noBlend = float(any( bvec4(1 - diff) )); + + // Check if any of the layer samples + // match the current texture id. + vec4 factors = vec4(0); + for(int i = 0; i < 4; i++) + factors[i] = (layerSample[i] == texId) ? 1 : 0; // workaround for Intel + + // This is a custom bilinear filter. + + vec2 uv = layerCoord * layerSize; + vec2 xy = floor( uv ); + vec2 ratio = uv - xy; + vec2 opposite = 1 - ratio; + + float blend = ( factors.b * opposite.x + factors.g * ratio.x ) * opposite.y + + ( factors.r * opposite.x + factors.a * ratio.x ) * ratio.y; + + return noBlend * blend; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/terrain/terrain.hlsl b/Templates/BaseGame/game/core/rendering/shaders/terrain/terrain.hlsl new file mode 100644 index 000000000..b7c87e618 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/terrain/terrain.hlsl @@ -0,0 +1,55 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + + +float calcBlend( float texId, float2 layerCoord, float layerSize, float4 layerSample ) +{ + // This is here to disable the blend if none of + // the neighbors equal the current id. + // + // We depend on the input layer samples being + // rounded to the correct integer ids. + // + float4 diff = saturate( abs( layerSample - texId ) ); + float noBlend = any( 1 - diff ); + + // Check if any of the layer samples + // match the current texture id. + float4 factors = 0; + [unroll] + for(int i = 0; i < 4; i++) + if(layerSample[i] == texId) + factors[i] = 1; + + // This is a custom bilinear filter. + + float2 uv = layerCoord * layerSize; + float2 xy = floor( uv ); + float2 ratio = uv - xy; + float2 opposite = 1 - ratio; + + // NOTE: This will optimize down to two lerp operations. + float blend = ( factors.b * opposite.x + factors.g * ratio.x ) * opposite.y + + ( factors.r * opposite.x + factors.a * ratio.x ) * ratio.y; + + return noBlend * blend; +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/torque.hlsl b/Templates/BaseGame/game/core/rendering/shaders/torque.hlsl new file mode 100644 index 000000000..7081c7153 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/torque.hlsl @@ -0,0 +1,342 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _TORQUE_HLSL_ +#define _TORQUE_HLSL_ + +#include "./shaderModel.hlsl" + +static float M_HALFPI_F = 1.57079632679489661923f; +static float M_PI_F = 3.14159265358979323846f; +static float M_2PI_F = 6.28318530717958647692f; + + +/// Calculate fog based on a start and end positions in worldSpace. +float computeSceneFog( float3 startPos, + float3 endPos, + float fogDensity, + float fogDensityOffset, + float fogHeightFalloff ) +{ + float f = length( startPos - endPos ) - fogDensityOffset; + float h = 1.0 - ( endPos.z * fogHeightFalloff ); + return exp( -fogDensity * f * h ); +} + + +/// Calculate fog based on a start and end position and a height. +/// Positions do not need to be in worldSpace but height does. +float computeSceneFog( float3 startPos, + float3 endPos, + float height, + float fogDensity, + float fogDensityOffset, + float fogHeightFalloff ) +{ + float f = length( startPos - endPos ) - fogDensityOffset; + float h = 1.0 - ( height * fogHeightFalloff ); + return exp( -fogDensity * f * h ); +} + + +/// Calculate fog based on a distance, height is not used. +float computeSceneFog( float dist, float fogDensity, float fogDensityOffset ) +{ + float f = dist - fogDensityOffset; + return exp( -fogDensity * f ); +} + + +/// Convert a float4 uv in viewport space to render target space. +float2 viewportCoordToRenderTarget( float4 inCoord, float4 rtParams ) +{ + float2 outCoord = inCoord.xy / inCoord.w; + outCoord = ( outCoord * rtParams.zw ) + rtParams.xy; + return outCoord; +} + + +/// Convert a float2 uv in viewport space to render target space. +float2 viewportCoordToRenderTarget( float2 inCoord, float4 rtParams ) +{ + float2 outCoord = ( inCoord * rtParams.zw ) + rtParams.xy; + return outCoord; +} + + +/// Convert a float4 quaternion into a 3x3 matrix. +float3x3 quatToMat( float4 quat ) +{ + float xs = quat.x * 2.0f; + float ys = quat.y * 2.0f; + float zs = quat.z * 2.0f; + + float wx = quat.w * xs; + float wy = quat.w * ys; + float wz = quat.w * zs; + + float xx = quat.x * xs; + float xy = quat.x * ys; + float xz = quat.x * zs; + + float yy = quat.y * ys; + float yz = quat.y * zs; + float zz = quat.z * zs; + + float3x3 mat; + + mat[0][0] = 1.0f - (yy + zz); + mat[0][1] = xy - wz; + mat[0][2] = xz + wy; + + mat[1][0] = xy + wz; + mat[1][1] = 1.0f - (xx + zz); + mat[1][2] = yz - wx; + + mat[2][0] = xz - wy; + mat[2][1] = yz + wx; + mat[2][2] = 1.0f - (xx + yy); + + return mat; +} + + +/// The number of additional substeps we take when refining +/// the results of the offset parallax mapping function below. +/// +/// You should turn down the number of steps if your needing +/// more performance out of your parallax surfaces. Increasing +/// the number doesn't yeild much better results and is rarely +/// worth the additional cost. +/// +#define PARALLAX_REFINE_STEPS 3 + +/// Performs fast parallax offset mapping using +/// multiple refinement steps. +/// +/// @param texMap The texture map whos alpha channel we sample the parallax depth. +/// @param texCoord The incoming texture coordinate for sampling the parallax depth. +/// @param negViewTS The negative view vector in tangent space. +/// @param depthScale The parallax factor used to scale the depth result. +/// +float2 parallaxOffset(TORQUE_SAMPLER2D(texMap), float2 texCoord, float3 negViewTS, float depthScale) +{ + float depth = TORQUE_TEX2D(texMap, texCoord).a/(PARALLAX_REFINE_STEPS*2); + float2 offset = negViewTS.xy * (depth * depthScale)/(PARALLAX_REFINE_STEPS); + + for (int i = 0; i < PARALLAX_REFINE_STEPS; i++) + { + depth = (depth + TORQUE_TEX2D(texMap, texCoord + offset).a)/(PARALLAX_REFINE_STEPS*2); + offset = negViewTS.xy * (depth * depthScale)/(PARALLAX_REFINE_STEPS); + } + + return offset; +} + +/// Same as parallaxOffset but for dxtnm where depth is stored in the red channel instead of the alpha +float2 parallaxOffsetDxtnm(TORQUE_SAMPLER2D(texMap), float2 texCoord, float3 negViewTS, float depthScale) +{ + float depth = TORQUE_TEX2D(texMap, texCoord).r/(PARALLAX_REFINE_STEPS*2); + float2 offset = negViewTS.xy * (depth * depthScale)/(PARALLAX_REFINE_STEPS*2); + + for (int i = 0; i < PARALLAX_REFINE_STEPS; i++) + { + depth = (depth + TORQUE_TEX2D(texMap, texCoord + offset).r)/(PARALLAX_REFINE_STEPS*2); + offset = negViewTS.xy * (depth * depthScale)/(PARALLAX_REFINE_STEPS*2); + } + + return offset; +} + + +/// The maximum value for 16bit per component integer HDR encoding. +static const float HDR_RGB16_MAX = 100.0; + +/// The maximum value for 10bit per component integer HDR encoding. +static const float HDR_RGB10_MAX = 4.0; + +/// Encodes an HDR color for storage into a target. +float3 hdrEncode( float3 sample ) +{ + #if defined( TORQUE_HDR_RGB16 ) + + return sample / HDR_RGB16_MAX; + + #elif defined( TORQUE_HDR_RGB10 ) + + return sample / HDR_RGB10_MAX; + + #else + + // No encoding. + return sample; + + #endif +} + +/// Encodes an HDR color for storage into a target. +float4 hdrEncode( float4 sample ) +{ + return float4( hdrEncode( sample.rgb ), sample.a ); +} + +/// Decodes an HDR color from a target. +float3 hdrDecode( float3 sample ) +{ + #if defined( TORQUE_HDR_RGB16 ) + + return sample * HDR_RGB16_MAX; + + #elif defined( TORQUE_HDR_RGB10 ) + + return sample * HDR_RGB10_MAX; + + #else + + // No encoding. + return sample; + + #endif +} + +/// Decodes an HDR color from a target. +float4 hdrDecode( float4 sample ) +{ + return float4( hdrDecode( sample.rgb ), sample.a ); +} + +/// Returns the luminance for an HDR pixel. +float hdrLuminance( float3 sample ) +{ + // There are quite a few different ways to + // calculate luminance from an rgb value. + // + // If you want to use a different technique + // then plug it in here. + // + + //////////////////////////////////////////////////////////////////////////// + // + // Max component luminance. + // + //float lum = max( sample.r, max( sample.g, sample.b ) ); + + //////////////////////////////////////////////////////////////////////////// + // The perceptual relative luminance. + // + // See http://en.wikipedia.org/wiki/Luminance_(relative) + // + const float3 RELATIVE_LUMINANCE = float3( 0.2126, 0.7152, 0.0722 ); + float lum = dot( sample, RELATIVE_LUMINANCE ); + + //////////////////////////////////////////////////////////////////////////// + // + // The average component luminance. + // + //const float3 AVERAGE_LUMINANCE = float3( 0.3333, 0.3333, 0.3333 ); + //float lum = dot( sample, AVERAGE_LUMINANCE ); + + return lum; +} + +/// Called from the visibility feature to do screen +/// door transparency for fading of objects. +void fizzle(float2 vpos, float visibility) +{ + // NOTE: The magic values below are what give us + // the nice even pattern during the fizzle. + // + // These values can be changed to get different + // patterns... some better than others. + // + // Horizontal Blinds - { vpos.x, 0.916, vpos.y, 0 } + // Vertical Lines - { vpos.x, 12.9898, vpos.y, 78.233 } + // + // I'm sure there are many more patterns here to + // discover for different effects. + + float2x2 m = { vpos.x, 0.916, vpos.y, 0.350 }; + clip( visibility - frac( determinant( m ) ) ); +} + +// Deferred Shading: Material Info Flag Check +bool getFlag(float flags, int num) +{ + int process = round(flags * 255); + int squareNum = pow(2, num); + return (fmod(process, pow(2, squareNum)) >= squareNum); +} + +// #define TORQUE_STOCK_GAMMA +#ifdef TORQUE_STOCK_GAMMA +// Sample in linear space. Decodes gamma. +float4 toLinear(float4 tex) +{ + return tex; +} +// Encodes gamma. +float4 toGamma(float4 tex) +{ + return tex; +} +float3 toLinear(float3 tex) +{ + return tex; +} +// Encodes gamma. +float3 toGamma(float3 tex) +{ + return tex; +} +float3 toLinear(float3 tex) +{ + return tex; +} +// Encodes gamma. +float3 toLinear(float3 tex) +{ + return tex; +} +#else +// Sample in linear space. Decodes gamma. +float4 toLinear(float4 tex) +{ + return float4(pow(abs(tex.rgb), 2.2), tex.a); +} +// Encodes gamma. +float4 toGamma(float4 tex) +{ + return float4(pow(abs(tex.rgb), 1.0/2.2), tex.a); +} +// Sample in linear space. Decodes gamma. +float3 toLinear(float3 tex) +{ + return pow(abs(tex.rgb), 2.2); +} +// Encodes gamma. +float3 toGamma(float3 tex) +{ + return pow(abs(tex.rgb), 1.0/2.2); +} +#endif // + +#endif // _TORQUE_HLSL_ diff --git a/Templates/BaseGame/game/core/rendering/shaders/water/gl/waterBasicP.glsl b/Templates/BaseGame/game/core/rendering/shaders/water/gl/waterBasicP.glsl new file mode 100644 index 000000000..91bdb4137 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/water/gl/waterBasicP.glsl @@ -0,0 +1,216 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../gl/torque.glsl" +#include "../../gl/hlslCompat.glsl" + +//----------------------------------------------------------------------------- +// Defines +//----------------------------------------------------------------------------- + +// miscParams +#define FRESNEL_BIAS miscParams[0] +#define FRESNEL_POWER miscParams[1] +#define CLARITY miscParams[2] +#define ISRIVER miscParams[3] + +// reflectParams +#define REFLECT_PLANE_Z reflectParams[0] +#define REFLECT_MIN_DIST reflectParams[1] +#define REFLECT_MAX_DIST reflectParams[2] +#define NO_REFLECT reflectParams[3] + +// distortionParams +#define DISTORT_START_DIST distortionParams[0] +#define DISTORT_END_DIST distortionParams[1] +#define DISTORT_FULL_DEPTH distortionParams[2] + +// ConnectData.misc +#define LIGHT_VEC IN_misc.xyz +#define WORLD_Z IN_objPos.w + +// specularParams +#define SPEC_POWER specularParams[3] +#define SPEC_COLOR specularParams.xyz + +//----------------------------------------------------------------------------- +// Defines +//----------------------------------------------------------------------------- + +// TexCoord 0 and 1 (xy,zw) for ripple texture lookup +in vec4 rippleTexCoord01; +#define IN_rippleTexCoord01 rippleTexCoord01 + +// TexCoord 2 for ripple texture lookup +in vec2 rippleTexCoord2; +#define IN_rippleTexCoord2 rippleTexCoord2 + +// Screenspace vert position BEFORE wave transformation +in vec4 posPreWave; +#define IN_posPreWave posPreWave + +// Screenspace vert position AFTER wave transformation +in vec4 posPostWave; +#define IN_posPostWave posPostWave + +// Worldspace unit distance/depth of this vertex/pixel +in float pixelDist; +#define IN_pixelDist pixelDist + +in vec4 objPos; +#define IN_objPos objPos + +in vec3 misc; +#define IN_misc misc + +//----------------------------------------------------------------------------- +// approximate Fresnel function +//----------------------------------------------------------------------------- +float fresnel(float NdotV, float bias, float power) +{ + return bias + (1.0-bias)*pow(abs(1.0 - max(NdotV, 0)), power); +} + +//----------------------------------------------------------------------------- +// Uniforms +//----------------------------------------------------------------------------- +uniform sampler2D bumpMap; +//uniform sampler2D deferredTex; +uniform sampler2D reflectMap; +uniform sampler2D refractBuff; +uniform samplerCube skyMap; +//uniform sampler2D foamMap; +uniform vec4 baseColor; +uniform vec4 miscParams; +uniform vec4 reflectParams; +uniform vec3 ambientColor; +uniform vec3 eyePos; +uniform vec3 distortionParams; +uniform vec3 fogData; +uniform vec4 fogColor; +uniform vec4 rippleMagnitude; +uniform vec4 specularParams; +uniform mat4 modelMat; + +out vec4 OUT_col; + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +void main() +{ + // Modulate baseColor by the ambientColor. + vec4 waterBaseColor = baseColor * vec4( ambientColor.rgb, 1 ); + + // Get the bumpNorm... + vec3 bumpNorm = ( texture( bumpMap, IN_rippleTexCoord01.xy ).rgb * 2.0 - 1.0 ) * rippleMagnitude.x; + bumpNorm += ( texture( bumpMap, IN_rippleTexCoord01.zw ).rgb * 2.0 - 1.0 ) * rippleMagnitude.y; + bumpNorm += ( texture( bumpMap, IN_rippleTexCoord2 ).rgb * 2.0 - 1.0 ) * rippleMagnitude.z; + + bumpNorm = normalize( bumpNorm ); + bumpNorm = mix( bumpNorm, vec3(0,0,1), 1.0 - rippleMagnitude.w ); + + // We subtract a little from it so that we don't + // distort where the water surface intersects the + // camera near plane. + float distortAmt = saturate( IN_pixelDist / 1.0 ) * 0.8; + + vec4 distortPos = IN_posPostWave; + distortPos.xy += bumpNorm.xy * distortAmt; + + #ifdef UNDERWATER + OUT_col = hdrEncode( textureProj( refractBuff, distortPos ) ); + #else + + vec3 eyeVec = IN_objPos.xyz - eyePos; + eyeVec = tMul( mat3(modelMat), eyeVec ); + vec3 reflectionVec = reflect( eyeVec, bumpNorm ); + + // Color that replaces the reflection color when we do not + // have one that is appropriate. + vec4 fakeColor = vec4(ambientColor,1); + + // Use fakeColor for ripple-normals that are angled towards the camera + eyeVec = -eyeVec; + eyeVec = normalize( eyeVec ); + float ang = saturate( dot( eyeVec, bumpNorm ) ); + float fakeColorAmt = ang; + + // Get reflection map color + vec4 refMapColor = hdrDecode( textureProj( reflectMap, distortPos ) ); + // If we do not have a reflection texture then we use the cubemap. + refMapColor = mix( refMapColor, texture( skyMap, reflectionVec ), NO_REFLECT ); + + // Combine reflection color and fakeColor. + vec4 reflectColor = mix( refMapColor, fakeColor, fakeColorAmt ); + //return refMapColor; + + // Get refract color + vec4 refractColor = hdrDecode( textureProj( refractBuff, distortPos ) ); + + // calc "diffuse" color by lerping from the water color + // to refraction image based on the water clarity. + vec4 diffuseColor = mix( refractColor, waterBaseColor, 1.0f - CLARITY ); + + // fresnel calculation + float fresnelTerm = fresnel( ang, FRESNEL_BIAS, FRESNEL_POWER ); + //return vec4( fresnelTerm.rrr, 1 ); + + // Also scale the frensel by our distance to the + // water surface. This removes the hard reflection + // when really close to the water surface. + fresnelTerm *= saturate( IN_pixelDist - 0.1 ); + + // Combine the diffuse color and reflection image via the + // fresnel term and set out output color. + vec4 OUT = mix( diffuseColor, reflectColor, fresnelTerm ); + + #ifdef WATER_SPEC + + // Get some specular reflection. + vec3 newbump = bumpNorm; + newbump.xy *= 3.5; + newbump = normalize( bumpNorm ); + half3 halfAng = normalize( eyeVec + -LIGHT_VEC ); + float specular = saturate( dot( newbump, halfAng ) ); + specular = pow( specular, SPEC_POWER ); + + OUT.rgb = OUT.rgb + ( SPEC_COLOR * specular.xxx ); + + #else // Disable fogging if spec is on because otherwise we run out of instructions. + + // Fog it. + float factor = computeSceneFog( eyePos, + IN_objPos.xyz, + WORLD_Z, + fogData.x, + fogData.y, + fogData.z ); + + //OUT.rgb = mix( OUT.rgb, fogColor.rgb, 1.0 - saturate( factor ) ); + + #endif + + OUT_col = hdrEncode( OUT ); + +#endif +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/water/gl/waterBasicV.glsl b/Templates/BaseGame/game/core/rendering/shaders/water/gl/waterBasicV.glsl new file mode 100644 index 000000000..e92c948e9 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/water/gl/waterBasicV.glsl @@ -0,0 +1,243 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../gl/hlslCompat.glsl" + +//----------------------------------------------------------------------------- +// Defines +//----------------------------------------------------------------------------- + +// TexCoord 0 and 1 (xy,zw) for ripple texture lookup +out vec4 rippleTexCoord01; +#define OUT_rippleTexCoord01 rippleTexCoord01 + +// TexCoord 2 for ripple texture lookup +out vec2 rippleTexCoord2; +#define OUT_rippleTexCoord2 rippleTexCoord2 + +// Screenspace vert position BEFORE wave transformation +out vec4 posPreWave; +#define OUT_posPreWave posPreWave + +// Screenspace vert position AFTER wave transformation +out vec4 posPostWave; +#define OUT_posPostWave posPostWave + +// Worldspace unit distance/depth of this vertex/pixel +out float pixelDist; +#define OUT_pixelDist pixelDist + +out vec4 objPos; +#define OUT_objPos objPos + +out vec3 misc; +#define OUT_misc misc + +//----------------------------------------------------------------------------- +// Uniforms +//----------------------------------------------------------------------------- +uniform mat4 modelMat; +uniform mat4 modelview; +uniform vec4 rippleMat[3]; +uniform vec3 eyePos; +uniform vec2 waveDir[3]; +uniform vec2 waveData[3]; +uniform vec2 rippleDir[3]; +uniform vec2 rippleTexScale[3]; +uniform vec3 rippleSpeed; +uniform vec3 inLightVec; +uniform vec3 reflectNormal; +uniform float gridElementSize; +uniform float elapsedTime; +uniform float undulateMaxDist; + +in vec4 vPosition; +in vec3 vNormal; +in vec2 vTexCoord0; +in vec4 vTexCoord1; + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +void main() +{ + vec4 IN_position = vPosition; + vec3 IN_normal = vNormal; + vec2 IN_undulateData = vTexCoord0; + vec4 IN_horizonFactor = vTexCoord1; + vec4 OUT_hpos = vec4(0); + + // use projection matrix for reflection / refraction texture coords + mat4 texGen = mat4FromRow( 0.5, 0.0, 0.0, 0.5, + 0.0, -0.5, 0.0, 0.5, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0 ); + + // Move the vertex based on the horizonFactor if specified to do so for this vert. + // if ( IN_horizonFactor.z > 0 ) + // { + // vec2 offsetXY = eyePos.xy - eyePos.xy % gridElementSize; + // IN_position.xy += offsetXY; + // IN_undulateData += offsetXY; + // } + + vec4 worldPos = tMul( modelMat, IN_position ); + + IN_position.z = mix( IN_position.z, eyePos.z, IN_horizonFactor.x ); + + //OUT_objPos = worldPos; + OUT_objPos.xyz = IN_position.xyz; + OUT_objPos.w = worldPos.z; + + // Send pre-undulation screenspace position + OUT_posPreWave = tMul( modelview, IN_position ); + OUT_posPreWave = tMul( texGen, OUT_posPreWave ); + + // Calculate the undulation amount for this vertex. + vec2 undulatePos = tMul( modelMat, vec4( IN_undulateData.xy, 0, 1 ) ).xy; + //if ( undulatePos.x < 0 ) + // undulatePos = IN_position.xy; + + float undulateAmt = 0.0; + + undulateAmt += waveData[0].y * sin( elapsedTime * waveData[0].x + + undulatePos.x * waveDir[0].x + + undulatePos.y * waveDir[0].y ); + undulateAmt += waveData[1].y * sin( elapsedTime * waveData[1].x + + undulatePos.x * waveDir[1].x + + undulatePos.y * waveDir[1].y ); + undulateAmt += waveData[2].y * sin( elapsedTime * waveData[2].x + + undulatePos.x * waveDir[2].x + + undulatePos.y * waveDir[2].y ); + + float undulateFade = 1; + + // Scale down wave magnitude amount based on distance from the camera. + float dist = distance( IN_position.xyz, eyePos ); + dist = clamp( dist, 1.0, undulateMaxDist ); + undulateFade *= ( 1 - dist / undulateMaxDist ); + + // Also scale down wave magnitude if the camera is very very close. + undulateFade *= saturate( ( distance( IN_position.xyz, eyePos ) - 0.5 ) / 10.0 ); + + undulateAmt *= undulateFade; + + //#endif + //undulateAmt = 0; + + // Apply wave undulation to the vertex. + OUT_posPostWave = IN_position; + OUT_posPostWave.xyz += IN_normal.xyz * undulateAmt; + + // Save worldSpace position of this pixel/vert + //OUT_worldPos = OUT_posPostWave.xyz; + //OUT_worldPos = tMul( modelMat, OUT_posPostWave.xyz ); + //OUT_worldPos.z += objTrans[2][2]; //91.16; + + // OUT_misc.w = tMul( modelMat, OUT_fogPos ).z; + // if ( IN_horizonFactor.x > 0 ) + // { + // vec3 awayVec = normalize( OUT_fogPos.xyz - eyePos ); + // OUT_fogPos.xy += awayVec.xy * 1000.0; + // } + + // Convert to screen + OUT_posPostWave = tMul( modelview, OUT_posPostWave ); // tMul( modelview, vec4( OUT_posPostWave.xyz, 1 ) ); + + // Setup the OUT position symantic variable + OUT_hpos = OUT_posPostWave; // tMul( modelview, vec4( IN_position.xyz, 1 ) ); //vec4( OUT_posPostWave.xyz, 1 ); + //OUT_hpos.z = mix( OUT_hpos.z, OUT_hpos.w, IN_horizonFactor.x ); + + // Save world space camera dist/depth of the outgoing pixel + OUT_pixelDist = OUT_hpos.z; + + // Convert to reflection texture space + OUT_posPostWave = tMul( texGen, OUT_posPostWave ); + + vec2 txPos = undulatePos; + if ( bool(IN_horizonFactor.x) ) + txPos = normalize( txPos ) * 50000.0; + + // set up tex coordinates for the 3 interacting normal maps + OUT_rippleTexCoord01.xy = txPos * rippleTexScale[0]; + OUT_rippleTexCoord01.xy += rippleDir[0] * elapsedTime * rippleSpeed.x; + + mat2 texMat; + texMat[0][0] = rippleMat[0].x; + texMat[1][0] = rippleMat[0].y; + texMat[0][1] = rippleMat[0].z; + texMat[1][1] = rippleMat[0].w; + OUT_rippleTexCoord01.xy = tMul( texMat, OUT_rippleTexCoord01.xy ); + + OUT_rippleTexCoord01.zw = txPos * rippleTexScale[1]; + OUT_rippleTexCoord01.zw += rippleDir[1] * elapsedTime * rippleSpeed.y; + + texMat[0][0] = rippleMat[1].x; + texMat[1][0] = rippleMat[1].y; + texMat[0][1] = rippleMat[1].z; + texMat[1][1] = rippleMat[1].w; + OUT_rippleTexCoord01.zw = tMul( texMat, OUT_rippleTexCoord01.zw ); + + OUT_rippleTexCoord2.xy = txPos * rippleTexScale[2]; + OUT_rippleTexCoord2.xy += rippleDir[2] * elapsedTime * rippleSpeed.z; + + texMat[0][0] = rippleMat[2].x; + texMat[1][0] = rippleMat[2].y; + texMat[0][1] = rippleMat[2].z; + texMat[1][1] = rippleMat[2].w; + OUT_rippleTexCoord2.xy = tMul( texMat, OUT_rippleTexCoord2.xy ); + +#ifdef WATER_SPEC + + vec3 binormal = vec3( 1, 0, 0 ); + vec3 tangent = vec3( 0, 1, 0 ); + vec3 normal; + for ( int i = 0; i < 3; i++ ) + { + binormal.z += undulateFade * waveDir[i].x * waveData[i].y * cos( waveDir[i].x * IN_undulateData.x + waveDir[i].y * IN_undulateData.y + elapsedTime * waveData[i].x ); + tangent.z += undulateFade * waveDir[i].y * waveData[i].y * cos( waveDir[i].x * IN_undulateData.x + waveDir[i].y * IN_undulateData.y + elapsedTime * waveData[i].x ); + } + + binormal = normalize( binormal ); + tangent = normalize( tangent ); + normal = cross( binormal, tangent ); + + mat3 worldToTangent; + worldToTangent[0] = binormal; + worldToTangent[1] = tangent; + worldToTangent[2] = normal; + + worldToTangent = transpose(worldToTangent); + + OUT_misc.xyz = tMul( inLightVec, modelMat ); + OUT_misc.xyz = tMul( worldToTangent, OUT_misc.xyz ); + +#else + + OUT_misc.xyz = inLightVec; + +#endif + + gl_Position = OUT_hpos; + correctSSP(gl_Position); +} + diff --git a/Templates/BaseGame/game/core/rendering/shaders/water/gl/waterP.glsl b/Templates/BaseGame/game/core/rendering/shaders/water/gl/waterP.glsl new file mode 100644 index 000000000..d4804245a --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/water/gl/waterP.glsl @@ -0,0 +1,396 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../gl/hlslCompat.glsl" +#include "shadergen:/autogenConditioners.h" +#include "../../gl/torque.glsl" + +//----------------------------------------------------------------------------- +// Defines +//----------------------------------------------------------------------------- + +#define PIXEL_DIST IN_rippleTexCoord2.z +// miscParams +#define FRESNEL_BIAS miscParams[0] +#define FRESNEL_POWER miscParams[1] +// miscParams[2] is unused +#define ISRIVER miscParams[3] + +// reflectParams +#define REFLECT_PLANE_Z reflectParams[0] +#define REFLECT_MIN_DIST reflectParams[1] +#define REFLECT_MAX_DIST reflectParams[2] +#define NO_REFLECT reflectParams[3] + +// fogParams +#define FOG_DENSITY fogParams[0] +#define FOG_DENSITY_OFFSET fogParams[1] + +// wetnessParams +#define WET_DEPTH wetnessParams[0] +#define WET_COLOR_FACTOR wetnessParams[1] + +// distortionParams +#define DISTORT_START_DIST distortionParams[0] +#define DISTORT_END_DIST distortionParams[1] +#define DISTORT_FULL_DEPTH distortionParams[2] + +// foamParams +#define FOAM_OPACITY foamParams[0] +#define FOAM_MAX_DEPTH foamParams[1] +#define FOAM_AMBIENT_LERP foamParams[2] +#define FOAM_RIPPLE_INFLUENCE foamParams[3] + +// specularParams +#define SPEC_POWER specularParams[3] +#define SPEC_COLOR specularParams.xyz + +//----------------------------------------------------------------------------- +// Structures +//----------------------------------------------------------------------------- + +//ConnectData IN + +in vec4 hpos; + +// TexCoord 0 and 1 (xy,zw) for ripple texture lookup +in vec4 rippleTexCoord01; + +// xy is TexCoord 2 for ripple texture lookup +// z is the Worldspace unit distance/depth of this vertex/pixel +// w is amount of the crestFoam ( more at crest of waves ). +in vec4 rippleTexCoord2; + +// Screenspace vert position BEFORE wave transformation +in vec4 posPreWave; + +// Screenspace vert position AFTER wave transformation +in vec4 posPostWave; + +// Objectspace vert position BEFORE wave transformation +// w coord is world space z position. +in vec4 objPos; + +in vec4 foamTexCoords; + +in mat3 tangentMat; + + +#define IN_hpos hpos +#define IN_rippleTexCoord01 rippleTexCoord01 +#define IN_rippleTexCoord2 rippleTexCoord2 +#define IN_posPreWave posPreWave +#define IN_posPostWave posPostWave +#define IN_objPos objPos +#define IN_foamTexCoords foamTexCoords +#define IN_tangentMat tangentMat + +//----------------------------------------------------------------------------- +// approximate Fresnel function +//----------------------------------------------------------------------------- +float fresnel(float NdotV, float bias, float power) +{ + return bias + (1.0-bias)*pow(abs(1.0 - max(NdotV, 0)), power); +} + +//----------------------------------------------------------------------------- +// Uniforms +//----------------------------------------------------------------------------- +uniform sampler2D bumpMap; +uniform sampler2D deferredTex; +uniform sampler2D reflectMap; +uniform sampler2D refractBuff; +uniform samplerCube skyMap; +uniform sampler2D foamMap; +uniform sampler1D depthGradMap; +uniform vec4 specularParams; +uniform vec4 baseColor; +uniform vec4 miscParams; +uniform vec2 fogParams; +uniform vec4 reflectParams; +uniform vec3 reflectNormal; +uniform vec2 wetnessParams; +uniform float farPlaneDist; +uniform vec3 distortionParams; +uniform vec4 foamParams; +uniform vec3 ambientColor; +uniform vec3 eyePos; // This is in object space! +uniform vec3 fogData; +uniform vec4 fogColor; +uniform vec4 rippleMagnitude; +uniform vec4 rtParams1; +uniform float depthGradMax; +uniform vec3 inLightVec; +uniform mat4 modelMat; +uniform vec4 sunColor; +uniform float sunBrightness; +uniform float reflectivity; + +out vec4 OUT_col; + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +void main() +{ + // Get the bumpNorm... + vec3 bumpNorm = ( texture( bumpMap, IN_rippleTexCoord01.xy ).rgb * 2.0 - 1.0 ) * rippleMagnitude.x; + bumpNorm += ( texture( bumpMap, IN_rippleTexCoord01.zw ).rgb * 2.0 - 1.0 ) * rippleMagnitude.y; + bumpNorm += ( texture( bumpMap, IN_rippleTexCoord2.xy ).rgb * 2.0 - 1.0 ) * rippleMagnitude.z; + + bumpNorm = normalize( bumpNorm ); + bumpNorm = mix( bumpNorm, vec3(0,0,1), 1.0 - rippleMagnitude.w ); + bumpNorm = tMul( bumpNorm, IN_tangentMat ); + + // Get depth of the water surface (this pixel). + // Convert from WorldSpace to EyeSpace. + float pixelDepth = PIXEL_DIST / farPlaneDist; + + vec2 deferredCoord = viewportCoordToRenderTarget( IN_posPostWave, rtParams1 ); + + float startDepth = deferredUncondition( deferredTex, deferredCoord ).w; + + // The water depth in world units of the undistorted pixel. + float startDelta = ( startDepth - pixelDepth ); + startDelta = max( startDelta, 0.0 ); + startDelta *= farPlaneDist; + + // Calculate the distortion amount for the water surface. + // + // We subtract a little from it so that we don't + // distort where the water surface intersects the + // camera near plane. + float distortAmt = saturate( ( PIXEL_DIST - DISTORT_START_DIST ) / DISTORT_END_DIST ); + + // Scale down distortion in shallow water. + distortAmt *= saturate( startDelta / DISTORT_FULL_DEPTH ); + + // Do the intial distortion... we might remove it below. + vec2 distortDelta = bumpNorm.xy * distortAmt; + vec4 distortPos = IN_posPostWave; + distortPos.xy += distortDelta; + + deferredCoord = viewportCoordToRenderTarget( distortPos, rtParams1 ); + + // Get deferred depth at the position of this distorted pixel. + float deferredDepth = deferredUncondition( deferredTex, deferredCoord ).w; + if ( deferredDepth > 0.99 ) + deferredDepth = 5.0; + + float delta = ( deferredDepth - pixelDepth ) * farPlaneDist; + + if ( delta < 0.0 ) + { + // If we got a negative delta then the distorted + // sample is above the water surface. Mask it out + // by removing the distortion. + distortPos = IN_posPostWave; + delta = startDelta; + distortAmt = 0; + } + else + { + float diff = ( deferredDepth - startDepth ) * farPlaneDist; + + if ( diff < 0 ) + { + distortAmt = saturate( ( PIXEL_DIST - DISTORT_START_DIST ) / DISTORT_END_DIST ); + distortAmt *= saturate( delta / DISTORT_FULL_DEPTH ); + + distortDelta = bumpNorm.xy * distortAmt; + + distortPos = IN_posPostWave; + distortPos.xy += distortDelta; + + deferredCoord = viewportCoordToRenderTarget( distortPos, rtParams1 ); + + // Get deferred depth at the position of this distorted pixel. + deferredDepth = deferredUncondition( deferredTex, deferredCoord ).w; + if ( deferredDepth > 0.99 ) + deferredDepth = 5.0; + delta = ( deferredDepth - pixelDepth ) * farPlaneDist; + } + + if ( delta < 0.1 ) + { + // If we got a negative delta then the distorted + // sample is above the water surface. Mask it out + // by removing the distortion. + distortPos = IN_posPostWave; + delta = startDelta; + distortAmt = 0; + } + } + + vec4 temp = IN_posPreWave; + temp.xy += bumpNorm.xy * distortAmt; + vec2 reflectCoord = viewportCoordToRenderTarget( temp, rtParams1 ); + + vec2 refractCoord = viewportCoordToRenderTarget( distortPos, rtParams1 ); + + vec4 fakeColor = vec4(ambientColor,1); + vec3 eyeVec = IN_objPos.xyz - eyePos; + eyeVec = tMul( mat3(modelMat), eyeVec ); + eyeVec = tMul( IN_tangentMat, eyeVec ); + vec3 reflectionVec = reflect( eyeVec, bumpNorm ); + + // Use fakeColor for ripple-normals that are angled towards the camera + eyeVec = -eyeVec; + eyeVec = normalize( eyeVec ); + float ang = saturate( dot( eyeVec, bumpNorm ) ); + float fakeColorAmt = ang; + + // for verts far from the reflect plane z position + float rplaneDist = abs( REFLECT_PLANE_Z - IN_objPos.w ); + rplaneDist = saturate( ( rplaneDist - 1.0 ) / 2.0 ); + rplaneDist *= ISRIVER; + fakeColorAmt = max( fakeColorAmt, rplaneDist ); + +#ifndef UNDERWATER + + // Get foam color and amount + vec2 foamRippleOffset = bumpNorm.xy * FOAM_RIPPLE_INFLUENCE; + vec4 IN_foamTexCoords = IN_foamTexCoords; + IN_foamTexCoords.xy += foamRippleOffset; + IN_foamTexCoords.zw += foamRippleOffset; + + vec4 foamColor = texture( foamMap, IN_foamTexCoords.xy ); + foamColor += texture( foamMap, IN_foamTexCoords.zw ); + foamColor = saturate( foamColor ); + + // Modulate foam color by ambient color + // so we don't have glowing white foam at night. + foamColor.rgb = mix( foamColor.rgb, ambientColor.rgb, FOAM_AMBIENT_LERP ); + + float foamDelta = saturate( delta / FOAM_MAX_DEPTH ); + float foamAmt = 1 - pow( foamDelta, 2 ); + + // Fade out the foam in very very low depth, + // this improves the shoreline a lot. + float diff = 0.8 - foamAmt; + if ( diff < 0.0 ) + foamAmt -= foamAmt * abs( diff ) / 0.2; + + foamAmt *= FOAM_OPACITY * foamColor.a; + + foamColor.rgb *= FOAM_OPACITY * foamAmt * foamColor.a; + + // Get reflection map color. + vec4 refMapColor = texture( reflectMap, reflectCoord ); + + // If we do not have a reflection texture then we use the cubemap. + refMapColor = mix( refMapColor, texture( skyMap, reflectionVec ), NO_REFLECT ); + + fakeColor = ( texture( skyMap, reflectionVec ) ); + fakeColor.a = 1; + // Combine reflection color and fakeColor. + vec4 reflectColor = mix( refMapColor, fakeColor, fakeColorAmt ); + + // Get refract color + vec4 refractColor = hdrDecode( texture( refractBuff, refractCoord ) ); + + // We darken the refraction color a bit to make underwater + // elements look wet. We fade out this darkening near the + // surface in order to not have hard water edges. + // @param WET_DEPTH The depth in world units at which full darkening will be recieved. + // @param WET_COLOR_FACTOR The refract color is scaled down by this amount when at WET_DEPTH + refractColor.rgb *= 1.0f - ( saturate( delta / WET_DEPTH ) * WET_COLOR_FACTOR ); + + // Add Water fog/haze. + float fogDelta = delta - FOG_DENSITY_OFFSET; + + if ( fogDelta < 0.0 ) + fogDelta = 0.0; + float fogAmt = 1.0 - saturate( exp( -FOG_DENSITY * fogDelta ) ); + + // Calculate the water "base" color based on depth. + vec4 waterBaseColor = baseColor * texture( depthGradMap, saturate( delta / depthGradMax ) ); + + // Modulate baseColor by the ambientColor. + waterBaseColor *= vec4( ambientColor.rgb, 1 ); + + // calc "diffuse" color by lerping from the water color + // to refraction image based on the water clarity. + vec4 diffuseColor = mix( refractColor, waterBaseColor, fogAmt ); + + // fresnel calculation + float fresnelTerm = fresnel( ang, FRESNEL_BIAS, FRESNEL_POWER ); + + // Scale the frensel strength by fog amount + // so that parts that are very clear get very little reflection. + fresnelTerm *= fogAmt; + + // Also scale the frensel by our distance to the + // water surface. This removes the hard reflection + // when really close to the water surface. + fresnelTerm *= saturate( PIXEL_DIST - 0.1 ); + + fresnelTerm *= reflectivity; + + // Combine the diffuse color and reflection image via the + // fresnel term and set out output color. + vec4 OUT = mix( diffuseColor, reflectColor, fresnelTerm ); + + vec3 lightVec = inLightVec; + + // Get some specular reflection. + vec3 newbump = bumpNorm; + newbump.xy *= 3.5; + newbump = normalize( newbump ); + vec3 halfAng = normalize( eyeVec + -lightVec ); + float specular = saturate( dot( newbump, halfAng ) ); + specular = pow( specular, SPEC_POWER ); + + // Scale down specularity in very shallow water to improve the transparency of the shoreline. + specular *= saturate( delta / 2 ); + OUT.rgb = OUT.rgb + ( SPEC_COLOR * vec3(specular) ); + +#else + + vec4 refractColor = hdrDecode( texture( refractBuff, refractCoord ) ); + vec4 OUT = refractColor; + +#endif + +#ifndef UNDERWATER + + OUT.rgb = OUT.rgb + foamColor.rgb; + + float factor = computeSceneFog( eyePos, + IN_objPos.xyz, + IN_objPos.w, + fogData.x, + fogData.y, + fogData.z ); + + OUT.rgb = mix( OUT.rgb, fogColor.rgb, 1.0 - saturate( factor ) ); + + //OUT.rgb = fogColor.rgb; + +#endif + + OUT.a = 1.0; + + //return OUT; + + OUT_col = hdrEncode( OUT ); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/water/gl/waterV.glsl b/Templates/BaseGame/game/core/rendering/shaders/water/gl/waterV.glsl new file mode 100644 index 000000000..490af63a7 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/water/gl/waterV.glsl @@ -0,0 +1,241 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../../gl/hlslCompat.glsl" +#include "shadergen:/autogenConditioners.h" + +//----------------------------------------------------------------------------- +// Structures +//----------------------------------------------------------------------------- +struct VertData +{ + vec4 position ;// POSITION; + vec3 normal ;// NORMAL; + vec2 undulateData ;// TEXCOORD0; + vec4 horizonFactor ;// TEXCOORD1; +}; + +//----------------------------------------------------------------------------- +// Defines +//----------------------------------------------------------------------------- +//VertData IN +in vec4 vPosition; +in vec3 vNormal; +in vec2 vTexCoord0; +in vec4 vTexCoord1; + +#define IN_position_ vPosition +#define IN_normal vNormal +#define IN_undulateData vTexCoord0 +#define IN_horizonFactor vTexCoord1 + +//ConnectData OUT +// + out vec4 hpos ; + +// TexCoord 0 and 1 (xy,zw) for ripple texture lookup +out vec4 rippleTexCoord01; + + // xy is TexCoord 2 for ripple texture lookup + // z is the Worldspace unit distance/depth of this vertex/pixel + // w is amount of the crestFoam ( more at crest of waves ). + out vec4 rippleTexCoord2 ; + +// Screenspace vert position BEFORE wave transformation +out vec4 posPreWave; + +// Screenspace vert position AFTER wave transformation +out vec4 posPostWave; + + // Objectspace vert position BEFORE wave transformation + // w coord is world space z position. + out vec4 objPos ; + + out vec4 foamTexCoords ; + + out mat3 tangentMat ; +// + +#define OUT_hpos hpos +#define OUT_rippleTexCoord01 rippleTexCoord01 +#define OUT_rippleTexCoord2 rippleTexCoord2 +#define OUT_posPreWave posPreWave +#define OUT_posPostWave posPostWave +#define OUT_objPos objPos +#define OUT_foamTexCoords foamTexCoords +#define OUT_tangentMat tangentMat + +//----------------------------------------------------------------------------- +// Uniforms +//----------------------------------------------------------------------------- +uniform mat4 modelMat; +uniform mat4 modelview; +uniform vec4 rippleMat[3]; +uniform vec3 eyePos; +uniform vec2 waveDir[3]; +uniform vec2 waveData[3]; +uniform vec2 rippleDir[3]; +uniform vec2 rippleTexScale[3]; +uniform vec3 rippleSpeed; +uniform vec4 foamDir; +uniform vec4 foamTexScale; +uniform vec2 foamSpeed; +uniform vec3 inLightVec; +uniform float gridElementSize; +uniform float elapsedTime; +uniform float undulateMaxDist; + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +void main() +{ + vec4 IN_position = IN_position_; + + // use projection matrix for reflection / refraction texture coords + mat4 texGen = mat4FromRow( 0.5, 0.0, 0.0, 0.5, + 0.0, -0.5, 0.0, 0.5, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0 ); + + IN_position.z = mix( IN_position.z, eyePos.z, IN_horizonFactor.x ); + + OUT_objPos = IN_position; + OUT_objPos.w = tMul( modelMat, IN_position ).z; + + // Send pre-undulation screenspace position + OUT_posPreWave = tMul( modelview, IN_position ); + OUT_posPreWave = tMul( texGen, OUT_posPreWave ); + + // Calculate the undulation amount for this vertex. + vec2 undulatePos = tMul( modelMat, vec4 ( IN_undulateData.xy, 0, 1 ) ).xy; + float undulateAmt = 0.0; + + undulateAmt += waveData[0].y * sin( elapsedTime * waveData[0].x + + undulatePos.x * waveDir[0].x + + undulatePos.y * waveDir[0].y ); + undulateAmt += waveData[1].y * sin( elapsedTime * waveData[1].x + + undulatePos.x * waveDir[1].x + + undulatePos.y * waveDir[1].y ); + undulateAmt += waveData[2].y * sin( elapsedTime * waveData[2].x + + undulatePos.x * waveDir[2].x + + undulatePos.y * waveDir[2].y ); + + float undulateFade = 1; + + // Scale down wave magnitude amount based on distance from the camera. + float dist = distance( IN_position.xyz, eyePos ); + dist = clamp( dist, 1.0, undulateMaxDist ); + undulateFade *= ( 1 - dist / undulateMaxDist ); + + // Also scale down wave magnitude if the camera is very very close. + undulateFade *= saturate( ( distance( IN_position.xyz, eyePos ) - 0.5 ) / 10.0 ); + + undulateAmt *= undulateFade; + + OUT_rippleTexCoord2.w = undulateAmt / ( waveData[0].y + waveData[1].y + waveData[2].y ); + OUT_rippleTexCoord2.w = saturate( OUT_rippleTexCoord2.w - 0.2 ) / 0.8; + + // Apply wave undulation to the vertex. + OUT_posPostWave = IN_position; + OUT_posPostWave.xyz += IN_normal.xyz * undulateAmt; + + // Convert to screen + OUT_posPostWave = tMul( modelview, OUT_posPostWave ); + + // Setup the OUT position symantic variable + OUT_hpos = OUT_posPostWave; + //OUT_hpos.z = mix( OUT_hpos.z, OUT_hpos.w, IN_horizonFactor.x ); + + // if ( IN_horizonFactor.x > 0 ) + // { + // vec3 awayVec = normalize( OUT_objPos.xyz - eyePos ); + // OUT_objPos.xy += awayVec.xy * 1000.0; + // } + + // Save world space camera dist/depth of the outgoing pixel + OUT_rippleTexCoord2.z = OUT_hpos.z; + + // Convert to reflection texture space + OUT_posPostWave = tMul( texGen, OUT_posPostWave ); + + vec2 txPos = undulatePos; + if ( bool(IN_horizonFactor.x) ) + txPos = normalize( txPos ) * 50000.0; + + // set up tex coordinates for the 3 interacting normal maps + OUT_rippleTexCoord01.xy = txPos * rippleTexScale[0]; + OUT_rippleTexCoord01.xy += rippleDir[0] * elapsedTime * rippleSpeed.x; + + mat2 texMat; + texMat[0][0] = rippleMat[0].x; + texMat[1][0] = rippleMat[0].y; + texMat[0][1] = rippleMat[0].z; + texMat[1][1] = rippleMat[0].w; + OUT_rippleTexCoord01.xy = tMul( texMat, OUT_rippleTexCoord01.xy ); + + OUT_rippleTexCoord01.zw = txPos * rippleTexScale[1]; + OUT_rippleTexCoord01.zw += rippleDir[1] * elapsedTime * rippleSpeed.y; + + texMat[0][0] = rippleMat[1].x; + texMat[1][0] = rippleMat[1].y; + texMat[0][1] = rippleMat[1].z; + texMat[1][1] = rippleMat[1].w; + OUT_rippleTexCoord01.zw = tMul( texMat, OUT_rippleTexCoord01.zw ); + + OUT_rippleTexCoord2.xy = txPos * rippleTexScale[2]; + OUT_rippleTexCoord2.xy += rippleDir[2] * elapsedTime * rippleSpeed.z; + + texMat[0][0] = rippleMat[2].x; + texMat[1][0] = rippleMat[2].y; + texMat[0][1] = rippleMat[2].z; + texMat[1][1] = rippleMat[2].w; + OUT_rippleTexCoord2.xy = tMul( texMat, OUT_rippleTexCoord2.xy ); + + OUT_foamTexCoords.xy = txPos * foamTexScale.xy + foamDir.xy * foamSpeed.x * elapsedTime; + OUT_foamTexCoords.zw = txPos * foamTexScale.zw + foamDir.zw * foamSpeed.y * elapsedTime; + + + vec3 binormal = vec3 ( 1, 0, 0 ); + vec3 tangent = vec3 ( 0, 1, 0 ); + vec3 normal; + for ( int i = 0; i < 3; i++ ) + { + binormal.z += undulateFade * waveDir[i].x * waveData[i].y * cos( waveDir[i].x * undulatePos.x + waveDir[i].y * undulatePos.y + elapsedTime * waveData[i].x ); + tangent.z += undulateFade * waveDir[i].y * waveData[i].y * cos( waveDir[i].x * undulatePos.x + waveDir[i].y * undulatePos.y + elapsedTime * waveData[i].x ); + } + + binormal = binormal; + tangent = tangent; + normal = cross( binormal, tangent ); + + mat3 worldToTangent; + worldToTangent[0] = binormal; + worldToTangent[1] = tangent; + worldToTangent[2] = normal; + + OUT_tangentMat = transpose(worldToTangent); + + gl_Position = OUT_hpos; + correctSSP(gl_Position); +} + diff --git a/Templates/BaseGame/game/core/rendering/shaders/water/waterBasicP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/water/waterBasicP.hlsl new file mode 100644 index 000000000..9cacfdf7a --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/water/waterBasicP.hlsl @@ -0,0 +1,213 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../torque.hlsl" + +//----------------------------------------------------------------------------- +// Defines +//----------------------------------------------------------------------------- + +// miscParams +#define FRESNEL_BIAS miscParams[0] +#define FRESNEL_POWER miscParams[1] +#define CLARITY miscParams[2] +#define ISRIVER miscParams[3] + +// reflectParams +#define REFLECT_PLANE_Z reflectParams[0] +#define REFLECT_MIN_DIST reflectParams[1] +#define REFLECT_MAX_DIST reflectParams[2] +#define NO_REFLECT reflectParams[3] + +// distortionParams +#define DISTORT_START_DIST distortionParams[0] +#define DISTORT_END_DIST distortionParams[1] +#define DISTORT_FULL_DEPTH distortionParams[2] + +// ConnectData.misc +#define LIGHT_VEC IN.misc.xyz +#define WORLD_Z IN.objPos.w + +// specularParams +#define SPEC_POWER specularParams[3] +#define SPEC_COLOR specularParams.xyz + +//----------------------------------------------------------------------------- +// Structures +//----------------------------------------------------------------------------- + +struct ConnectData +{ + float4 hpos : TORQUE_POSITION; + + // TexCoord 0 and 1 (xy,zw) for ripple texture lookup + float4 rippleTexCoord01 : TEXCOORD0; + + // TexCoord 2 for ripple texture lookup + float2 rippleTexCoord2 : TEXCOORD1; + + // Screenspace vert position BEFORE wave transformation + float4 posPreWave : TEXCOORD2; + + // Screenspace vert position AFTER wave transformation + float4 posPostWave : TEXCOORD3; + + // Worldspace unit distance/depth of this vertex/pixel + float pixelDist : TEXCOORD4; + + // Objectspace vert position BEFORE wave transformation + // w coord is world space z position. + float4 objPos : TEXCOORD5; + + float3 misc : TEXCOORD6; +}; + +//----------------------------------------------------------------------------- +// approximate Fresnel function +//----------------------------------------------------------------------------- +float fresnel(float NdotV, float bias, float power) +{ + return bias + (1.0-bias)*pow(abs(1.0 - max(NdotV, 0)), power); +} + +//----------------------------------------------------------------------------- +// Uniforms +//----------------------------------------------------------------------------- +TORQUE_UNIFORM_SAMPLER2D(bumpMap,0); +//uniform sampler2D deferredTex : register( S1 ); +TORQUE_UNIFORM_SAMPLER2D(reflectMap,2); +TORQUE_UNIFORM_SAMPLER2D(refractBuff,3); +TORQUE_UNIFORM_SAMPLERCUBE(skyMap,4); +//uniform sampler foamMap : register( S5 ); +uniform float4 baseColor; +uniform float4 miscParams; +uniform float4 reflectParams; +uniform float3 ambientColor; +uniform float3 eyePos; +uniform float3 distortionParams; +uniform float3 fogData; +uniform float4 fogColor; +uniform float4 rippleMagnitude; +uniform float4 specularParams; +uniform float4x4 modelMat; + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +float4 main( ConnectData IN ) : TORQUE_TARGET0 +{ + // Modulate baseColor by the ambientColor. + float4 waterBaseColor = baseColor * float4( ambientColor.rgb, 1 ); + + // Get the bumpNorm... + float3 bumpNorm = ( TORQUE_TEX2D( bumpMap, IN.rippleTexCoord01.xy ).rgb * 2.0 - 1.0 ) * rippleMagnitude.x; + bumpNorm += ( TORQUE_TEX2D( bumpMap, IN.rippleTexCoord01.zw ).rgb * 2.0 - 1.0 ) * rippleMagnitude.y; + bumpNorm += ( TORQUE_TEX2D( bumpMap, IN.rippleTexCoord2 ).rgb * 2.0 - 1.0 ) * rippleMagnitude.z; + + bumpNorm = normalize( bumpNorm ); + bumpNorm = lerp( bumpNorm, float3(0,0,1), 1.0 - rippleMagnitude.w ); + + // We subtract a little from it so that we don't + // distort where the water surface intersects the + // camera near plane. + float distortAmt = saturate( IN.pixelDist / 1.0 ) * 0.8; + + float4 distortPos = IN.posPostWave; + distortPos.xy += bumpNorm.xy * distortAmt; + + #ifdef UNDERWATER + return hdrEncode( TORQUE_TEX2DPROJ( refractBuff, distortPos ) ); + #else + + float3 eyeVec = IN.objPos.xyz - eyePos; + eyeVec = mul( (float3x3)modelMat, eyeVec ); + float3 reflectionVec = reflect( eyeVec, bumpNorm ); + + // Color that replaces the reflection color when we do not + // have one that is appropriate. + float4 fakeColor = float4(ambientColor,1); + + // Use fakeColor for ripple-normals that are angled towards the camera + eyeVec = -eyeVec; + eyeVec = normalize( eyeVec ); + float ang = saturate( dot( eyeVec, bumpNorm ) ); + float fakeColorAmt = ang; + + // Get reflection map color + float4 refMapColor = hdrDecode( TORQUE_TEX2DPROJ( reflectMap, distortPos ) ); + // If we do not have a reflection texture then we use the cubemap. + refMapColor = lerp( refMapColor, TORQUE_TEXCUBE( skyMap, reflectionVec ), NO_REFLECT ); + + // Combine reflection color and fakeColor. + float4 reflectColor = lerp( refMapColor, fakeColor, fakeColorAmt ); + //return refMapColor; + + // Get refract color + float4 refractColor = hdrDecode( TORQUE_TEX2DPROJ( refractBuff, distortPos ) ); + + // calc "diffuse" color by lerping from the water color + // to refraction image based on the water clarity. + float4 diffuseColor = lerp( refractColor, waterBaseColor, 1.0f - CLARITY ); + + // fresnel calculation + float fresnelTerm = fresnel( ang, FRESNEL_BIAS, FRESNEL_POWER ); + //return float4( fresnelTerm.rrr, 1 ); + + // Also scale the frensel by our distance to the + // water surface. This removes the hard reflection + // when really close to the water surface. + fresnelTerm *= saturate( IN.pixelDist - 0.1 ); + + // Combine the diffuse color and reflection image via the + // fresnel term and set out output color. + float4 OUT = lerp( diffuseColor, reflectColor, fresnelTerm ); + + #ifdef WATER_SPEC + + // Get some specular reflection. + float3 newbump = bumpNorm; + newbump.xy *= 3.5; + newbump = normalize( bumpNorm ); + half3 halfAng = normalize( eyeVec + -LIGHT_VEC ); + float specular = saturate( dot( newbump, halfAng ) ); + specular = pow( specular, SPEC_POWER ); + + OUT.rgb = OUT.rgb + ( SPEC_COLOR * specular.xxx ); + + #else // Disable fogging if spec is on because otherwise we run out of instructions. + + // Fog it. + float factor = computeSceneFog( eyePos, + IN.objPos.xyz, + WORLD_Z, + fogData.x, + fogData.y, + fogData.z ); + + //OUT.rgb = lerp( OUT.rgb, fogColor.rgb, 1.0 - saturate( factor ) ); + + #endif + + return hdrEncode( OUT ); + +#endif +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/water/waterBasicV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/water/waterBasicV.hlsl new file mode 100644 index 000000000..310647c90 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/water/waterBasicV.hlsl @@ -0,0 +1,237 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../shaderModel.hlsl" +//----------------------------------------------------------------------------- +// Structures +//----------------------------------------------------------------------------- +struct VertData +{ + float3 position : POSITION; + float3 normal : NORMAL; + float2 undulateData : TEXCOORD0; + float4 horizonFactor : TEXCOORD1; +}; + +struct ConnectData +{ + float4 hpos : TORQUE_POSITION; + + // TexCoord 0 and 1 (xy,zw) for ripple texture lookup + float4 rippleTexCoord01 : TEXCOORD0; + + // TexCoord 2 for ripple texture lookup + float2 rippleTexCoord2 : TEXCOORD1; + + // Screenspace vert position BEFORE wave transformation + float4 posPreWave : TEXCOORD2; + + // Screenspace vert position AFTER wave transformation + float4 posPostWave : TEXCOORD3; + + // Worldspace unit distance/depth of this vertex/pixel + float pixelDist : TEXCOORD4; + + // Objectspace vert position BEFORE wave transformation + // w coord is world space z position. + float4 objPos : TEXCOORD5; + + float3 misc : TEXCOORD6; +}; + +//----------------------------------------------------------------------------- +// Uniforms +//----------------------------------------------------------------------------- +uniform float4x4 modelMat; +uniform float4x4 modelview; +uniform float4 rippleMat[3]; +uniform float3 eyePos; +uniform float2 waveDir[3]; +uniform float2 waveData[3]; +uniform float2 rippleDir[3]; +uniform float2 rippleTexScale[3]; +uniform float3 rippleSpeed; +uniform float3 inLightVec; +uniform float3 reflectNormal; +uniform float gridElementSize; +uniform float elapsedTime; +uniform float undulateMaxDist; + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +ConnectData main( VertData IN ) +{ + ConnectData OUT; + + // use projection matrix for reflection / refraction texture coords + float4x4 texGen = { 0.5, 0.0, 0.0, 0.5, + 0.0, -0.5, 0.0, 0.5, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0 }; + + // Move the vertex based on the horizonFactor if specified to do so for this vert. + // if ( IN.horizonFactor.z > 0 ) + // { + // float2 offsetXY = eyePos.xy - eyePos.xy % gridElementSize; + // IN.position.xy += offsetXY; + // IN.undulateData += offsetXY; + // } + float4 inPos = float4(IN.position, 1.0); + float4 worldPos = mul(modelMat, inPos); + + IN.position.z = lerp( IN.position.z, eyePos.z, IN.horizonFactor.x ); + + //OUT.objPos = worldPos; + OUT.objPos.xyz = IN.position; + OUT.objPos.w = worldPos.z; + + // Send pre-undulation screenspace position + OUT.posPreWave = mul( modelview, inPos ); + OUT.posPreWave = mul( texGen, OUT.posPreWave ); + + // Calculate the undulation amount for this vertex. + float2 undulatePos = mul( modelMat, float4( IN.undulateData.xy, 0, 1 )).xy; + //if ( undulatePos.x < 0 ) + // undulatePos = IN.position.xy; + + float undulateAmt = 0.0; + + undulateAmt += waveData[0].y * sin( elapsedTime * waveData[0].x + + undulatePos.x * waveDir[0].x + + undulatePos.y * waveDir[0].y ); + undulateAmt += waveData[1].y * sin( elapsedTime * waveData[1].x + + undulatePos.x * waveDir[1].x + + undulatePos.y * waveDir[1].y ); + undulateAmt += waveData[2].y * sin( elapsedTime * waveData[2].x + + undulatePos.x * waveDir[2].x + + undulatePos.y * waveDir[2].y ); + + float undulateFade = 1; + + // Scale down wave magnitude amount based on distance from the camera. + float dist = distance( IN.position, eyePos ); + dist = clamp( dist, 1.0, undulateMaxDist ); + undulateFade *= ( 1 - dist / undulateMaxDist ); + + // Also scale down wave magnitude if the camera is very very close. + undulateFade *= saturate( ( distance( IN.position, eyePos ) - 0.5 ) / 10.0 ); + + undulateAmt *= undulateFade; + + //#endif + //undulateAmt = 0; + + // Apply wave undulation to the vertex. + OUT.posPostWave = inPos; + OUT.posPostWave.xyz += IN.normal.xyz * undulateAmt; + + // Save worldSpace position of this pixel/vert + //OUT.worldPos = OUT.posPostWave.xyz; + //OUT.worldPos = mul( modelMat, OUT.posPostWave.xyz ); + //OUT.worldPos.z += objTrans[2][2]; //91.16; + + // OUT.misc.w = mul( modelMat, OUT.fogPos ).z; + // if ( IN.horizonFactor.x > 0 ) + // { + // float3 awayVec = normalize( OUT.fogPos.xyz - eyePos ); + // OUT.fogPos.xy += awayVec.xy * 1000.0; + // } + + // Convert to screen + OUT.posPostWave = mul( modelview, OUT.posPostWave ); // mul( modelview, float4( OUT.posPostWave.xyz, 1 ) ); + + // Setup the OUT position symantic variable + OUT.hpos = OUT.posPostWave; // mul( modelview, float4( IN.position.xyz, 1 ) ); //float4( OUT.posPostWave.xyz, 1 ); + //OUT.hpos.z = lerp( OUT.hpos.z, OUT.hpos.w, IN.horizonFactor.x ); + + // Save world space camera dist/depth of the outgoing pixel + OUT.pixelDist = OUT.hpos.z; + + // Convert to reflection texture space + OUT.posPostWave = mul( texGen, OUT.posPostWave ); + + float2 txPos = undulatePos; + if ( IN.horizonFactor.x ) + txPos = normalize( txPos ) * 50000.0; + + // set up tex coordinates for the 3 interacting normal maps + OUT.rippleTexCoord01.xy = txPos * rippleTexScale[0]; + OUT.rippleTexCoord01.xy += rippleDir[0] * elapsedTime * rippleSpeed.x; + + float2x2 texMat; + texMat[0][0] = rippleMat[0].x; + texMat[0][1] = rippleMat[0].y; + texMat[1][0] = rippleMat[0].z; + texMat[1][1] = rippleMat[0].w; + OUT.rippleTexCoord01.xy = mul( texMat, OUT.rippleTexCoord01.xy ); + + OUT.rippleTexCoord01.zw = txPos * rippleTexScale[1]; + OUT.rippleTexCoord01.zw += rippleDir[1] * elapsedTime * rippleSpeed.y; + + texMat[0][0] = rippleMat[1].x; + texMat[0][1] = rippleMat[1].y; + texMat[1][0] = rippleMat[1].z; + texMat[1][1] = rippleMat[1].w; + OUT.rippleTexCoord01.zw = mul( texMat, OUT.rippleTexCoord01.zw ); + + OUT.rippleTexCoord2.xy = txPos * rippleTexScale[2]; + OUT.rippleTexCoord2.xy += rippleDir[2] * elapsedTime * rippleSpeed.z; + + texMat[0][0] = rippleMat[2].x; + texMat[0][1] = rippleMat[2].y; + texMat[1][0] = rippleMat[2].z; + texMat[1][1] = rippleMat[2].w; + OUT.rippleTexCoord2.xy = mul( texMat, OUT.rippleTexCoord2.xy ); + +#ifdef WATER_SPEC + + float3 binormal = float3( 1, 0, 0 ); + float3 tangent = float3( 0, 1, 0 ); + float3 normal; + for ( int i = 0; i < 3; i++ ) + { + binormal.z += undulateFade * waveDir[i].x * waveData[i].y * cos( waveDir[i].x * IN.undulateData.x + waveDir[i].y * IN.undulateData.y + elapsedTime * waveData[i].x ); + tangent.z += undulateFade * waveDir[i].y * waveData[i].y * cos( waveDir[i].x * IN.undulateData.x + waveDir[i].y * IN.undulateData.y + elapsedTime * waveData[i].x ); + } + + binormal = normalize( binormal ); + tangent = normalize( tangent ); + normal = cross( binormal, tangent ); + + float3x3 worldToTangent; + worldToTangent[0] = binormal; + worldToTangent[1] = tangent; + worldToTangent[2] = normal; + + OUT.misc.xyz = mul( inLightVec, modelMat ); + OUT.misc.xyz = mul( worldToTangent, OUT.misc.xyz ); + +#else + + OUT.misc.xyz = inLightVec; + +#endif + + return OUT; +} + diff --git a/Templates/BaseGame/game/core/rendering/shaders/water/waterP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/water/waterP.hlsl new file mode 100644 index 000000000..59bdad05d --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/water/waterP.hlsl @@ -0,0 +1,383 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../shaderModelAutoGen.hlsl" +#include "../torque.hlsl" + +//----------------------------------------------------------------------------- +// Defines +//----------------------------------------------------------------------------- + +#define PIXEL_DIST IN.rippleTexCoord2.z +// miscParams +#define FRESNEL_BIAS miscParams[0] +#define FRESNEL_POWER miscParams[1] +// miscParams[2] is unused +#define ISRIVER miscParams[3] + +// reflectParams +#define REFLECT_PLANE_Z reflectParams[0] +#define REFLECT_MIN_DIST reflectParams[1] +#define REFLECT_MAX_DIST reflectParams[2] +#define NO_REFLECT reflectParams[3] + +// fogParams +#define FOG_DENSITY fogParams[0] +#define FOG_DENSITY_OFFSET fogParams[1] + +// wetnessParams +#define WET_DEPTH wetnessParams[0] +#define WET_COLOR_FACTOR wetnessParams[1] + +// distortionParams +#define DISTORT_START_DIST distortionParams[0] +#define DISTORT_END_DIST distortionParams[1] +#define DISTORT_FULL_DEPTH distortionParams[2] + +// foamParams +#define FOAM_OPACITY foamParams[0] +#define FOAM_MAX_DEPTH foamParams[1] +#define FOAM_AMBIENT_LERP foamParams[2] +#define FOAM_RIPPLE_INFLUENCE foamParams[3] + +// specularParams +#define SPEC_POWER specularParams[3] +#define SPEC_COLOR specularParams.xyz + +//----------------------------------------------------------------------------- +// Structures +//----------------------------------------------------------------------------- + +struct ConnectData +{ + float4 hpos : TORQUE_POSITION; + + // TexCoord 0 and 1 (xy,zw) for ripple texture lookup + float4 rippleTexCoord01 : TEXCOORD0; + + // xy is TexCoord 2 for ripple texture lookup + // z is the Worldspace unit distance/depth of this vertex/pixel + // w is amount of the crestFoam ( more at crest of waves ). + float4 rippleTexCoord2 : TEXCOORD1; + + // Screenspace vert position BEFORE wave transformation + float4 posPreWave : TEXCOORD2; + + // Screenspace vert position AFTER wave transformation + float4 posPostWave : TEXCOORD3; + + // Objectspace vert position BEFORE wave transformation + // w coord is world space z position. + float4 objPos : TEXCOORD4; + + float4 foamTexCoords : TEXCOORD5; + + float3x3 tangentMat : TEXCOORD6; +}; + +//----------------------------------------------------------------------------- +// approximate Fresnel function +//----------------------------------------------------------------------------- +float fresnel(float NdotV, float bias, float power) +{ + return bias + (1.0-bias)*pow(abs(1.0 - max(NdotV, 0)), power); +} + +//----------------------------------------------------------------------------- +// Uniforms +//----------------------------------------------------------------------------- +TORQUE_UNIFORM_SAMPLER2D(bumpMap,0); +TORQUE_UNIFORM_SAMPLER2D(deferredTex, 1); +TORQUE_UNIFORM_SAMPLER2D(reflectMap, 2); +TORQUE_UNIFORM_SAMPLER2D(refractBuff, 3); +TORQUE_UNIFORM_SAMPLERCUBE(skyMap, 4); +TORQUE_UNIFORM_SAMPLER2D(foamMap, 5); +TORQUE_UNIFORM_SAMPLER1D(depthGradMap, 6); +uniform float4 specularParams; +uniform float4 baseColor; +uniform float4 miscParams; +uniform float2 fogParams; +uniform float4 reflectParams; +uniform float3 reflectNormal; +uniform float2 wetnessParams; +uniform float farPlaneDist; +uniform float3 distortionParams; +uniform float4 foamParams; +uniform float3 ambientColor; +uniform float3 eyePos; // This is in object space! +uniform float3 fogData; +uniform float4 fogColor; +uniform float4 rippleMagnitude; +uniform float4 rtParams1; +uniform float depthGradMax; +uniform float3 inLightVec; +uniform float4x4 modelMat; +uniform float4 sunColor; +uniform float sunBrightness; +uniform float reflectivity; + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +float4 main( ConnectData IN ) : TORQUE_TARGET0 +{ + // Get the bumpNorm... + float3 bumpNorm = ( TORQUE_TEX2D( bumpMap, IN.rippleTexCoord01.xy ).rgb * 2.0 - 1.0 ) * rippleMagnitude.x; + bumpNorm += ( TORQUE_TEX2D( bumpMap, IN.rippleTexCoord01.zw ).rgb * 2.0 - 1.0 ) * rippleMagnitude.y; + bumpNorm += ( TORQUE_TEX2D( bumpMap, IN.rippleTexCoord2.xy ).rgb * 2.0 - 1.0 ) * rippleMagnitude.z; + + bumpNorm = normalize( bumpNorm ); + bumpNorm = lerp( bumpNorm, float3(0,0,1), 1.0 - rippleMagnitude.w ); + bumpNorm = mul( bumpNorm, IN.tangentMat ); + + // Get depth of the water surface (this pixel). + // Convert from WorldSpace to EyeSpace. + float pixelDepth = PIXEL_DIST / farPlaneDist; + + float2 deferredCoord = viewportCoordToRenderTarget( IN.posPostWave, rtParams1 ); + + float startDepth = TORQUE_DEFERRED_UNCONDITION( deferredTex, deferredCoord ).w; + + // The water depth in world units of the undistorted pixel. + float startDelta = ( startDepth - pixelDepth ); + startDelta = max( startDelta, 0.0 ); + startDelta *= farPlaneDist; + + // Calculate the distortion amount for the water surface. + // + // We subtract a little from it so that we don't + // distort where the water surface intersects the + // camera near plane. + float distortAmt = saturate( ( PIXEL_DIST - DISTORT_START_DIST ) / DISTORT_END_DIST ); + + // Scale down distortion in shallow water. + distortAmt *= saturate( startDelta / DISTORT_FULL_DEPTH ); + + // Do the intial distortion... we might remove it below. + float2 distortDelta = bumpNorm.xy * distortAmt; + float4 distortPos = IN.posPostWave; + distortPos.xy += distortDelta; + + deferredCoord = viewportCoordToRenderTarget( distortPos, rtParams1 ); + + // Get deferred depth at the position of this distorted pixel. + float deferredDepth = TORQUE_DEFERRED_UNCONDITION( deferredTex, deferredCoord ).w; + if ( deferredDepth > 0.99 ) + deferredDepth = 5.0; + + float delta = ( deferredDepth - pixelDepth ) * farPlaneDist; + + if ( delta < 0.0 ) + { + // If we got a negative delta then the distorted + // sample is above the water surface. Mask it out + // by removing the distortion. + distortPos = IN.posPostWave; + delta = startDelta; + distortAmt = 0; + } + else + { + float diff = ( deferredDepth - startDepth ) * farPlaneDist; + + if ( diff < 0 ) + { + distortAmt = saturate( ( PIXEL_DIST - DISTORT_START_DIST ) / DISTORT_END_DIST ); + distortAmt *= saturate( delta / DISTORT_FULL_DEPTH ); + + distortDelta = bumpNorm.xy * distortAmt; + + distortPos = IN.posPostWave; + distortPos.xy += distortDelta; + + deferredCoord = viewportCoordToRenderTarget( distortPos, rtParams1 ); + + // Get deferred depth at the position of this distorted pixel. + deferredDepth = TORQUE_DEFERRED_UNCONDITION( deferredTex, deferredCoord ).w; + if ( deferredDepth > 0.99 ) + deferredDepth = 5.0; + delta = ( deferredDepth - pixelDepth ) * farPlaneDist; + } + + if ( delta < 0.1 ) + { + // If we got a negative delta then the distorted + // sample is above the water surface. Mask it out + // by removing the distortion. + distortPos = IN.posPostWave; + delta = startDelta; + distortAmt = 0; + } + } + + float4 temp = IN.posPreWave; + temp.xy += bumpNorm.xy * distortAmt; + float2 reflectCoord = viewportCoordToRenderTarget( temp, rtParams1 ); + + float2 refractCoord = viewportCoordToRenderTarget( distortPos, rtParams1 ); + + float4 fakeColor = float4(ambientColor,1); + float3 eyeVec = IN.objPos.xyz - eyePos; + eyeVec = mul( (float3x3)modelMat, eyeVec ); + eyeVec = mul( IN.tangentMat, eyeVec ); + float3 reflectionVec = reflect( eyeVec, bumpNorm ); + + // Use fakeColor for ripple-normals that are angled towards the camera + eyeVec = -eyeVec; + eyeVec = normalize( eyeVec ); + float ang = saturate( dot( eyeVec, bumpNorm ) ); + float fakeColorAmt = ang; + + // for verts far from the reflect plane z position + float rplaneDist = abs( REFLECT_PLANE_Z - IN.objPos.w ); + rplaneDist = saturate( ( rplaneDist - 1.0 ) / 2.0 ); + rplaneDist *= ISRIVER; + fakeColorAmt = max( fakeColorAmt, rplaneDist ); + +#ifndef UNDERWATER + + // Get foam color and amount + float2 foamRippleOffset = bumpNorm.xy * FOAM_RIPPLE_INFLUENCE; + IN.foamTexCoords.xy += foamRippleOffset; + IN.foamTexCoords.zw += foamRippleOffset; + + float4 foamColor = TORQUE_TEX2D( foamMap, IN.foamTexCoords.xy ); + foamColor += TORQUE_TEX2D( foamMap, IN.foamTexCoords.zw ); + foamColor = saturate( foamColor ); + + // Modulate foam color by ambient color + // so we don't have glowing white foam at night. + foamColor.rgb = lerp( foamColor.rgb, ambientColor.rgb, FOAM_AMBIENT_LERP ); + + float foamDelta = saturate( delta / FOAM_MAX_DEPTH ); + float foamAmt = 1 - pow( foamDelta, 2 ); + + // Fade out the foam in very very low depth, + // this improves the shoreline a lot. + float diff = 0.8 - foamAmt; + if ( diff < 0.0 ) + foamAmt -= foamAmt * abs( diff ) / 0.2; + + foamAmt *= FOAM_OPACITY * foamColor.a; + + foamColor.rgb *= FOAM_OPACITY * foamAmt * foamColor.a; + + // Get reflection map color. + float4 refMapColor = TORQUE_TEX2D( reflectMap, reflectCoord ); + + // If we do not have a reflection texture then we use the cubemap. + refMapColor = lerp( refMapColor, TORQUE_TEXCUBE( skyMap, reflectionVec ), NO_REFLECT ); + + fakeColor = ( TORQUE_TEXCUBE( skyMap, reflectionVec ) ); + fakeColor.a = 1; + // Combine reflection color and fakeColor. + float4 reflectColor = lerp( refMapColor, fakeColor, fakeColorAmt ); + + // Get refract color + float4 refractColor = hdrDecode( TORQUE_TEX2D( refractBuff, refractCoord ) ); + + // We darken the refraction color a bit to make underwater + // elements look wet. We fade out this darkening near the + // surface in order to not have hard water edges. + // @param WET_DEPTH The depth in world units at which full darkening will be recieved. + // @param WET_COLOR_FACTOR The refract color is scaled down by this amount when at WET_DEPTH + refractColor.rgb *= 1.0f - ( saturate( delta / WET_DEPTH ) * WET_COLOR_FACTOR ); + + // Add Water fog/haze. + float fogDelta = delta - FOG_DENSITY_OFFSET; + + if ( fogDelta < 0.0 ) + fogDelta = 0.0; + float fogAmt = 1.0 - saturate( exp( -FOG_DENSITY * fogDelta ) ); + + // Calculate the water "base" color based on depth. + float4 waterBaseColor = baseColor * TORQUE_TEX1D( depthGradMap, saturate( delta / depthGradMax ) ); + + // Modulate baseColor by the ambientColor. + waterBaseColor *= float4( ambientColor.rgb, 1 ); + + // calc "diffuse" color by lerping from the water color + // to refraction image based on the water clarity. + float4 diffuseColor = lerp( refractColor, waterBaseColor, fogAmt ); + + // fresnel calculation + float fresnelTerm = fresnel( ang, FRESNEL_BIAS, FRESNEL_POWER ); + + // Scale the frensel strength by fog amount + // so that parts that are very clear get very little reflection. + fresnelTerm *= fogAmt; + + // Also scale the frensel by our distance to the + // water surface. This removes the hard reflection + // when really close to the water surface. + fresnelTerm *= saturate( PIXEL_DIST - 0.1 ); + + fresnelTerm *= reflectivity; + + // Combine the diffuse color and reflection image via the + // fresnel term and set out output color. + float4 OUT = lerp( diffuseColor, reflectColor, fresnelTerm ); + + float3 lightVec = inLightVec; + + // Get some specular reflection. + float3 newbump = bumpNorm; + newbump.xy *= 3.5; + newbump = normalize( newbump ); + float3 halfAng = normalize( eyeVec + -lightVec ); + float specular = saturate( dot( newbump, halfAng ) ); + specular = pow( specular, SPEC_POWER ); + + // Scale down specularity in very shallow water to improve the transparency of the shoreline. + specular *= saturate( delta / 2 ); + OUT.rgb = OUT.rgb + ( SPEC_COLOR * specular.xxx ); + +#else + + float4 refractColor = hdrDecode( TORQUE_TEX2D( refractBuff, refractCoord ) ); + float4 OUT = refractColor; + +#endif + +#ifndef UNDERWATER + + OUT.rgb = OUT.rgb + foamColor.rgb; + + float factor = computeSceneFog( eyePos, + IN.objPos.xyz, + IN.objPos.w, + fogData.x, + fogData.y, + fogData.z ); + + OUT.rgb = lerp( OUT.rgb, fogColor.rgb, 1.0 - saturate( factor ) ); + + //OUT.rgb = fogColor.rgb; + +#endif + + OUT.a = 1.0; + + //return OUT; + + return hdrEncode( OUT ); +} diff --git a/Templates/BaseGame/game/core/rendering/shaders/water/waterV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/water/waterV.hlsl new file mode 100644 index 000000000..c869f0e9f --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/water/waterV.hlsl @@ -0,0 +1,216 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "../shaderModel.hlsl" + +//----------------------------------------------------------------------------- +// Structures +//----------------------------------------------------------------------------- +struct VertData +{ + float3 position : POSITION; + float3 normal : NORMAL; + float2 undulateData : TEXCOORD0; + float4 horizonFactor : TEXCOORD1; +}; + +struct ConnectData +{ + float4 hpos : TORQUE_POSITION; + + // TexCoord 0 and 1 (xy,zw) for ripple texture lookup + float4 rippleTexCoord01 : TEXCOORD0; + + // xy is TexCoord 2 for ripple texture lookup + // z is the Worldspace unit distance/depth of this vertex/pixel + // w is amount of the crestFoam ( more at crest of waves ). + float4 rippleTexCoord2 : TEXCOORD1; + + // Screenspace vert position BEFORE wave transformation + float4 posPreWave : TEXCOORD2; + + // Screenspace vert position AFTER wave transformation + float4 posPostWave : TEXCOORD3; + + // Objectspace vert position BEFORE wave transformation + // w coord is world space z position. + float4 objPos : TEXCOORD4; + + float4 foamTexCoords : TEXCOORD5; + + float3x3 tangentMat : TEXCOORD6; +}; + +//----------------------------------------------------------------------------- +// Uniforms +//----------------------------------------------------------------------------- +uniform float4x4 modelMat; +uniform float4x4 modelview; +uniform float4 rippleMat[3]; +uniform float3 eyePos; +uniform float2 waveDir[3]; +uniform float2 waveData[3]; +uniform float2 rippleDir[3]; +uniform float2 rippleTexScale[3]; +uniform float3 rippleSpeed; +uniform float4 foamDir; +uniform float4 foamTexScale; +uniform float2 foamSpeed; +uniform float3 inLightVec; +uniform float gridElementSize; +uniform float elapsedTime; +uniform float undulateMaxDist; + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +ConnectData main( VertData IN ) +{ + ConnectData OUT; + + // use projection matrix for reflection / refraction texture coords + float4x4 texGen = { 0.5, 0.0, 0.0, 0.5, + 0.0, -0.5, 0.0, 0.5, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0 }; + + IN.position.z = lerp( IN.position.z, eyePos.z, IN.horizonFactor.x ); + float4 inPos = float4( IN.position, 1.0); + OUT.objPos = inPos; + OUT.objPos.w = mul( modelMat, inPos ).z; + + // Send pre-undulation screenspace position + OUT.posPreWave = mul( modelview, inPos ); + OUT.posPreWave = mul( texGen, OUT.posPreWave ); + + // Calculate the undulation amount for this vertex. + float2 undulatePos = mul( modelMat, float4( IN.undulateData.xy, 0, 1 ) ).xy; + float undulateAmt = 0.0; + + undulateAmt += waveData[0].y * sin( elapsedTime * waveData[0].x + + undulatePos.x * waveDir[0].x + + undulatePos.y * waveDir[0].y ); + undulateAmt += waveData[1].y * sin( elapsedTime * waveData[1].x + + undulatePos.x * waveDir[1].x + + undulatePos.y * waveDir[1].y ); + undulateAmt += waveData[2].y * sin( elapsedTime * waveData[2].x + + undulatePos.x * waveDir[2].x + + undulatePos.y * waveDir[2].y ); + + float undulateFade = 1; + + // Scale down wave magnitude amount based on distance from the camera. + float dist = distance( IN.position.xyz, eyePos ); + dist = clamp( dist, 1.0, undulateMaxDist ); + undulateFade *= ( 1 - dist / undulateMaxDist ); + + // Also scale down wave magnitude if the camera is very very close. + undulateFade *= saturate( ( distance( IN.position.xyz, eyePos ) - 0.5 ) / 10.0 ); + + undulateAmt *= undulateFade; + + OUT.rippleTexCoord2.w = undulateAmt / ( waveData[0].y + waveData[1].y + waveData[2].y ); + OUT.rippleTexCoord2.w = saturate( OUT.rippleTexCoord2.w - 0.2 ) / 0.8; + + // Apply wave undulation to the vertex. + OUT.posPostWave = inPos; + OUT.posPostWave.xyz += IN.normal.xyz * undulateAmt; + + // Convert to screen + OUT.posPostWave = mul( modelview, OUT.posPostWave ); + + // Setup the OUT position symantic variable + OUT.hpos = OUT.posPostWave; + //OUT.hpos.z = lerp( OUT.hpos.z, OUT.hpos.w, IN.horizonFactor.x ); + + // if ( IN.horizonFactor.x > 0 ) + // { + // float3 awayVec = normalize( OUT.objPos.xyz - eyePos ); + // OUT.objPos.xy += awayVec.xy * 1000.0; + // } + + // Save world space camera dist/depth of the outgoing pixel + OUT.rippleTexCoord2.z = OUT.hpos.z; + + // Convert to reflection texture space + OUT.posPostWave = mul( texGen, OUT.posPostWave ); + + float2 txPos = undulatePos; + if ( IN.horizonFactor.x ) + txPos = normalize( txPos ) * 50000.0; + + // set up tex coordinates for the 3 interacting normal maps + OUT.rippleTexCoord01.xy = txPos * rippleTexScale[0]; + OUT.rippleTexCoord01.xy += rippleDir[0] * elapsedTime * rippleSpeed.x; + + float2x2 texMat; + texMat[0][0] = rippleMat[0].x; + texMat[0][1] = rippleMat[0].y; + texMat[1][0] = rippleMat[0].z; + texMat[1][1] = rippleMat[0].w; + OUT.rippleTexCoord01.xy = mul( texMat, OUT.rippleTexCoord01.xy ); + + OUT.rippleTexCoord01.zw = txPos * rippleTexScale[1]; + OUT.rippleTexCoord01.zw += rippleDir[1] * elapsedTime * rippleSpeed.y; + + texMat[0][0] = rippleMat[1].x; + texMat[0][1] = rippleMat[1].y; + texMat[1][0] = rippleMat[1].z; + texMat[1][1] = rippleMat[1].w; + OUT.rippleTexCoord01.zw = mul( texMat, OUT.rippleTexCoord01.zw ); + + OUT.rippleTexCoord2.xy = txPos * rippleTexScale[2]; + OUT.rippleTexCoord2.xy += rippleDir[2] * elapsedTime * rippleSpeed.z; + + texMat[0][0] = rippleMat[2].x; + texMat[0][1] = rippleMat[2].y; + texMat[1][0] = rippleMat[2].z; + texMat[1][1] = rippleMat[2].w; + OUT.rippleTexCoord2.xy = mul( texMat, OUT.rippleTexCoord2.xy ); + + OUT.foamTexCoords.xy = txPos * foamTexScale.xy + foamDir.xy * foamSpeed.x * elapsedTime; + OUT.foamTexCoords.zw = txPos * foamTexScale.zw + foamDir.zw * foamSpeed.y * elapsedTime; + + + float3 binormal = float3( 1, 0, 0 ); + float3 tangent = float3( 0, 1, 0 ); + float3 normal; + for ( int i = 0; i < 3; i++ ) + { + binormal.z += undulateFade * waveDir[i].x * waveData[i].y * cos( waveDir[i].x * undulatePos.x + waveDir[i].y * undulatePos.y + elapsedTime * waveData[i].x ); + tangent.z += undulateFade * waveDir[i].y * waveData[i].y * cos( waveDir[i].x * undulatePos.x + waveDir[i].y * undulatePos.y + elapsedTime * waveData[i].x ); + } + + binormal = binormal; + tangent = tangent; + normal = cross( binormal, tangent ); + + float3x3 worldToTangent; + worldToTangent[0] = binormal; + worldToTangent[1] = tangent; + worldToTangent[2] = normal; + + OUT.tangentMat = worldToTangent; + + return OUT; +} + diff --git a/Templates/BaseGame/game/core/rendering/shaders/wavesP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/wavesP.hlsl new file mode 100644 index 000000000..c51eb4b89 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/wavesP.hlsl @@ -0,0 +1,89 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#define IN_HLSL +#include "shdrConsts.h" +#include "shaderModel.hlsl" + +//----------------------------------------------------------------------------- +// Data +//----------------------------------------------------------------------------- +struct v2f +{ + float4 HPOS : TORQUE_POSITION; + float2 TEX0 : TEXCOORD0; + float4 tangentToCube0 : TEXCOORD1; + float4 tangentToCube1 : TEXCOORD2; + float4 tangentToCube2 : TEXCOORD3; + float4 lightVec : TEXCOORD4; + float3 pixPos : TEXCOORD5; + float3 eyePos : TEXCOORD6; +}; + + + +struct Fragout +{ + float4 col : TORQUE_TARGET0; +}; + +// Uniforms +TORQUE_UNIFORM_SAMPLER2D(diffMap,0); +//TORQUE_UNIFORM_SAMPLERCUBE(cubeMap, 1); not used? +TORQUE_UNIFORM_SAMPLER2D(bumpMap,2); + +uniform float4 specularColor : register(PC_MAT_SPECCOLOR); +uniform float4 ambient : register(PC_AMBIENT_COLOR); +uniform float specularPower : register(PC_MAT_SPECPOWER); +uniform float accumTime : register(PC_ACCUM_TIME); + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +Fragout main(v2f IN) +{ + Fragout OUT; + + float2 texOffset; + float sinOffset1 = sin( accumTime * 1.5 + IN.TEX0.y * 6.28319 * 3.0 ) * 0.03; + float sinOffset2 = sin( accumTime * 3.0 + IN.TEX0.y * 6.28319 ) * 0.04; + + texOffset.x = IN.TEX0.x + sinOffset1 + sinOffset2; + texOffset.y = IN.TEX0.y + cos( accumTime * 3.0 + IN.TEX0.x * 6.28319 * 2.0 ) * 0.05; + + + float4 bumpNorm = TORQUE_TEX2D( bumpMap, texOffset ) * 2.0 - 1.0; + float4 diffuse = TORQUE_TEX2D( diffMap, texOffset ); + + OUT.col = diffuse * (saturate( dot( IN.lightVec, bumpNorm.xyz ) ) + ambient); + + float3 eyeVec = normalize(IN.eyePos - IN.pixPos); + float3 halfAng = normalize(eyeVec + IN.lightVec.xyz); + float specular = saturate( dot(bumpNorm, halfAng) ) * IN.lightVec.w; + specular = pow(abs(specular), specularPower); + OUT.col += specularColor * specular; + + + + return OUT; +} + diff --git a/Templates/BaseGame/game/core/rendering/shaders/wavesV.hlsl b/Templates/BaseGame/game/core/rendering/shaders/wavesV.hlsl new file mode 100644 index 000000000..fccef9d25 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/wavesV.hlsl @@ -0,0 +1,90 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#define IN_HLSL +#include "shdrConsts.h" +#include "hlslStructs.hlsl" + +//----------------------------------------------------------------------------- +// Constants +//----------------------------------------------------------------------------- + +struct Conn +{ + float4 HPOS : POSITION; + float2 TEX0 : TEXCOORD0; + float4 tangentToCube0 : TEXCOORD1; + float4 tangentToCube1 : TEXCOORD2; + float4 tangentToCube2 : TEXCOORD3; + float4 outLightVec : TEXCOORD4; + float3 pos : TEXCOORD5; + float3 outEyePos : TEXCOORD6; + +}; + + +uniform float4x4 modelview : register(VC_WORLD_PROJ); +uniform float3x3 cubeTrans : register(VC_CUBE_TRANS); +uniform float3 cubeEyePos : register(VC_CUBE_EYE_POS); +uniform float3 inLightVec : register(VC_LIGHT_DIR1); +uniform float3 eyePos : register(VC_EYE_POS); + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +Conn main( VertexIn_PNTTTB In) +{ + Conn Out; + + Out.HPOS = mul(modelview, float4(In.pos,1.0)); + Out.TEX0 = In.uv0; + + + float3x3 objToTangentSpace; + objToTangentSpace[0] = In.T; + objToTangentSpace[1] = In.B; + objToTangentSpace[2] = In.normal; + + + Out.tangentToCube0.xyz = mul( objToTangentSpace, cubeTrans[0].xyz ); + Out.tangentToCube1.xyz = mul( objToTangentSpace, cubeTrans[1].xyz ); + Out.tangentToCube2.xyz = mul( objToTangentSpace, cubeTrans[2].xyz ); + + float3 pos = mul( cubeTrans, In.pos ).xyz; + float3 eye = cubeEyePos - pos; + normalize( eye ); + + Out.tangentToCube0.w = eye.x; + Out.tangentToCube1.w = eye.y; + Out.tangentToCube2.w = eye.z; + + Out.outLightVec.xyz = -inLightVec; + Out.outLightVec.xyz = mul(objToTangentSpace, Out.outLightVec); + Out.pos = mul(objToTangentSpace, In.pos.xyz / 100.0); + Out.outEyePos.xyz = mul(objToTangentSpace, eyePos.xyz / 100.0); + Out.outLightVec.w = step( 0.0, dot( -inLightVec, In.normal ) ); + + + return Out; +} + + diff --git a/Templates/BaseGame/game/core/rendering/shaders/wind.hlsl b/Templates/BaseGame/game/core/rendering/shaders/wind.hlsl new file mode 100644 index 000000000..b3fee7721 --- /dev/null +++ b/Templates/BaseGame/game/core/rendering/shaders/wind.hlsl @@ -0,0 +1,101 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// +// A tip of the hat.... +// +// The following wind effects were derived from the GPU Gems +// 3 chapter "Vegetation Procedural Animation and Shading in Crysis" +// by Tiago Sousa of Crytek. +// + +float4 smoothCurve( float4 x ) +{ + return x * x * ( 3.0 - 2.0 * x ); +} + +float4 triangleWave( float4 x ) +{ + return abs( frac( x + 0.5 ) * 2.0 - 1.0 ); +} + +float4 smoothTriangleWave( float4 x ) +{ + return smoothCurve( triangleWave( x ) ); +} + +float3 windTrunkBending( float3 vPos, float2 vWind, float fBendFactor ) +{ + // Smooth the bending factor and increase + // the near by height limit. + fBendFactor += 1.0; + fBendFactor *= fBendFactor; + fBendFactor = fBendFactor * fBendFactor - fBendFactor; + + // Displace the vert. + float3 vNewPos = vPos; + vNewPos.xy += vWind * fBendFactor; + + // Limit the length which makes the bend more + // spherical and prevents stretching. + float fLength = length( vPos ); + vPos = normalize( vNewPos ) * fLength; + + return vPos; +} + +float3 windBranchBending( float3 vPos, + float3 vNormal, + + float fTime, + float fWindSpeed, + + float fBranchPhase, + float fBranchAmp, + float fBranchAtten, + + float fDetailPhase, + float fDetailAmp, + float fDetailFreq, + + float fEdgeAtten ) +{ + float fVertPhase = dot( vPos, fDetailPhase + fBranchPhase ); + + float2 vWavesIn = fTime + float2( fVertPhase, fBranchPhase ); + + float4 vWaves = ( frac( vWavesIn.xxyy * + float4( 1.975, 0.793, 0.375, 0.193 ) ) * + 2.0 - 1.0 ) * fWindSpeed * fDetailFreq; + + vWaves = smoothTriangleWave( vWaves ); + + float2 vWavesSum = vWaves.xz + vWaves.yw; + + // We want the branches to bend both up and down. + vWavesSum.y = 1 - ( vWavesSum.y * 2 ); + + vPos += vWavesSum.xxy * float3( fEdgeAtten * fDetailAmp * vNormal.xy, + fBranchAtten * fBranchAmp ); + + return vPos; +} diff --git a/Templates/BaseGame/game/core/sfx/Core_SFX.cs b/Templates/BaseGame/game/core/sfx/Core_SFX.cs new file mode 100644 index 000000000..acd5c6e08 --- /dev/null +++ b/Templates/BaseGame/game/core/sfx/Core_SFX.cs @@ -0,0 +1,15 @@ + +function Core_SFX::onCreate(%this) +{ + exec("./scripts/audio.cs"); + exec("./scripts/audioData.cs"); + exec("./scripts/audioAmbience.cs"); + exec("./scripts/audioDescriptions.cs"); + exec("./scripts/audioEnvironments.cs"); + exec("./scripts/audioStates.cs"); + +} + +function Core_SFX::onDestroy(%this) +{ +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/sfx/Core_SFX.module b/Templates/BaseGame/game/core/sfx/Core_SFX.module new file mode 100644 index 000000000..855fe2a11 --- /dev/null +++ b/Templates/BaseGame/game/core/sfx/Core_SFX.module @@ -0,0 +1,9 @@ + + \ No newline at end of file diff --git a/Templates/BaseGame/game/core/sfx/scripts/audio.cs b/Templates/BaseGame/game/core/sfx/scripts/audio.cs new file mode 100644 index 000000000..a5932de8f --- /dev/null +++ b/Templates/BaseGame/game/core/sfx/scripts/audio.cs @@ -0,0 +1,436 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Source groups. +//----------------------------------------------------------------------------- + +singleton SFXDescription( AudioMaster ); +singleton SFXSource( AudioChannelMaster ) +{ + description = AudioMaster; +}; + +singleton SFXDescription( AudioChannel ) +{ + sourceGroup = AudioChannelMaster; +}; + +singleton SFXSource( AudioChannelDefault ) +{ + description = AudioChannel; +}; +singleton SFXSource( AudioChannelGui ) +{ + description = AudioChannel; +}; +singleton SFXSource( AudioChannelEffects ) +{ + description = AudioChannel; +}; +singleton SFXSource( AudioChannelMessages ) +{ + description = AudioChannel; +}; +singleton SFXSource( AudioChannelMusic ) +{ + description = AudioChannel; +}; + +// Set default playback states of the channels. + +AudioChannelMaster.play(); +AudioChannelDefault.play(); + +AudioChannelGui.play(); +AudioChannelMusic.play(); +AudioChannelMessages.play(); + +// Stop in-game effects channels. +AudioChannelEffects.stop(); + +//----------------------------------------------------------------------------- +// Master SFXDescriptions. +//----------------------------------------------------------------------------- + +// Master description for interface audio. +singleton SFXDescription( AudioGui ) +{ + volume = 1.0; + sourceGroup = AudioChannelGui; +}; + +// Master description for game effects audio. +singleton SFXDescription( AudioEffect ) +{ + volume = 1.0; + sourceGroup = AudioChannelEffects; +}; + +// Master description for audio in notifications. +singleton SFXDescription( AudioMessage ) +{ + volume = 1.0; + sourceGroup = AudioChannelMessages; +}; + +// Master description for music. +singleton SFXDescription( AudioMusic ) +{ + volume = 1.0; + sourceGroup = AudioChannelMusic; +}; + +//----------------------------------------------------------------------------- +// SFX Functions. +//----------------------------------------------------------------------------- + +/// This initializes the sound system device from +/// the defaults in the $pref::SFX:: globals. +function sfxStartup() +{ + echo( "\nsfxStartup..." ); + + // If we have a provider set, try initialize a device now. + + if( $pref::SFX::provider !$= "" ) + { + if( sfxInit() ) + return; + else + { + // Force auto-detection. + $pref::SFX::autoDetect = true; + } + } + + // If enabled autodetect a safe device. + + if( ( !isDefined( "$pref::SFX::autoDetect" ) || $pref::SFX::autoDetect ) && + sfxAutodetect() ) + return; + + // Failure. + + error( " Failed to initialize device!\n\n" ); + + $pref::SFX::provider = ""; + $pref::SFX::device = ""; + + return; +} + + +/// This initializes the sound system device from +/// the defaults in the $pref::SFX:: globals. +function sfxInit() +{ + // If already initialized, shut down the current device first. + + if( sfxGetDeviceInfo() !$= "" ) + sfxShutdown(); + + // Start it up! + %maxBuffers = $pref::SFX::useHardware ? -1 : $pref::SFX::maxSoftwareBuffers; + if ( !sfxCreateDevice( $pref::SFX::provider, $pref::SFX::device, $pref::SFX::useHardware, %maxBuffers ) ) + return false; + + // This returns a tab seperated string with + // the initialized system info. + %info = sfxGetDeviceInfo(); + $pref::SFX::provider = getField( %info, 0 ); + $pref::SFX::device = getField( %info, 1 ); + $pref::SFX::useHardware = getField( %info, 2 ); + %useHardware = $pref::SFX::useHardware ? "Yes" : "No"; + %maxBuffers = getField( %info, 3 ); + + echo( " Provider: " @ $pref::SFX::provider ); + echo( " Device: " @ $pref::SFX::device ); + echo( " Hardware: " @ %useHardware ); + echo( " Max Buffers: " @ %maxBuffers ); + echo( " " ); + + if( isDefined( "$pref::SFX::distanceModel" ) ) + sfxSetDistanceModel( $pref::SFX::distanceModel ); + if( isDefined( "$pref::SFX::dopplerFactor" ) ) + sfxSetDopplerFactor( $pref::SFX::dopplerFactor ); + if( isDefined( "$pref::SFX::rolloffFactor" ) ) + sfxSetRolloffFactor( $pref::SFX::rolloffFactor ); + + // Restore master volume. + + sfxSetMasterVolume( $pref::SFX::masterVolume ); + + // Restore channel volumes. + + for( %channel = 0; %channel <= 8; %channel ++ ) + sfxSetChannelVolume( %channel, $pref::SFX::channelVolume[ %channel ] ); + + return true; +} + + +/// Destroys the current sound system device. +function sfxShutdown() +{ + // Store volume prefs. + + $pref::SFX::masterVolume = sfxGetMasterVolume(); + + for( %channel = 0; %channel <= 8; %channel ++ ) + $pref::SFX::channelVolume[ %channel ] = sfxGetChannelVolume( %channel ); + + // We're assuming here that a null info + // string means that no device is loaded. + if( sfxGetDeviceInfo() $= "" ) + return; + + sfxDeleteDevice(); +} + + +/// Determines which of the two SFX providers is preferable. +function sfxCompareProvider( %providerA, %providerB ) +{ + if( %providerA $= %providerB ) + return 0; + + switch$( %providerA ) + { + // Always prefer FMOD over anything else. + case "FMOD": + return 1; + + // Prefer OpenAL over anything but FMOD. + case "OpenAL": + if( %providerB $= "FMOD" ) + return -1; + else + return 1; + + // choose XAudio over DirectSound + case "XAudio": + if( %providerB $= "FMOD" || %providerB $= "OpenAL" ) + return -1; + else + return 0; + + case "DirectSound": + if( %providerB !$= "FMOD" && %providerB !$= "OpenAL" && %providerB !$= "XAudio" ) + return 1; + else + return -1; + + default: + return -1; + } +} + + +/// Try to detect and initalize the best SFX device available. +function sfxAutodetect() +{ + // Get all the available devices. + + %devices = sfxGetAvailableDevices(); + + // Collect and sort the devices by preferentiality. + + %deviceTrySequence = new ArrayObject(); + %bestMatch = -1; + %count = getRecordCount( %devices ); + for( %i = 0; %i < %count; %i ++ ) + { + %info = getRecord( %devices, %i ); + %provider = getField( %info, 0 ); + + %deviceTrySequence.push_back( %provider, %info ); + } + + %deviceTrySequence.sortfkd( "sfxCompareProvider" ); + + // Try the devices in order. + + %count = %deviceTrySequence.count(); + for( %i = 0; %i < %count; %i ++ ) + { + %provider = %deviceTrySequence.getKey( %i ); + %info = %deviceTrySequence.getValue( %i ); + + $pref::SFX::provider = %provider; + $pref::SFX::device = getField( %info, 1 ); + $pref::SFX::useHardware = getField( %info, 2 ); + + // By default we've decided to avoid hardware devices as + // they are buggy and prone to problems. + $pref::SFX::useHardware = false; + + if( sfxInit() ) + { + $pref::SFX::autoDetect = false; + %deviceTrySequence.delete(); + return true; + } + } + + // Found no suitable device. + + error( "sfxAutodetect - Could not initialize a valid SFX device." ); + + $pref::SFX::provider = ""; + $pref::SFX::device = ""; + $pref::SFX::useHardware = ""; + + %deviceTrySequence.delete(); + + return false; +} + + +//----------------------------------------------------------------------------- +// Backwards-compatibility with old channel system. +//----------------------------------------------------------------------------- + +// Volume channel IDs for backwards-compatibility. + +$GuiAudioType = 1; // Interface. +$SimAudioType = 2; // Game. +$MessageAudioType = 3; // Notifications. +$MusicAudioType = 4; // Music. + +$AudioChannels[ 0 ] = AudioChannelDefault; +$AudioChannels[ $GuiAudioType ] = AudioChannelGui; +$AudioChannels[ $SimAudioType ] = AudioChannelEffects; +$AudioChannels[ $MessageAudioType ] = AudioChannelMessages; +$AudioChannels[ $MusicAudioType ] = AudioChannelMusic; + +function sfxOldChannelToGroup( %channel ) +{ + return $AudioChannels[ %channel ]; +} + +function sfxGroupToOldChannel( %group ) +{ + %id = %group.getId(); + for( %i = 0;; %i ++ ) + if( !isObject( $AudioChannels[ %i ] ) ) + return -1; + else if( $AudioChannels[ %i ].getId() == %id ) + return %i; + + return -1; +} + +function sfxSetMasterVolume( %volume ) +{ + AudioChannelMaster.setVolume( %volume ); +} + +function sfxGetMasterVolume( %volume ) +{ + return AudioChannelMaster.getVolume(); +} + +function sfxStopAll( %channel ) +{ + // Don't stop channel itself since that isn't quite what the function + // here intends. + + %channel = sfxOldChannelToGroup( %channel ); + if (isObject(%channel)) + { + foreach( %source in %channel ) + %source.stop(); + } +} + +function sfxGetChannelVolume( %channel ) +{ + %obj = sfxOldChannelToGroup( %channel ); + if( isObject( %obj ) ) + return %obj.getVolume(); +} + +function sfxSetChannelVolume( %channel, %volume ) +{ + %obj = sfxOldChannelToGroup( %channel ); + if( isObject( %obj ) ) + %obj.setVolume( %volume ); +} + +/*singleton SimSet( SFXPausedSet ); + + +/// Pauses the playback of active sound sources. +/// +/// @param %channels An optional word list of channel indices or an empty +/// string to pause sources on all channels. +/// @param %pauseSet An optional SimSet which is filled with the paused +/// sources. If not specified the global SfxSourceGroup +/// is used. +/// +/// @deprecated +/// +function sfxPause( %channels, %pauseSet ) +{ + // Did we get a set to populate? + if ( !isObject( %pauseSet ) ) + %pauseSet = SFXPausedSet; + + %count = SFXSourceSet.getCount(); + for ( %i = 0; %i < %count; %i++ ) + { + %source = SFXSourceSet.getObject( %i ); + + %channel = sfxGroupToOldChannel( %source.getGroup() ); + if( %channels $= "" || findWord( %channels, %channel ) != -1 ) + { + %source.pause(); + %pauseSet.add( %source ); + } + } +} + + +/// Resumes the playback of paused sound sources. +/// +/// @param %pauseSet An optional SimSet which contains the paused sound +/// sources to be resumed. If not specified the global +/// SfxSourceGroup is used. +/// @deprecated +/// +function sfxResume( %pauseSet ) +{ + if ( !isObject( %pauseSet ) ) + %pauseSet = SFXPausedSet; + + %count = %pauseSet.getCount(); + for ( %i = 0; %i < %count; %i++ ) + { + %source = %pauseSet.getObject( %i ); + %source.play(); + } + + // Clear our pause set... the caller is left + // to clear his own if he passed one. + %pauseSet.clear(); +}*/ diff --git a/Templates/BaseGame/game/core/sfx/scripts/audioAmbience.cs b/Templates/BaseGame/game/core/sfx/scripts/audioAmbience.cs new file mode 100644 index 000000000..8c2bf270c --- /dev/null +++ b/Templates/BaseGame/game/core/sfx/scripts/audioAmbience.cs @@ -0,0 +1,44 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +singleton SFXAmbience( AudioAmbienceDefault ) +{ + environment = AudioEnvOff; +}; + +singleton SFXAmbience( AudioAmbienceOutside ) +{ + environment = AudioEnvPlain; + states[ 0 ] = AudioLocationOutside; +}; + +singleton SFXAmbience( AudioAmbienceInside ) +{ + environment = AudioEnvRoom; + states[ 0 ] = AudioLocationInside; +}; + +singleton SFXAmbience( AudioAmbienceUnderwater ) +{ + environment = AudioEnvUnderwater; + states[ 0 ] = AudioLocationUnderwater; +}; diff --git a/Templates/BaseGame/game/core/sfx/scripts/audioData.cs b/Templates/BaseGame/game/core/sfx/scripts/audioData.cs new file mode 100644 index 000000000..8584ce50e --- /dev/null +++ b/Templates/BaseGame/game/core/sfx/scripts/audioData.cs @@ -0,0 +1,42 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// Game specific audio descriptions. Always declare SFXDescription's (the type of sound) +// before SFXProfile's (the sound itself) when creating new ones + +singleton SFXDescription(BulletFireDesc : AudioEffect ) +{ + isLooping = false; + is3D = true; + ReferenceDistance = 10.0; + MaxDistance = 60.0; +}; + +singleton SFXDescription(BulletImpactDesc : AudioEffect ) +{ + isLooping = false; + is3D = true; + ReferenceDistance = 10.0; + MaxDistance = 30.0; + volume = 0.4; + pitch = 1.4; +}; diff --git a/Templates/BaseGame/game/core/sfx/scripts/audioDescriptions.cs b/Templates/BaseGame/game/core/sfx/scripts/audioDescriptions.cs new file mode 100644 index 000000000..d682461cf --- /dev/null +++ b/Templates/BaseGame/game/core/sfx/scripts/audioDescriptions.cs @@ -0,0 +1,143 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// Always declare SFXDescription's (the type of sound) before SFXProfile's (the +// sound itself) when creating new ones + +//----------------------------------------------------------------------------- +// 3D Sounds +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Single shot sounds +//----------------------------------------------------------------------------- + +singleton SFXDescription( AudioDefault3D : AudioEffect ) +{ + is3D = true; + ReferenceDistance = 20.0; + MaxDistance = 100.0; +}; + +singleton SFXDescription( AudioSoft3D : AudioEffect ) +{ + is3D = true; + ReferenceDistance = 20.0; + MaxDistance = 100.0; + volume = 0.4; +}; + +singleton SFXDescription( AudioClose3D : AudioEffect ) +{ + is3D = true; + ReferenceDistance = 10.0; + MaxDistance = 60.0; +}; + +singleton SFXDescription( AudioClosest3D : AudioEffect ) +{ + is3D = true; + ReferenceDistance = 5.0; + MaxDistance = 10.0; +}; + +//----------------------------------------------------------------------------- +// Looping sounds +//----------------------------------------------------------------------------- + +singleton SFXDescription( AudioDefaultLoop3D : AudioEffect ) +{ + isLooping = true; + is3D = true; + ReferenceDistance = 20.0; + MaxDistance = 100.0; +}; + +singleton SFXDescription( AudioCloseLoop3D : AudioEffect ) +{ + isLooping = true; + is3D = true; + ReferenceDistance = 18.0; + MaxDistance = 25.0; +}; + +singleton SFXDescription( AudioClosestLoop3D : AudioEffect ) +{ + isLooping = true; + is3D = true; + ReferenceDistance = 5.0; + MaxDistance = 10.0; +}; + +//----------------------------------------------------------------------------- +// 2d sounds +//----------------------------------------------------------------------------- + +// Used for non-looping environmental sounds (like power on, power off) +singleton SFXDescription( Audio2D : AudioEffect ) +{ + isLooping = false; +}; + +// Used for Looping Environmental Sounds +singleton SFXDescription( AudioLoop2D : AudioEffect ) +{ + isLooping = true; +}; + +singleton SFXDescription( AudioStream2D : AudioEffect ) +{ + isStreaming = true; +}; +singleton SFXDescription( AudioStreamLoop2D : AudioEffect ) +{ + isLooping = true; + isStreaming = true; +}; + +//----------------------------------------------------------------------------- +// Music +//----------------------------------------------------------------------------- + +singleton SFXDescription( AudioMusic2D : AudioMusic ) +{ + isStreaming = true; +}; + +singleton SFXDescription( AudioMusicLoop2D : AudioMusic ) +{ + isLooping = true; + isStreaming = true; +}; + +singleton SFXDescription( AudioMusic3D : AudioMusic ) +{ + isStreaming = true; + is3D = true; +}; + +singleton SFXDescription( AudioMusicLoop3D : AudioMusic ) +{ + isStreaming = true; + is3D = true; + isLooping = true; +}; diff --git a/Templates/BaseGame/game/core/sfx/scripts/audioEnvironments.cs b/Templates/BaseGame/game/core/sfx/scripts/audioEnvironments.cs new file mode 100644 index 000000000..671825b6b --- /dev/null +++ b/Templates/BaseGame/game/core/sfx/scripts/audioEnvironments.cs @@ -0,0 +1,916 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// Reverb environment presets. +// +// For customized presets, best derive from one of these presets. + +singleton SFXEnvironment( AudioEnvOff ) +{ + envSize = "7.5"; + envDiffusion = "1.0"; + room = "-10000"; + roomHF = "-10000"; + roomLF = "0"; + decayTime = "1.0"; + decayHFRatio = "1.0"; + decayLFRatio = "1.0"; + reflections = "-2602"; + reflectionsDelay = "0.007"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + reverb = "200"; + reverbDelay = "0.011"; + reverbPan[ 0 ] = "0.0"; + reverbPan[ 1 ] = "0.0"; + reverbPan[ 2 ] = "0.0"; + echoTime = "0.25"; + echoDepth = "0.0"; + modulationTime = "0.25"; + modulationDepth = "0.0"; + airAbsorptionHF = "-5.0"; + HFReference = "5000.0"; + LFReference = "250.0"; + roomRolloffFactor = "0.0"; + diffusion = "0.0"; + density = "0.0"; + flags = 0x33; +}; + +singleton SFXEnvironment( AudioEnvGeneric ) +{ + envSize = "7.5"; + envDiffusion = "1.0"; + room = "-1000"; + roomHF = "-100"; + roomLF = "0"; + decayTime = "1.49"; + decayHFRatio = "0.83"; + decayLFRatio = "1.0"; + reflections = "-2602"; + reflectionsDelay = "0.007"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + reverb = "200"; + reverbDelay = "0.011"; + reverbPan[ 0 ] = "0.0"; + reverbPan[ 1 ] = "0.0"; + reverbPan[ 2 ] = "0.0"; + echoTime = "0.25"; + echoDepth = "0.0"; + modulationTime = "0.25"; + modulationDepth = "0.0"; + airAbsorptionHF = "-5.0"; + HFReference = "5000.0"; + LFReference = "250.0"; + roomRolloffFactor = "0.0"; + diffusion = "100.0"; + density = "100.0"; + flags = 0x3f; +}; + +singleton SFXEnvironment( AudioEnvRoom ) +{ + envSize = "1.9"; + envDiffusion = "1.0"; + room = "-1000"; + roomHF = "-454"; + roomLF = "0"; + decayTime = "0.4"; + decayHFRatio = "0.83"; + decayLFRatio = "1.0"; + reflections = "-1646"; + reflectionsDelay = "0.002"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + reverb = "53"; + reverbDelay = "0.003"; + reverbPan[ 0 ] = "0.0"; + reverbPan[ 1 ] = "0.0"; + reverbPan[ 2 ] = "0.0"; + echoTime = "0.25"; + echoDepth = "0.0"; + modulationTime = "0.25"; + modulationDepth = "0.0"; + airAbsorptionHF = "-5.0"; + HFReference = "5000.0"; + LFReference = "250.0"; + roomRolloffFactor = "0.0"; + diffusion = "100.0"; + density = "100.0"; + flags = 0x3f; +}; + +singleton SFXEnvironment( AudioEnvPaddedCell ) +{ + envSize = "1.4"; + envDiffusion = "1.0"; + room = "-1000"; + roomHF = "-6000"; + roomLF = "0"; + decayTime = "0.17"; + decayHFRatio = "0.1"; + decayLFRatio = "1.0"; + reflections = "-1204"; + reflectionsDelay = "0.001"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + reverb = "207"; + reverbDelay = "0.002"; + reverbPan[ 0 ] = "0.0"; + reverbPan[ 1 ] = "0.0"; + reverbPan[ 2 ] = "0.0"; + echoTime = "0.25"; + echoDepth = "0.0"; + modulationTime = "0.25"; + modulationDepth = "0.0"; + airAbsorptionHF = "-5.0"; + HFReference = "5000.0"; + LFReference = "250.0"; + roomRolloffFactor = "0.0"; + diffusion = "100.0"; + density = "100.0"; + flags = 0x3f; +}; + +singleton SFXEnvironment( AudioEnvBathroom ) +{ + envSize = "1.4"; + envDiffusion = "1.0"; + room = "-1000"; + roomHF = "-1200"; + roomLF = "0"; + decayTime = "1.49"; + decayHFRatio = "0.54"; + decayLFRatio = "1.0"; + reflections = "-370"; + reflectionsDelay = "0.007"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + reverb = "1030"; + reverbDelay = "0.011"; + reverbPan[ 0 ] = "0.0"; + reverbPan[ 1 ] = "0.0"; + reverbPan[ 2 ] = "0.0"; + echoTime = "0.25"; + echoDepth = "0.0"; + modulationTime = "0.25"; + modulationDepth = "0.0"; + airAbsorptionHF = "-5.0"; + HFReference = "5000.0"; + LFReference = "250.0"; + roomRolloffFactor = "0.0"; + diffusion = "100.0"; + density = "60.0"; + flags = 0x3f; +}; + +singleton SFXEnvironment( AudioEnvLivingRoom ) +{ + envSize = "2.5"; + envDiffusion = "1.0"; + room = "-1000"; + roomHF = "-6000"; + roomLF = "0"; + decayTime = "0.5"; + decayHFRatio = "0.1"; + decayLFRatio = "1.0"; + reflections = "-1376"; + reflectionsDelay = "0.003"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + reverb = "-1104"; + reverbDelay = "0.004"; + reverbPan[ 0 ] = "0.0"; + reverbPan[ 1 ] = "0.0"; + reverbPan[ 2 ] = "0.0"; + echoTime = "0.25"; + echoDepth = "0.0"; + modulationTime = "0.25"; + modulationDepth = "0.0"; + airAbsorptionHF = "-5.0"; + HFReference = "5000.0"; + LFReference = "250.0"; + roomRolloffFactor = "0.0"; + diffusion = "100.0"; + density = "100.0"; + flags = 0x3f; +}; + +singleton SFXEnvironment( AudioEnvStoneRoom ) +{ + envSize = "11.6"; + envDiffusion = "1.0"; + room = "-1000"; + roomHF = "300"; + roomLF = "0"; + decayTime = "2.31"; + decayHFRatio = "0.64"; + decayLFRatio = "1.0"; + reflections = "-711"; + reflectionsDelay = "0.012"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + reverb = "83"; + reverbDelay = "0.017"; + reverbPan[ 0 ] = "0.0"; + reverbPan[ 1 ] = "0.0"; + reverbPan[ 2 ] = "0.0"; + echoTime = "0.25"; + echoDepth = "0.0"; + modulationTime = "0.25"; + modulationDepth = "0.0"; + airAbsorptionHF = "-5.0"; + HFReference = "-5000.0"; + LFReference = "250.0"; + roomRolloffFactor = "0.0"; + diffusion = "100.0"; + density = "100.0"; + flags = 0x3f; +}; + +singleton SFXEnvironment( AudioEnvAuditorium ) +{ + envSize = "21.6"; + envDiffusion = "1.0"; + room = "-1000"; + roomHF = "-476"; + roomLF = "0"; + decayTime = "4.32"; + decayHFRatio = "0.59"; + decayLFRatio = "1.0"; + reflections = "1"; + reflectionsDelay = "0.02"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + reverb = "-289"; + reverbDelay = "0.03"; + reverbPan[ 0 ] = "0.0"; + reverbPan[ 1 ] = "0.0"; + reverbPan[ 2 ] = "0.0"; + echoTime = "0.25"; + echoDepth = "0.0"; + modulationTime = "0.25"; + modulationDepth = "0.0"; + airAbsorptionHF = "-5.0"; + HFReference = "5000.0"; + LFReference = "250.0"; + roomRolloffFactor = "0.0"; + diffusion = "100.0"; + density = "100.0"; + flags = 0x3f; +}; + +singleton SFXEnvironment( AudioEnvConcertHall ) +{ + envSize = "19.6"; + envDiffusion = "1.0"; + room = "-1000"; + roomHF = "-500"; + roomLF = "0"; + decayTime = "3.92"; + decayHFRatio = "0.7"; + decayLFRatio = "1.0"; + reflections = "-1230"; + reflectionsDelay = "0.02"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + reverb = "-2"; + reverbDelay = "0.029"; + reverbPan[ 0 ] = "0.0"; + reverbPan[ 1 ] = "0.0"; + reverbPan[ 2 ] = "0.0"; + echoTime = "0.25"; + echoDepth = "0.0"; + modulationTime = "0.25"; + modulationDepth = "0.0"; + airAbsorptionHF = "-5.0"; + HFReference = "5000.0"; + LFReference = "250.0"; + roomRolloffFactor = "0.0"; + diffusion = "100.0"; + density = "100.0"; + flags = 0x3f; +}; + +singleton SFXEnvironment( AudioEnvCave ) +{ + envSize = "14.6"; + envDiffusion = "1.0"; + room = "-1000"; + roomHF = "0"; + roomLF = "0"; + decayTime = "2.91"; + decayHFRatio = "1.3"; + decayLFRatio = "1.0"; + reflections = "-602"; + reflectionsDelay = "0.015"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + reverb = "-302"; + reverbDelay = "0.022"; + reverbPan[ 0 ] = "0.0"; + reverbPan[ 1 ] = "0.0"; + reverbPan[ 2 ] = "0.0"; + echoTime = "0.25"; + echoDepth = "0.0"; + modulationTime = "0.25"; + modulationDepth = "0.0"; + airAbsorptionHF = "-5.0"; + HFReference = "5000.0"; + LFReference = "250.0"; + roomRolloffFactor = "0.0"; + diffusion = "100.0"; + density = "100.0"; + flags = 0x1f; +}; + +singleton SFXEnvironment( AudioEnvArena ) +{ + envSize = "36.2f"; + envDiffusion = "1.0"; + room = "-1000"; + roomHF = "-698"; + roomLF = "0"; + decayTime = "7.24"; + decayHFRatio = "0.33"; + decayLFRatio = "1.0"; + reflections = "-1166"; + reflectionsDelay = "0.02"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + reverb = "16"; + reverbDelay = "0.03"; + reverbPan[ 0 ] = "0.0"; + reverbPan[ 1 ] = "0.0"; + reverbPan[ 2 ] = "0.0"; + echoTime = "0.25"; + echoDepth = "0.0"; + modulationTime = "0.25"; + modulationDepth = "0.0"; + airAbsorptionHF = "-5.0"; + HFReference = "5000.0"; + LFReference = "250.0"; + roomRolloffFactor = "0.0"; + diffusion = "100.0"; + density = "100.0"; + flags = 0x3f; +}; + +singleton SFXEnvironment( AudioEnvHangar ) +{ + envSize = "50.3"; + envDiffusion = "1.0"; + room = "-1000"; + roomHF = "-1000"; + roomLF = "0"; + decayTime = "10.05"; + decayHFRatio = "0.23"; + decayLFRatio = "1.0"; + reflections = "-602"; + reflectionsDelay = "0.02"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + reverb = "198"; + reverbDelay = "0.03"; + reverbPan[ 0 ] = "0.0"; + reverbPan[ 1 ] = "0.0"; + reverbPan[ 2 ] = "0.0"; + echoTime = "0.25"; + echoDepth = "0.0"; + modulationTime = "0.25"; + modulationDepth = "0.0"; + airAbsorptionHF = "-5.0"; + HFReference = "5000.0"; + LFReference = "250.0"; + roomRolloffFactor = "0.0"; + diffusion = "100.0"; + density = "100.0"; + flags = 0x3f; +}; + +singleton SFXEnvironment( AudioEnvCarpettedHallway ) +{ + envSize = "1.9"; + envDiffusion = "1.0"; + room = "-1000"; + roomHF = "-4000"; + roomLF = "0"; + decayTime = "0.3"; + decayHFRatio = "0.1"; + decayLFRatio = "1.0"; + reflections = "-1831"; + reflectionsDelay = "0.002"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + reverb = "-1630"; + reverbDelay = "0.03"; + reverbPan[ 0 ] = "0.0"; + reverbPan[ 1 ] = "0.0"; + reverbPan[ 2 ] = "0.0"; + echoTime = "0.25"; + echoDepth = "0.0"; + modulationTime = "0.25"; + modulationDepth = "0.0"; + airAbsorptionHF = "-5.0"; + HFReference = "5000.0"; + LFReference = "250.0"; + roomRolloffFactor = "0.0"; + diffusion = "100.0"; + density = "100.0"; + flags = 0x3f; +}; + +singleton SFXEnvironment( AudioEnvHallway ) +{ + envSize = "1.8"; + envDiffusion = "1.0"; + room = "-1000"; + roomHF = "-300"; + roomLF = "0"; + decayTime = "1.49"; + decayHFRatio = "0.59"; + decayLFRatio = "1.0"; + reflections = "-1219"; + reflectionsDelay = "0.007"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + reverb = "441"; + reverbDelay = "0.011"; + reverbPan[ 0 ] = "0.0"; + reverbPan[ 1 ] = "0.0"; + reverbPan[ 2 ] = "0.0"; + echoTime = "0.25"; + echoDepth = "0.0"; + modulationTime = "0.25"; + modulationDepth = "0.0"; + airAbsorptionHF = "-5.0"; + HFReference = "5000.0"; + LFReference = "250.0"; + roomRolloffFactor = "0.0"; + diffusion = "100.0"; + density = "100.0"; + flags = 0x3f; +}; + +singleton SFXEnvironment( AudioEnvStoneCorridor ) +{ + envSize = "13.5"; + envDiffusion = "1.0"; + room = "-1000"; + roomHF = "-237"; + roomLF = "0"; + decayTime = "2.7"; + decayHFRatio = "0.79"; + decayLFRatio = "1.0"; + reflections = "-1214"; + reflectionsDelay = "0.013"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + reverb = "395"; + reverbDelay = "0.02"; + reverbPan[ 0 ] = "0.0"; + reverbPan[ 1 ] = "0.0"; + reverbPan[ 2 ] = "0.0"; + echoTime = "0.25"; + echoDepth = "0.0"; + modulationTime = "0.25"; + modulationDepth = "0.0"; + airAbsorptionHF = "-5.0"; + HFReference = "5000.0"; + LFReference = "250.0"; + roomRolloffFactor = "0.0"; + diffusion = "100.0"; + density = "100.0"; + flags = 0x3f; +}; + +singleton SFXEnvironment( AudioEnvAlley ) +{ + envSize = "7.5"; + envDiffusion = "0.3"; + room = "-1000"; + roomHF = "-270"; + roomLF = "0"; + decayTime = "1.49"; + decayHFRatio = "0.86"; + decayLFRatio = "1.0"; + reflections = "-1204"; + reflectionsDelay = "0.007"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + reverb = "-4"; + reverbDelay = "0.011"; + reverbPan[ 0 ] = "0.0"; + reverbPan[ 1 ] = "0.0"; + reverbPan[ 2 ] = "0.0"; + echoTime = "0.125"; + echoDepth = "0.95"; + modulationTime = "0.25"; + modulationDepth = "0.0"; + airAbsorptionHF = "-5.0"; + HFReference = "5000.0"; + LFReference = "250.0"; + roomRolloffFactor = "0.0"; + diffusion = "100.0"; + density = "100.0"; + flags = 0x3f; +}; + +singleton SFXEnvironment( AudioEnvForest ) +{ + envSize = "38.0"; + envDiffusion = "0.3"; + room = "-1000"; + roomHF = "-3300"; + roomLF = "0"; + decayTime = "1.49"; + decayHFRatio = "0.54"; + decayLFRatio = "1.0"; + reflections = "-2560"; + reflectionsDelay = "0.162"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + reverb = "-229"; + reverbDelay = "0.088"; + reverbPan[ 0 ] = "0.0"; + reverbPan[ 1 ] = "0.0"; + reverbPan[ 2 ] = "0.0"; + echoTime = "0.125"; + echoDepth = "1.0"; + modulationTime = "0.25"; + modulationDepth = "0.0"; + airAbsorptionHF = "-5.0"; + HFReference = "5000.0"; + LFReference = "250.0"; + roomRolloffFactor = "0.0"; + diffusion = "79.0"; + density = "100.0"; + flags = 0x3f; +}; + +singleton SFXEnvironment( AudioEnvCity ) +{ + envSize = "7.5"; + envDiffusion = "0.5"; + room = "-1000"; + roomHF = "-800"; + roomLF = "0"; + decayTime = "1.49"; + decayHFRatio = "0.67"; + decayLFRatio = "1.0"; + reflections = "-2273"; + reflectionsDelay = "0.007"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + reverb = "-1691"; + reverbDelay = "0.011"; + reverbPan[ 0 ] = "0.0"; + reverbPan[ 1 ] = "0.0"; + reverbPan[ 2 ] = "0.0"; + echoTime = "0.25"; + echoDepth = "0.0"; + modulationTime = "0.25"; + modulationDepth = "0.0"; + airAbsorptionHF = "-5.0"; + HFReference = "5000.0"; + LFReference = "250.0"; + roomRolloffFactor = "0.0"; + diffusion = "50.0"; + density = "100.0"; + flags = 0x3f; +}; + +singleton SFXEnvironment( AudioEnvMountains ) +{ + envSize = "100.0"; + envDiffusion = "0.27"; + room = "-1000"; + roomHF = "-2500"; + roomLF = "0"; + decayTime = "1.49"; + decayHFRatio = "0.21"; + decayLFRatio = "1.0"; + reflections = "-2780"; + reflectionsDelay = "0.3"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + reverb = "-1434"; + reverbDelay = "0.1"; + reverbPan[ 0 ] = "0.0"; + reverbPan[ 1 ] = "0.0"; + reverbPan[ 2 ] = "0.0"; + echoTime = "0.25"; + echoDepth = "1.0"; + modulationTime = "0.25"; + modulationDepth = "0.0"; + airAbsorptionHF = "-5.0"; + HFReference = "5000.0"; + LFReference = "250.0"; + roomRolloffFactor = "0.0"; + diffusion = "27.0"; + density = "100.0"; + flags = 0x1f; +}; + +singleton SFXEnvironment( AudioEnvQuary ) +{ + envSize = "17.5"; + envDiffusion = "1.0"; + room = "-1000"; + roomHF = "-1000"; + roomLF = "0"; + decayTime = "1.49"; + decayHFRatio = "0.83"; + decayLFRatio = "1.0"; + reflections = "-10000"; + reflectionsDelay = "0.061"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + reverb = "500"; + reverbDelay = "0.025"; + reverbPan[ 0 ] = "0.0"; + reverbPan[ 1 ] = "0.0"; + reverbPan[ 2 ] = "0.0"; + echoTime = "0.125"; + echoDepth = "0.7"; + modulationTime = "0.25"; + modulationDepth = "0.0"; + airAbsorptionHF = "-5.0"; + HFReference = "5000.0"; + LFReference = "250.0"; + roomRolloffFactor = "0.0"; + diffusion = "100.0"; + density = "100.0"; + flags = 0x3f; +}; + +singleton SFXEnvironment( AudioEnvPlain ) +{ + envSize = "42.5"; + envDiffusion = "0.21"; + room = "-1000"; + roomHF = "-2000"; + roomLF = "0"; + decayTime = "1.49"; + decayHFRatio = "0.5"; + decayLFRatio = "1.0"; + reflections = "-2466"; + reflectionsDelay = "0.179"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + reverb = "-1926"; + reverbDelay = "0.1"; + reverbPan[ 0 ] = "0.0"; + reverbPan[ 1 ] = "0.0"; + reverbPan[ 2 ] = "0.0"; + echoTime = "0.25"; + echoDepth = "1.0"; + modulationTime = "0.25"; + modulationDepth = "0.0"; + airAbsorptionHF = "-5.0"; + HFReference = "5000.0"; + LFReference = "250.0"; + roomRolloffFactor = "0.0"; + diffusion = "21.0"; + density = "100.0"; + flags = 0x3f; +}; + +singleton SFXEnvironment( AudioEnvParkingLot ) +{ + envSize = "8.3"; + envDiffusion = "1.0"; + room = "-1000"; + roomHF = "0"; + roomLF = "0"; + decayTime = "1.65"; + decayHFRatio = "1.5"; + decayLFRatio = "1.0"; + reflections = "-1363"; + reflectionsDelay = "0.008"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + reverb = "-1153"; + reverbDelay = "0.012"; + reverbPan[ 0 ] = "0.0"; + reverbPan[ 1 ] = "0.0"; + reverbPan[ 2 ] = "0.0"; + echoTime = "0.25"; + echoDepth = "0.0"; + modulationTime = "0.25"; + modulationDepth = "0.0"; + airAbsorptionHF = "-5.0"; + HFReference = "5000.0"; + LFReference = "250.0"; + roomRolloffFactor = "0.0"; + diffusion = "100.0"; + density = "100.0"; + flags = 0x1f; +}; + +singleton SFXEnvironment( AudioEnvSewerPipe ) +{ + envSize = "1.7"; + envDiffusion = "0.8"; + room = "-1000"; + roomHF = "-1000"; + roomLF = "0"; + decayTime = "2.81"; + decayHFRatio = "0.14"; + decayLFRatio = "1.0"; + reflections = "429"; + reflectionsDelay = "0.014"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + reverb = "1023"; + reverbDelay = "0.21"; + reverbPan[ 0 ] = "0.0"; + reverbPan[ 1 ] = "0.0"; + reverbPan[ 2 ] = "0.0"; + echoTime = "0.25"; + echoDepth = "0.0"; + modulationTime = "0.25"; + modulationDepth = "0.0"; + airAbsorptionHF = "-5.0"; + HFReference = "5000.0"; + LFReference = "250.0"; + roomRolloffFactor = "0.0"; + diffusion = "80.0"; + density = "60.0"; + flags = 0x3f; +}; + +singleton SFXEnvironment( AudioEnvUnderwater ) +{ + envSize = "1.8"; + envDiffusion = "1.0"; + room = "-1000"; + roomHF = "-4000"; + roomLF = "0"; + decayTime = "1.49"; + decayHFRatio = "0.1"; + decayLFRatio = "1.0"; + reflections = "-449"; + reflectionsDelay = "0.007"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + reverb = "1700"; + reverbDelay = "0.011"; + reverbPan[ 0 ] = "0.0"; + reverbPan[ 1 ] = "0.0"; + reverbPan[ 2 ] = "0.0"; + echoTime = "0.25"; + echoDepth = "0.0"; + modulationTime = "1.18"; + modulationDepth = "0.348"; + airAbsorptionHF = "-5.0"; + HFReference = "5000.0"; + LFReference = "250.0"; + roomRolloffFactor = "0.0"; + diffusion = "100.0"; + density = "100.0"; + flags = 0x3f; +}; + +singleton SFXEnvironment( AudioEnvDrugged ) +{ + envSize = "1.9"; + envDiffusion = "0.5"; + room = "-1000"; + roomHF = "0"; + roomLF = "0"; + decayTime = "8.39"; + decayHFRatio = "1.39"; + decayLFRatio = "1.0"; + reflections = "-115"; + reflectionsDelay = "0.002"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + reverb = "985"; + reverbDelay = "0.03"; + reverbPan[ 0 ] = "0.0"; + reverbPan[ 1 ] = "0.0"; + reverbPan[ 2 ] = "0.0"; + echoTime = "0.25"; + echoDepth = "0.0"; + modulationTime = "0.25"; + modulationDepth = "1.0"; + airAbsorptionHF = "-5.0"; + HFReference = "5000.0"; + LFReference = "250.0"; + roomRolloffFactor = "0.0"; + diffusion = "100.0"; + density = "100.0"; + flags = 0x1f; +}; + +singleton SFXEnvironment( AudioEnvDizzy ) +{ + envSize = "1.8"; + envDiffusion = "0.6"; + room = "-1000.0"; + roomHF = "-400"; + roomLF = "0"; + decayTime = "17.23"; + decayHFRatio = "0.56"; + decayLFRatio = "1.0"; + reflections = "-1713"; + reflectionsDelay = "0.02"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + reverb = "-613"; + reverbDelay = "0.03"; + reverbPan[ 0 ] = "0.0"; + reverbPan[ 1 ] = "0.0"; + reverbPan[ 2 ] = "0.0"; + echoTime = "0.25"; + echoDepth = "1.0"; + modulationTime = "0.81"; + modulationDepth = "0.31"; + airAbsorptionHF = "-5.0"; + HFReference = "5000.0"; + LFReference = "250.0"; + roomRolloffFactor = "0.0"; + diffusion = "100.0"; + density = "100.0"; + flags = 0x1f; +}; + +singleton SFXEnvironment( AudioEnvPsychotic ) +{ + envSize = "1.0"; + envDiffusion = "0.5"; + room = "-1000"; + roomHF = "-151"; + roomLF = "0"; + decayTime = "7.56"; + decayHFRatio = "0.91"; + decayLFRatio = "1.0"; + reflections = "-626"; + reflectionsDelay = "0.02"; + reflectionsPan[ 0 ] = "0.0"; + reflectionsPan[ 1 ] = "0.0"; + reflectionsPan[ 2 ] = "0.0"; + reverb = "774"; + reverbDelay = "0.03"; + reverbPan[ 0 ] = "0.0"; + reverbPan[ 1 ] = "0.0"; + reverbPan[ 2 ] = "0.0"; + echoTime = "0.25"; + echoDepth = "0.0"; + modulationTime = "4.0"; + modulationDepth = "1.0"; + airAbsorptionHF = "-5.0"; + HFReference = "5000.0"; + LFReference = "250.0"; + roomRolloffFactor = "0.0"; + diffusion = "100.0"; + density = "100.0"; + flags = 0x1f; +}; diff --git a/Templates/BaseGame/game/core/sfx/scripts/audioStates.cs b/Templates/BaseGame/game/core/sfx/scripts/audioStates.cs new file mode 100644 index 000000000..3ab55cf78 --- /dev/null +++ b/Templates/BaseGame/game/core/sfx/scripts/audioStates.cs @@ -0,0 +1,158 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// Some state presets. + + +/// Return the first active SFXState in the given SimSet/SimGroup. +function sfxGetActiveStateInGroup( %group ) +{ + %count = %group.getCount(); + for( %i = 0; %i < %count; %i ++ ) + { + %obj = %group.getObject( %i ); + if( !%obj.isMemberOfClass( "SFXState" ) ) + continue; + + if( %obj.isActive() ) + return %obj; + } + + return 0; +} + + +//----------------------------------------------------------------------------- +// Special audio state that will always and only be active when no other +// state is active. Useful for letting slots apply specifically when no +// other slot in a list applies. + +singleton SFXState( AudioStateNone ) {}; + +AudioStateNone.activate(); + +function SFXState::onActivate( %this ) +{ + if( %this.getId() != AudioStateNone.getId() ) + AudioStateNone.disable(); +} + +function SFXState::onDeactivate( %this ) +{ + if( %this.getId() != AudioStateNone.getId() ) + AudioStateNone.enable(); +} + +//----------------------------------------------------------------------------- +// AudioStateExclusive class. +// +// Automatically deactivates sibling SFXStates in its parent SimGroup +// when activated. + +function AudioStateExclusive::onActivate( %this ) +{ + Parent::onActivate( %this ); + + %group = %this.parentGroup; + %count = %group.getCount(); + + for( %i = 0; %i < %count; %i ++ ) + { + %obj = %group.getObject( %i ); + + if( %obj != %this && %obj.isMemberOfClass( "SFXState" ) && %obj.isActive() ) + %obj.deactivate(); + } +} + +//----------------------------------------------------------------------------- +// Location-dependent states. + +singleton SimGroup( AudioLocation ); + +/// State when the listener is outside. +singleton SFXState( AudioLocationOutside ) +{ + parentGroup = AudioLocation; + className = "AudioStateExclusive"; +}; + +/// State when the listener is submerged. +singleton SFXState( AudioLocationUnderwater ) +{ + parentGroup = AudioLocation; + className = "AudioStateExclusive"; +}; + +/// State when the listener is indoors. +singleton SFXState( AudioLocationInside ) +{ + parentGroup = AudioLocation; + className = "AudioStateExclusive"; +}; + +/// Return the currently active SFXState in AudioLocation. +function sfxGetLocation() +{ + return sfxGetActiveStateInGroup( AudioLocation ); +} + +//----------------------------------------------------------------------------- +// Mood-dependent states. + +singleton SimGroup( AudioMood ); + +singleton SFXState( AudioMoodNeutral ) +{ + parentGroup = AudioMood; + className = "AudioStateExclusive"; +}; + +singleton SFXState( AudioMoodAggressive ) +{ + parentGroup = AudioMood; + className = "AudioStateExclusive"; +}; + +singleton SFXState( AudioMoodTense ) +{ + parentGroup = AudioMood; + className = "AudioStateExclusive"; +}; + +singleton SFXState( AudioMoodVictory ) +{ + parentGroup = AudioMood; + className = "AudioStateExclusive"; +}; + +singleton SFXState( AudioMoodCalm ) +{ + parentGroup = AudioMood; + className = "AudioStateExclusive"; +}; + +/// Return the currently active SFXState in AudioMood. +function sfxGetMood() +{ + return sfxGetActiveStateInGroup( AudioMood ); +} diff --git a/Templates/BaseGame/game/core/utility/Core_Utility.cs b/Templates/BaseGame/game/core/utility/Core_Utility.cs new file mode 100644 index 000000000..d412f3544 --- /dev/null +++ b/Templates/BaseGame/game/core/utility/Core_Utility.cs @@ -0,0 +1,11 @@ + +function Core_Utility::onCreate(%this) +{ + exec("./scripts/parseArgs.cs"); + exec("./scripts/globals.cs"); + exec("./scripts/helperFunctions.cs"); +} + +function Core_Utility::onDestroy(%this) +{ +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/utility/Core_Utility.module b/Templates/BaseGame/game/core/utility/Core_Utility.module new file mode 100644 index 000000000..cb6539040 --- /dev/null +++ b/Templates/BaseGame/game/core/utility/Core_Utility.module @@ -0,0 +1,9 @@ + + \ No newline at end of file diff --git a/Templates/BaseGame/game/core/utility/scripts/globals.cs b/Templates/BaseGame/game/core/utility/scripts/globals.cs new file mode 100644 index 000000000..fcf52390a --- /dev/null +++ b/Templates/BaseGame/game/core/utility/scripts/globals.cs @@ -0,0 +1,102 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// ---------------------------------------------------------------------------- +// DInput keyboard, mouse, and joystick prefs +// ---------------------------------------------------------------------------- + +$pref::Input::MouseEnabled = 1; +$pref::Input::LinkMouseSensitivity = 1; +$pref::Input::KeyboardEnabled = 1; +$pref::Input::KeyboardTurnSpeed = 0.1; +$pref::Input::JoystickEnabled = 0; + +// ---------------------------------------------------------------------------- +// Video Preferences +// ---------------------------------------------------------------------------- + +// Set directory paths for various data or default images. +$pref::Video::ProfilePath = "core/rendering/scripts/gfxprofile"; +/*$pref::Video::missingTexturePath = "core/images/missingTexture.png"; +$pref::Video::unavailableTexturePath = "core/images/unavailable.png"; +$pref::Video::warningTexturePath = "core/images/warnMat.dds";*/ + +$pref::Video::disableVerticalSync = 1; +$pref::Video::mode = "800 600 false 32 60 4"; +$pref::Video::defaultFenceCount = 0; + +// This disables the hardware FSAA/MSAA so that we depend completely on the FXAA +// post effect which works on all cards and in deferred mode. Note that the new +// Intel Hybrid graphics on laptops will fail to initialize when hardware AA is +// enabled... so you've been warned. +$pref::Video::disableHardwareAA = true; + +$pref::Video::disableNormalmapping = false; +$pref::Video::disablePixSpecular = false; +$pref::Video::disableCubemapping = false; +$pref::Video::disableParallaxMapping = false; + +// The number of mipmap levels to drop on loaded textures to reduce video memory +// usage. It will skip any textures that have been defined as not allowing down +// scaling. +$pref::Video::textureReductionLevel = 0; + +$pref::Video::defaultAnisotropy = 1; +//$pref::Video::Gamma = 1.0; + +/// AutoDetect graphics quality levels the next startup. +$pref::Video::autoDetect = 1; + +// ---------------------------------------------------------------------------- +// Shader stuff +// ---------------------------------------------------------------------------- + +// This is the path used by ShaderGen to cache procedural shaders. If left +// blank ShaderGen will only cache shaders to memory and not to disk. +$shaderGen::cachePath = "data/shaderCache"; + +// Uncomment to disable ShaderGen, useful when debugging +//$ShaderGen::GenNewShaders = false; + +// Uncomment to dump disassembly for any shader that is compiled to disk. These +// will appear as shadername_dis.txt in the same path as the shader file. +//$gfx::disassembleAllShaders = true; + +// ---------------------------------------------------------------------------- +// Lighting and shadowing +// ---------------------------------------------------------------------------- + +// Uncomment to enable AdvancedLighting on the Mac (T3D 2009 Beta 3) +//$pref::machax::enableAdvancedLighting = true; + +$sceneLighting::cacheSize = 20000; +$sceneLighting::purgeMethod = "lastCreated"; +$sceneLighting::cacheLighting = 1; + +$pref::Shadows::textureScalar = 1.0; +$pref::Shadows::disable = false; + +// Sets the shadow filtering mode. +// None - Disables filtering. +// SoftShadow - Does a simple soft shadow +// SoftShadowHighQuality +$pref::Shadows::filterMode = "SoftShadow"; diff --git a/Templates/BaseGame/game/core/utility/scripts/helperFunctions.cs b/Templates/BaseGame/game/core/utility/scripts/helperFunctions.cs new file mode 100644 index 000000000..8abe3e6e6 --- /dev/null +++ b/Templates/BaseGame/game/core/utility/scripts/helperFunctions.cs @@ -0,0 +1,1158 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + + +//------------------------------------------------------------------------------ +// Check if a script file exists, compiled or not. +function isScriptFile(%path) +{ + if( isFile(%path @ ".dso") || isFile(%path) ) + return true; + + return false; +} + +function loadMaterials() +{ + // Load any materials files for which we only have DSOs. + + for( %file = findFirstFile( "*/materials.cs.dso" ); + %file !$= ""; + %file = findNextFile( "*/materials.cs.dso" )) + { + // Only execute, if we don't have the source file. + %csFileName = getSubStr( %file, 0, strlen( %file ) - 4 ); + if( !isFile( %csFileName ) ) + exec( %csFileName ); + } + + // Load all source material files. + + for( %file = findFirstFile( "*/materials.cs" ); + %file !$= ""; + %file = findNextFile( "*/materials.cs" )) + { + exec( %file ); + } + + // Load all materials created by the material editor if + // the folder exists + if( IsDirectory( "materialEditor" ) ) + { + for( %file = findFirstFile( "materialEditor/*.cs.dso" ); + %file !$= ""; + %file = findNextFile( "materialEditor/*.cs.dso" )) + { + // Only execute, if we don't have the source file. + %csFileName = getSubStr( %file, 0, strlen( %file ) - 4 ); + if( !isFile( %csFileName ) ) + exec( %csFileName ); + } + + for( %file = findFirstFile( "materialEditor/*.cs" ); + %file !$= ""; + %file = findNextFile( "materialEditor/*.cs" )) + { + exec( %file ); + } + } +} + +function reloadMaterials() +{ + reloadTextures(); + loadMaterials(); + reInitMaterials(); +} + +function loadDatablockFiles( %datablockFiles, %recurse ) +{ + if ( %recurse ) + { + recursiveLoadDatablockFiles( %datablockFiles, 9999 ); + return; + } + + %count = %datablockFiles.count(); + for ( %i=0; %i < %count; %i++ ) + { + %file = %datablockFiles.getKey( %i ); + if ( !isFile(%file @ ".dso") && !isFile(%file) ) + continue; + + exec( %file ); + } + + // Destroy the incoming list. + //%datablockFiles.delete(); +} + +function recursiveLoadDatablockFiles( %datablockFiles, %previousErrors ) +{ + %reloadDatablockFiles = new ArrayObject(); + + // Keep track of the number of datablocks that + // failed during this pass. + %failedDatablocks = 0; + + // Try re-executing the list of datablock files. + %count = %datablockFiles.count(); + for ( %i=0; %i < %count; %i++ ) + { + %file = %datablockFiles.getKey( %i ); + if ( !isFile(%file @ ".dso") && !isFile(%file) ) + continue; + + // Start counting copy constructor creation errors. + $Con::objectCopyFailures = 0; + + exec( %file ); + + // If errors occured then store this file for re-exec later. + if ( $Con::objectCopyFailures > 0 ) + { + %reloadDatablockFiles.add( %file ); + %failedDatablocks = %failedDatablocks + $Con::objectCopyFailures; + } + } + + // Clear the object copy failure counter so that + // we get console error messages again. + $Con::objectCopyFailures = -1; + + // Delete the old incoming list... we're done with it. + //%datablockFiles.delete(); + + // If we still have datablocks to retry. + %newCount = %reloadDatablockFiles.count(); + if ( %newCount > 0 ) + { + // If the datablock failures have not been reduced + // from the last pass then we must have a real syntax + // error and not just a bad dependancy. + if ( %previousErrors > %failedDatablocks ) + recursiveLoadDatablockFiles( %reloadDatablockFiles, %failedDatablocks ); + + else + { + // Since we must have real syntax errors do one + // last normal exec to output error messages. + loadDatablockFiles( %reloadDatablockFiles, false ); + } + + return; + } + + // Cleanup the empty reload list. + %reloadDatablockFiles.delete(); +} + +function getUserPath() +{ + %temp = getUserHomeDirectory(); + echo(%temp); + if(!isDirectory(%temp)) + { + %temp = getUserDataDirectory(); + echo(%temp); + if(!isDirectory(%temp)) + { + %userPath = "data"; + } + else + { + //put it in appdata/roaming + %userPath = %temp @ "/" @ $appName; + } + } + else + { + //put it in user/documents + %userPath = %temp @ "/" @ $appName; + } + return %userPath; +} + +function getPrefpath() +{ + $prefPath = getUserPath() @ "/preferences"; + return $prefPath; +} + +function updateTSShapeLoadProgress(%progress, %msg) +{ + // Check if the loading GUI is visible and use that instead of the + // separate import progress GUI if possible + /* if ( isObject(LoadingGui) && LoadingGui.isAwake() ) + { + // Save/Restore load progress at the start/end of the import process + if ( %progress == 0 ) + { + ColladaImportProgress.savedProgress = LoadingProgress.getValue(); + ColladaImportProgress.savedText = LoadingProgressTxt.getValue(); + + ColladaImportProgress.msgPrefix = "Importing " @ %msg; + %msg = "Reading file into memory..."; + } + else if ( %progress == 1.0 ) + { + LoadingProgress.setValue( ColladaImportProgress.savedProgress ); + LoadingProgressTxt.setValue( ColladaImportProgress.savedText ); + } + + %msg = ColladaImportProgress.msgPrefix @ ": " @ %msg; + + %progressCtrl = LoadingProgress; + %textCtrl = LoadingProgressTxt; + } + else + { + //it's probably the editors using it + if(isFunction("updateToolTSShapeLoadProgress")) + { + updateToolTSShapeLoadProgress(%progress, %msg); + } + } + + // Update progress indicators + if (%progress == 0) + { + %progressCtrl.setValue(0.001); + %textCtrl.setText(%msg); + } + else if (%progress != 1.0) + { + %progressCtrl.setValue(%progress); + %textCtrl.setText(%msg); + } + + Canvas.repaint(33);*/ +} + +/// A helper function which will return the ghosted client object +/// from a server object when connected to a local server. +function serverToClientObject( %serverObject ) +{ + assert( isObject( LocalClientConnection ), "serverToClientObject() - No local client connection found!" ); + assert( isObject( ServerConnection ), "serverToClientObject() - No server connection found!" ); + + %ghostId = LocalClientConnection.getGhostId( %serverObject ); + if ( %ghostId == -1 ) + return 0; + + return ServerConnection.resolveGhostID( %ghostId ); +} + +//---------------------------------------------------------------------------- +// Debug commands +//---------------------------------------------------------------------------- + +function netSimulateLag( %msDelay, %packetLossPercent ) +{ + if ( %packetLossPercent $= "" ) + %packetLossPercent = 0; + + commandToServer( 'NetSimulateLag', %msDelay, %packetLossPercent ); +} + +//Various client functions + +function validateDatablockName(%name) +{ + // remove whitespaces at beginning and end + %name = trim( %name ); + + // remove numbers at the beginning + %numbers = "0123456789"; + while( strlen(%name) > 0 ) + { + // the first character + %firstChar = getSubStr( %name, 0, 1 ); + // if the character is a number remove it + if( strpos( %numbers, %firstChar ) != -1 ) + { + %name = getSubStr( %name, 1, strlen(%name) -1 ); + %name = ltrim( %name ); + } + else + break; + } + + // replace whitespaces with underscores + %name = strreplace( %name, " ", "_" ); + + // remove any other invalid characters + %invalidCharacters = "-+*/%$&§=()[].?\"#,;!~<>|°^{}"; + %name = stripChars( %name, %invalidCharacters ); + + if( %name $= "" ) + %name = "Unnamed"; + + return %name; +} + +//-------------------------------------------------------------------------- +// Finds location of %word in %text, starting at %start. Works just like strPos +//-------------------------------------------------------------------------- + +function wordPos(%text, %word, %start) +{ + if (%start $= "") %start = 0; + + if (strpos(%text, %word, 0) == -1) return -1; + %count = getWordCount(%text); + if (%start >= %count) return -1; + for (%i = %start; %i < %count; %i++) + { + if (getWord( %text, %i) $= %word) return %i; + } + return -1; +} + +//-------------------------------------------------------------------------- +// Finds location of %field in %text, starting at %start. Works just like strPos +//-------------------------------------------------------------------------- + +function fieldPos(%text, %field, %start) +{ + if (%start $= "") %start = 0; + + if (strpos(%text, %field, 0) == -1) return -1; + %count = getFieldCount(%text); + if (%start >= %count) return -1; + for (%i = %start; %i < %count; %i++) + { + if (getField( %text, %i) $= %field) return %i; + } + return -1; +} + +//-------------------------------------------------------------------------- +// returns the text in a file with "\n" at the end of each line +//-------------------------------------------------------------------------- + +function loadFileText( %file) +{ + %fo = new FileObject(); + %fo.openForRead(%file); + %text = ""; + while(!%fo.isEOF()) + { + %text = %text @ %fo.readLine(); + if (!%fo.isEOF()) %text = %text @ "\n"; + } + + %fo.delete(); + return %text; +} + +function setValueSafe(%dest, %val) +{ + %cmd = %dest.command; + %alt = %dest.altCommand; + %dest.command = ""; + %dest.altCommand = ""; + + %dest.setValue(%val); + + %dest.command = %cmd; + %dest.altCommand = %alt; +} + +function shareValueSafe(%source, %dest) +{ + setValueSafe(%dest, %source.getValue()); +} + +function shareValueSafeDelay(%source, %dest, %delayMs) +{ + schedule(%delayMs, 0, shareValueSafe, %source, %dest); +} + + +//------------------------------------------------------------------------------ +// An Aggregate Control is a plain GuiControl that contains other controls, +// which all share a single job or represent a single value. +//------------------------------------------------------------------------------ + +// AggregateControl.setValue( ) propagates the value to any control that has an +// internal name. +function AggregateControl::setValue(%this, %val, %child) +{ + for(%i = 0; %i < %this.getCount(); %i++) + { + %obj = %this.getObject(%i); + if( %obj == %child ) + continue; + + if(%obj.internalName !$= "") + setValueSafe(%obj, %val); + } +} + +// AggregateControl.getValue() uses the value of the first control that has an +// internal name, if it has not cached a value via .setValue +function AggregateControl::getValue(%this) +{ + for(%i = 0; %i < %this.getCount(); %i++) + { + %obj = %this.getObject(%i); + if(%obj.internalName !$= "") + { + //error("obj = " @ %obj.getId() @ ", " @ %obj.getName() @ ", " @ %obj.internalName ); + //error(" value = " @ %obj.getValue()); + return %obj.getValue(); + } + } +} + +// AggregateControl.updateFromChild( ) is called by child controls to propagate +// a new value, and to trigger the onAction() callback. +function AggregateControl::updateFromChild(%this, %child) +{ + %val = %child.getValue(); + if(%val == mCeil(%val)){ + %val = mCeil(%val); + }else{ + if ( %val <= -100){ + %val = mCeil(%val); + }else if ( %val <= -10){ + %val = mFloatLength(%val, 1); + }else if ( %val < 0){ + %val = mFloatLength(%val, 2); + }else if ( %val >= 1000){ + %val = mCeil(%val); + }else if ( %val >= 100){ + %val = mFloatLength(%val, 1); + }else if ( %val >= 10){ + %val = mFloatLength(%val, 2); + }else if ( %val > 0){ + %val = mFloatLength(%val, 3); + } + } + %this.setValue(%val, %child); + %this.onAction(); +} + +// default onAction stub, here only to prevent console spam warnings. +function AggregateControl::onAction(%this) +{ +} + +// call a method on all children that have an internalName and that implement the method. +function AggregateControl::callMethod(%this, %method, %args) +{ + for(%i = 0; %i < %this.getCount(); %i++) + { + %obj = %this.getObject(%i); + if(%obj.internalName !$= "" && %obj.isMethod(%method)) + eval(%obj @ "." @ %method @ "( " @ %args @ " );"); + } + +} + +//------------------------------------------------------------------------------ +// Altered Version of TGB's QuickEditDropDownTextEditCtrl +//------------------------------------------------------------------------------ +function QuickEditDropDownTextEditCtrl::onRenameItem( %this ) +{ +} + +function QuickEditDropDownTextEditCtrl::updateFromChild( %this, %ctrl ) +{ + if( %ctrl.internalName $= "PopUpMenu" ) + { + %this->TextEdit.setText( %ctrl.getText() ); + } + else if ( %ctrl.internalName $= "TextEdit" ) + { + %popup = %this->PopupMenu; + %popup.changeTextById( %popup.getSelected(), %ctrl.getText() ); + %this.onRenameItem(); + } +} + +// Writes out all script functions to a file. +function writeOutFunctions() +{ + new ConsoleLogger(logger, "scriptFunctions.txt", false); + dumpConsoleFunctions(); + logger.delete(); +} + +// Writes out all script classes to a file. +function writeOutClasses() +{ + new ConsoleLogger(logger, "scriptClasses.txt", false); + dumpConsoleClasses(); + logger.delete(); +} + +// +function compileFiles(%pattern) +{ + %path = filePath(%pattern); + + %saveDSO = $Scripts::OverrideDSOPath; + %saveIgnore = $Scripts::ignoreDSOs; + + $Scripts::OverrideDSOPath = %path; + $Scripts::ignoreDSOs = false; + %mainCsFile = makeFullPath("main.cs"); + + for (%file = findFirstFileMultiExpr(%pattern); %file !$= ""; %file = findNextFileMultiExpr(%pattern)) + { + // we don't want to try and compile the primary main.cs + if(%mainCsFile !$= %file) + compile(%file, true); + } + + $Scripts::OverrideDSOPath = %saveDSO; + $Scripts::ignoreDSOs = %saveIgnore; + +} + +function displayHelp() +{ + // Notes on logmode: console logging is written to console.log. + // -log 0 disables console logging. + // -log 1 appends to existing logfile; it also closes the file + // (flushing the write buffer) after every write. + // -log 2 overwrites any existing logfile; it also only closes + // the logfile when the application shuts down. (default) + + error( + "Torque Demo command line options:\n"@ + " -log Logging behavior; see main.cs comments for details\n"@ + " -game Reset list of mods to only contain \n"@ + " Works like the -game argument\n"@ + " -dir Add to list of directories\n"@ + " -console Open a separate console\n"@ + " -jSave Record a journal\n"@ + " -jPlay Play back a journal\n"@ + " -help Display this help message\n" + ); +} + +// Execute startup scripts for each mod, starting at base and working up +function loadDir(%dir) +{ + pushback($userDirs, %dir, ";"); + + if (isScriptFile(%dir @ "/main.cs")) + exec(%dir @ "/main.cs"); +} + +function loadDirs(%dirPath) +{ + %dirPath = nextToken(%dirPath, token, ";"); + if (%dirPath !$= "") + loadDirs(%dirPath); + + if(exec(%token @ "/main.cs") != true) + { + error("Error: Unable to find specified directory: " @ %token ); + $dirCount--; + } +} + +//------------------------------------------------------------------------------ +// Utility remap functions: +//------------------------------------------------------------------------------ + +function ActionMap::copyBind( %this, %otherMap, %command ) +{ + if ( !isObject( %otherMap ) ) + { + error( "ActionMap::copyBind - \"" @ %otherMap @ "\" is not an object!" ); + return; + } + + %bind = %otherMap.getBinding( %command ); + if ( %bind !$= "" ) + { + %device = getField( %bind, 0 ); + %action = getField( %bind, 1 ); + %flags = %otherMap.isInverted( %device, %action ) ? "SDI" : "SD"; + %deadZone = %otherMap.getDeadZone( %device, %action ); + %scale = %otherMap.getScale( %device, %action ); + %this.bind( %device, %action, %flags, %deadZone, %scale, %command ); + } +} + +//------------------------------------------------------------------------------ +function ActionMap::blockBind( %this, %otherMap, %command ) +{ + if ( !isObject( %otherMap ) ) + { + error( "ActionMap::blockBind - \"" @ %otherMap @ "\" is not an object!" ); + return; + } + + %bind = %otherMap.getBinding( %command ); + if ( %bind !$= "" ) + %this.bind( getField( %bind, 0 ), getField( %bind, 1 ), "" ); +} + +//Dev helpers +/// Shortcut for typing dbgSetParameters with the default values torsion uses. +function dbgTorsion() +{ + dbgSetParameters( 6060, "password", false ); +} + +/// Reset the input state to a default of all-keys-up. +/// A helpful remedy for when Torque misses a button up event do to your breakpoints +/// and can't stop shooting / jumping / strafing. +function mvReset() +{ + for ( %i = 0; %i < 6; %i++ ) + setVariable( "mvTriggerCount" @ %i, 0 ); + + $mvUpAction = 0; + $mvDownAction = 0; + $mvLeftAction = 0; + $mvRightAction = 0; + + // There are others. +} + +//Persistance Manager tests + +new PersistenceManager(TestPManager); + +function runPManTest(%test) +{ + if (!isObject(TestPManager)) + return; + + if (%test $= "") + %test = 100; + + switch(%test) + { + case 0: + TestPManager.testFieldUpdates(); + case 1: + TestPManager.testObjectRename(); + case 2: + TestPManager.testNewObject(); + case 3: + TestPManager.testNewGroup(); + case 4: + TestPManager.testMoveObject(); + case 5: + TestPManager.testObjectRemove(); + case 100: + TestPManager.testFieldUpdates(); + TestPManager.testObjectRename(); + TestPManager.testNewObject(); + TestPManager.testNewGroup(); + TestPManager.testMoveObject(); + TestPManager.testObjectRemove(); + } +} + +function TestPManager::testFieldUpdates(%doNotSave) +{ + // Set some objects as dirty + TestPManager.setDirty(AudioGui); + TestPManager.setDirty(AudioSim); + TestPManager.setDirty(AudioMessage); + + // Alter some of the existing fields + AudioEffect.isLooping = true; + AudioMessage.isLooping = true; + AudioEffect.is3D = true; + + // Test removing a field + TestPManager.removeField(AudioGui, "isLooping"); + + // Alter some of the persistent fields + AudioGui.referenceDistance = 0.8; + AudioMessage.referenceDistance = 0.8; + + // Add some new dynamic fields + AudioGui.foo = "bar"; + AudioEffect.foo = "bar"; + + // Remove an object from the dirty list + // It shouldn't get updated in the file + TestPManager.removeDirty(AudioEffect); + + // Dirty an object in another file as well + TestPManager.setDirty(WarningMaterial); + + // Update a field that doesn't exist + WarningMaterial.glow[0] = true; + + // Drity another object to test for crashes + // when a dirty object is deleted + TestPManager.setDirty(SFXPausedSet); + + // Delete the object + SFXPausedSet.delete(); + + // Unless %doNotSave is set (by a batch/combo test) + // then go ahead and save now + if (!%doNotSave) + TestPManager.saveDirty(); +} + +function TestPManager::testObjectRename(%doNotSave) +{ + // Flag an object as dirty + if (isObject(AudioGui)) + TestPManager.setDirty(AudioGui); + else if (isObject(AudioGuiFoo)) + TestPManager.setDirty(AudioGuiFoo); + + // Rename it + if (isObject(AudioGui)) + AudioGui.setName(AudioGuiFoo); + else if (isObject(AudioGuiFoo)) + AudioGuiFoo.setName(AudioGui); + + // Unless %doNotSave is set (by a batch/combo test) + // then go ahead and save now + if (!%doNotSave) + TestPManager.saveDirty(); +} + +function TestPManager::testNewObject(%doNotSave) +{ + // Test adding a new named object + new SFXDescription(AudioNew) + { + volume = 0.5; + isLooping = true; + channel = $GuiAudioType; + foo = 2; + }; + + // Flag it as dirty + TestPManager.setDirty(AudioNew, "core/scripts/client/audio.cs"); + + // Test adding a new unnamed object + %obj = new SFXDescription() + { + volume = 0.75; + isLooping = true; + bar = 3; + }; + + // Flag it as dirty + TestPManager.setDirty(%obj, "core/scripts/client/audio.cs"); + + // Test adding an "empty" object + new SFXDescription(AudioEmpty); + + TestPManager.setDirty(AudioEmpty, "core/scripts/client/audio.cs"); + + // Unless %doNotSave is set (by a batch/combo test) + // then go ahead and save now + if (!%doNotSave) + TestPManager.saveDirty(); +} + +function TestPManager::testNewGroup(%doNotSave) +{ + // Test adding a new named SimGroup + new SimGroup(TestGroup) + { + foo = "bar"; + + new SFXDescription(TestObject) + { + volume = 0.5; + isLooping = true; + channel = $GuiAudioType; + foo = 1; + }; + new SimGroup(SubGroup) + { + foo = 2; + + new SFXDescription(SubObject) + { + volume = 0.5; + isLooping = true; + channel = $GuiAudioType; + foo = 3; + }; + }; + }; + + // Flag this as dirty + TestPManager.setDirty(TestGroup, "core/scripts/client/audio.cs"); + + // Test adding a new unnamed SimGroup + %group = new SimGroup() + { + foo = "bar"; + + new SFXDescription() + { + volume = 0.75; + channel = $GuiAudioType; + foo = 4; + }; + new SimGroup() + { + foo = 5; + + new SFXDescription() + { + volume = 0.75; + isLooping = true; + channel = $GuiAudioType; + foo = 6; + }; + }; + }; + + // Flag this as dirty + TestPManager.setDirty(%group, "core/scripts/client/audio.cs"); + + // Test adding a new unnamed SimSet + %set = new SimSet() + { + foo = "bar"; + + new SFXDescription() + { + volume = 0.75; + channel = $GuiAudioType; + foo = 7; + }; + new SimGroup() + { + foo = 8; + + new SFXDescription() + { + volume = 0.75; + isLooping = true; + channel = $GuiAudioType; + foo = 9; + }; + }; + }; + + // Flag this as dirty + TestPManager.setDirty(%set, "core/scripts/client/audio.cs"); + + // Unless %doNotSave is set (by a batch/combo test) + // then go ahead and save now + if (!%doNotSave) + TestPManager.saveDirty(); +} + +function TestPManager::testMoveObject(%doNotSave) +{ + // First add a couple of groups to the file + new SimGroup(MoveGroup1) + { + foo = "bar"; + + new SFXDescription(MoveObject1) + { + volume = 0.5; + isLooping = true; + channel = $GuiAudioType; + foo = 1; + }; + + new SimSet(SubGroup1) + { + new SFXDescription(SubObject1) + { + volume = 0.75; + isLooping = true; + channel = $GuiAudioType; + foo = 2; + }; + }; + }; + + // Flag this as dirty + TestPManager.setDirty(MoveGroup1, "core/scripts/client/audio.cs"); + + new SimGroup(MoveGroup2) + { + foo = "bar"; + + new SFXDescription(MoveObject2) + { + volume = 0.5; + isLooping = true; + channel = $GuiAudioType; + foo = 3; + }; + }; + + // Flag this as dirty + TestPManager.setDirty(MoveGroup2, "core/scripts/client/audio.cs"); + + // Unless %doNotSave is set (by a batch/combo test) + // then go ahead and save now + if (!%doNotSave) + TestPManager.saveDirty(); + + // Set them as dirty again + TestPManager.setDirty(MoveGroup1); + TestPManager.setDirty(MoveGroup2); + + // Give the subobject an new value + MoveObject1.foo = 4; + + // Move it into the other group + MoveGroup1.add(MoveObject2); + + // Switch the other subobject + MoveGroup2.add(MoveObject1); + + // Also add a new unnamed object to one of the groups + %obj = new SFXDescription() + { + volume = 0.75; + isLooping = true; + bar = 5; + }; + + MoveGroup1.add(%obj); + + // Unless %doNotSave is set (by a batch/combo test) + // then go ahead and save now + if (!%doNotSave) + TestPManager.saveDirty(); +} + +function TestPManager::testObjectRemove(%doNotSave) +{ + TestPManager.removeObjectFromFile(AudioSim); +} + +//Game Object management +function findGameObject(%name) +{ + //find all GameObjectAssets + %assetQuery = new AssetQuery(); + if(!AssetDatabase.findAssetType(%assetQuery, "GameObjectAsset")) + return 0; //if we didn't find ANY, just exit + + %count = %assetQuery.getCount(); + + for(%i=0; %i < %count; %i++) + { + %assetId = %assetQuery.getAsset(%i); + + //%assetName = AssetDatabase.getAssetName(%assetId); + + if(%assetId $= %name) + { + %gameObjectAsset = AssetDatabase.acquireAsset(%assetId); + + %assetQuery.delete(); + return %gameObjectAsset; + } + } + + %assetQuery.delete(); + return 0; +} + +function spawnGameObject(%name, %addToMissionGroup) +{ + if(%addToMissionGroup $= "") + %addToMissionGroup = true; + + //First, check if this already exists in our GameObjectPool + if(isObject(GameObjectPool)) + { + %goCount = GameObjectPool.countKey(%name); + + //if we have some already in the pool, pull it out and use that + if(%goCount != 0) + { + %goIdx = GameObjectPool.getIndexFromKey(%name); + %go = GameObjectPool.getValue(%goIdx); + + %go.setHidden(false); + %go.setScopeAlways(); + + if(%addToMissionGroup == true) //save instance when saving level + MissionGroup.add(%go); + else // clear instance on level exit + MissionCleanup.add(%go); + + //remove from the object pool's list + GameObjectPool.erase(%goIdx); + + return %go; + } + } + + //We have no existing pool, or no existing game objects of this type, so spawn a new one + + %gameObjectAsset = findGameObject(%name); + + if(isObject(%gameObjectAsset)) + { + %newSGOObject = TamlRead(%gameObjectAsset.TAMLFilePath); + + if(%addToMissionGroup == true) //save instance when saving level + MissionGroup.add(%newSGOObject); + else // clear instance on level exit + MissionCleanup.add(%newSGOObject); + + return %newSGOObject; + } + + return 0; +} + +function saveGameObject(%name, %tamlPath, %scriptPath) +{ + %gameObjectAsset = findGameObject(%name); + + //find if it already exists. If it does, we'll update it, if it does not, we'll make a new asset + if(isObject(%gameObjectAsset)) + { + %assetID = %gameObjectAsset.getAssetId(); + + %gameObjectAsset.TAMLFilePath = %tamlPath; + %gameObjectAsset.scriptFilePath = %scriptPath; + + TAMLWrite(%gameObjectAsset, AssetDatabase.getAssetFilePath(%assetID)); + AssetDatabase.refreshAsset(%assetID); + } + else + { + //Doesn't exist, so make a new one + %gameObjectAsset = new GameObjectAsset() + { + assetName = %name @ "Asset"; + gameObjectName = %name; + TAMLFilePath = %tamlPath; + scriptFilePath = %scriptPath; + }; + + //Save it alongside the taml file + %path = filePath(%tamlPath); + + TAMLWrite(%gameObjectAsset, %path @ "/" @ %name @ ".asset.taml"); + AssetDatabase.refreshAllAssets(true); + } +} + +//Allocates a number of a game object into a pool to be pulled from as needed +function allocateGameObjects(%name, %amount) +{ + //First, we need to make sure our pool exists + if(!isObject(GameObjectPool)) + { + new ArrayObject(GameObjectPool); + } + + //Next, we loop and generate our game objects, and add them to the pool + for(%i=0; %i < %amount; %i++) + { + %go = spawnGameObject(%name, false); + + //When our object is in the pool, it's not "real", so we need to make sure + //that we don't ghost it to clients untill we actually spawn it. + %go.clearScopeAlways(); + + //We also hide it, so that we don't 'exist' in the scene until we spawn + %go.hidden = true; + + //Lastly, add us to the pool, with the key being our game object type + GameObjectPool.add(%name, %go); + } +} + +function Entity::delete(%this) +{ + //we want to intercept the delete call, and add it to our GameObjectPool + //if it's a game object + if(%this.gameObjectAsset !$= "") + { + %this.setHidden(true); + %this.clearScopeAlways(); + + if(!isObject(GameObjectPool)) + { + new ArrayObject(GameObjectPool); + } + + GameObjectPool.add(%this.gameObjectAsset, %this); + + %missionSet = %this.getGroup(); + %missionSet.remove(%this); + } + else + { + %this.superClass.delete(); + } +} + +function clearGameObjectPool() +{ + if(isObject(GameObjectPool)) + { + %count = GameObjectPool.count(); + + for(%i=0; %i < %count; %i++) + { + %go = GameObjectPool.getValue(%i); + + %go.superClass.delete(); + } + + GameObjectPool.empty(); + } +} + +// +function switchCamera(%client, %newCamEntity) +{ + if(!isObject(%client) || !isObject(%newCamEntity)) + return error("SwitchCamera: No client or target camera!"); + + %cam = %newCamEntity.getComponent(CameraComponent); + + if(!isObject(%cam)) + return error("SwitchCamera: Target camera doesn't have a camera behavior!"); + + //TODO: Cleanup clientOwner for previous camera! + if(%cam.clientOwner == 0 || %cam.clientOwner $= "") + %cam.clientOwner = 0; + + %cam.scopeToClient(%client); + %cam.setDirty(); + + %client.setCameraObject(%newCamEntity); + %client.setControlCameraFov(%cam.FOV); + + %client.camera = %newCamEntity; +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/utility/scripts/parseArgs.cs b/Templates/BaseGame/game/core/utility/scripts/parseArgs.cs new file mode 100644 index 000000000..811cee00c --- /dev/null +++ b/Templates/BaseGame/game/core/utility/scripts/parseArgs.cs @@ -0,0 +1,392 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Support functions used to manage the directory list +function pushFront(%list, %token, %delim) +{ + if (%list !$= "") + return %token @ %delim @ %list; + return %token; +} + +function pushBack(%list, %token, %delim) +{ + if (%list !$= "") + return %list @ %delim @ %token; + return %token; +} + +function popFront(%list, %delim) +{ + return nextToken(%list, unused, %delim); +} + +function parseArgs() +{ + for ($i = 1; $i < $Game::argc ; $i++) + { + $arg = $Game::argv[$i]; + $nextArg = $Game::argv[$i+1]; + $hasNextArg = $Game::argc - $i > 1; + $logModeSpecified = false; + + // Check for dedicated run + /*if( stricmp($arg,"-dedicated") == 0 ) + { + $userDirs = $defaultGame; + $dirCount = 1; + $isDedicated = true; + }*/ + + switch$ ($arg) + { + //-------------------- + case "-dedicated": + $userDirs = $defaultGame; + $dirCount = 1; + $isDedicated = true; + $Server::Dedicated = true; + enableWinConsole(true); + $argUsed[%i]++; + + //-------------------- + case "-mission": + $argUsed[%i]++; + if ($hasNextArg) + { + $missionArg = $nextArg; + $argUsed[%i+1]++; + %i++; + } + else + error("Error: Missing Command Line argument. Usage: -mission "); + + //-------------------- + case "-connect": + $argUsed[%i]++; + if ($hasNextArg) + { + $JoinGameAddress = $nextArg; + $argUsed[%i+1]++; + %i++; + } + else + error("Error: Missing Command Line argument. Usage: -connect "); + + + //-------------------- + case "-log": + $argUsed[$i]++; + if ($hasNextArg) + { + // Turn on console logging + if ($nextArg != 0) + { + // Dump existing console to logfile first. + $nextArg += 4; + } + setLogMode($nextArg); + $logModeSpecified = true; + $argUsed[$i+1]++; + $i++; + } + else + error("Error: Missing Command Line argument. Usage: -log "); + + //-------------------- + case "-dir": + $argUsed[$i]++; + if ($hasNextArg) + { + // Append the mod to the end of the current list + $userDirs = strreplace($userDirs, $nextArg, ""); + $userDirs = pushFront($userDirs, $nextArg, ";"); + $argUsed[$i+1]++; + $i++; + $dirCount++; + } + else + error("Error: Missing Command Line argument. Usage: -dir "); + + //-------------------- + // changed the default behavior of this command line arg. It now + // defaults to ONLY loading the game, not tools + // default auto-run already loads in tools --SRZ 11/29/07 + case "-game": + $argUsed[$i]++; + if ($hasNextArg) + { + // Set the selected dir --NOTE: we no longer allow tools with this argument + /* + if( $isDedicated ) + { + $userDirs = $nextArg; + $dirCount = 1; + } + else + { + $userDirs = "tools;" @ $nextArg; + $dirCount = 2; + } + */ + $userDirs = $nextArg; + $dirCount = 1; + $argUsed[$i+1]++; + $i++; + error($userDirs); + } + else + error("Error: Missing Command Line argument. Usage: -game "); + + //-------------------- + case "-console": + enableWinConsole(true); + $argUsed[$i]++; + + //-------------------- + case "-jSave": + $argUsed[$i]++; + if ($hasNextArg) + { + echo("Saving event log to journal: " @ $nextArg); + saveJournal($nextArg); + $argUsed[$i+1]++; + $i++; + } + else + error("Error: Missing Command Line argument. Usage: -jSave "); + + //-------------------- + case "-jPlay": + $argUsed[$i]++; + if ($hasNextArg) + { + playJournal($nextArg); + $argUsed[$i+1]++; + $i++; + } + else + error("Error: Missing Command Line argument. Usage: -jPlay "); + + //-------------------- + case "-jPlayToVideo": + $argUsed[$i]++; + if ($hasNextArg) + { + $VideoCapture::journalName = $nextArg; + $VideoCapture::captureFromJournal = true; + $argUsed[$i+1]++; + $i++; + } + else + error("Error: Missing Command Line argument. Usage: -jPlayToVideo "); + + //-------------------- + case "-vidCapFile": + $argUsed[$i]++; + if ($hasNextArg) + { + $VideoCapture::fileName = $nextArg; + $argUsed[$i+1]++; + $i++; + } + else + error("Error: Missing Command Line argument. Usage: -vidCapFile "); + + //-------------------- + case "-vidCapFPS": + $argUsed[$i]++; + if ($hasNextArg) + { + $VideoCapture::fps = $nextArg; + $argUsed[$i+1]++; + $i++; + } + else + error("Error: Missing Command Line argument. Usage: -vidCapFPS "); + + //-------------------- + case "-vidCapEncoder": + $argUsed[$i]++; + if ($hasNextArg) + { + $VideoCapture::encoder = $nextArg; + $argUsed[$i+1]++; + $i++; + } + else + error("Error: Missing Command Line argument. Usage: -vidCapEncoder "); + + //-------------------- + case "-vidCapWidth": + $argUsed[$i]++; + if ($hasNextArg) + { + $videoCapture::width = $nextArg; + $argUsed[$i+1]++; + $i++; + } + else + error("Error: Missing Command Line argument. Usage: -vidCapWidth "); + + //-------------------- + case "-vidCapHeight": + $argUsed[$i]++; + if ($hasNextArg) + { + $videoCapture::height = $nextArg; + $argUsed[$i+1]++; + $i++; + } + else + error("Error: Missing Command Line argument. Usage: -vidCapHeight "); + + //-------------------- + case "-level": + $argUsed[$i]++; + if ($hasNextArg) + { + %hasExt = strpos($nextArg, ".mis"); + if(%hasExt == -1) + { + $levelToLoad = $nextArg @ " "; + + for(%i = $i + 2; %i < $Game::argc; %i++) + { + $arg = $Game::argv[%i]; + %hasExt = strpos($arg, ".mis"); + + if(%hasExt == -1) + { + $levelToLoad = $levelToLoad @ $arg @ " "; + } else + { + $levelToLoad = $levelToLoad @ $arg; + break; + } + } + } + else + { + $levelToLoad = $nextArg; + } + + $argUsed[$i+1]++; + $i++; + } + else + error("Error: Missing Command Line argument. Usage: -level "); + + //------------------- + case "-worldeditor": + $startWorldEditor = true; + $argUsed[$i]++; + + //------------------- + case "-guieditor": + $startGUIEditor = true; + $argUsed[$i]++; + + //------------------- + case "-help": + $displayHelp = true; + $argUsed[$i]++; + + //------------------- + case "-compileAll": + $compileAll = true; + $argUsed[$i]++; + + //------------------- + case "-compileTools": + $compileTools = true; + $argUsed[$i]++; + + //------------------- + case "-genScript": + $genScript = true; + $argUsed[$i]++; + + case "-fullscreen": + $cliFullscreen = true; + $argUsed[%i]++; + + case "-windowed": + $cliFullscreen = false; + $argUsed[%i]++; + + case "-openGL": + $pref::Video::displayDevice = "OpenGL"; + $argUsed[%i]++; + + case "-directX": + $pref::Video::displayDevice = "D3D"; + $argUsed[%i]++; + + case "-autoVideo": + $pref::Video::displayDevice = ""; + $argUsed[%i]++; + + case "-prefs": + $argUsed[%i]++; + if ($hasNextArg) { + exec($nextArg, true, true); + $argUsed[%i+1]++; + %i++; + } + else + error("Error: Missing Command Line argument. Usage: -prefs "); + + + //------------------- + default: + $argUsed[$i]++; + if($userDirs $= "") + $userDirs = $arg; + } + } + + //----------------------------------------------- + // Play journal to video file? + if ($VideoCapture::captureFromJournal && $VideoCapture::journalName !$= "") + { + if ($VideoCapture::fileName $= "") + $VideoCapture::fileName = $VideoCapture::journalName; + + if ($VideoCapture::encoder $= "") + $VideoCapture::encoder = "THEORA"; + + if ($VideoCapture::fps $= "") + $VideoCapture::fps = 30; + + if ($videoCapture::width $= "") + $videoCapture::width = 0; + + if ($videoCapture::height $= "") + $videoCapture::height = 0; + + playJournalToVideo( $VideoCapture::journalName, $VideoCapture::fileName, + $VideoCapture::encoder, $VideoCapture::fps, + $videoCapture::width SPC $videoCapture::height ); + } +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/vr/Core_VR.cs b/Templates/BaseGame/game/core/vr/Core_VR.cs new file mode 100644 index 000000000..42b2df7e0 --- /dev/null +++ b/Templates/BaseGame/game/core/vr/Core_VR.cs @@ -0,0 +1,9 @@ + +function Core_VR::onCreate(%this) +{ + exec("./scripts/oculusVR.cs"); +} + +function Core_VR::onDestroy(%this) +{ +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/vr/Core_VR.module b/Templates/BaseGame/game/core/vr/Core_VR.module new file mode 100644 index 000000000..960a5a85a --- /dev/null +++ b/Templates/BaseGame/game/core/vr/Core_VR.module @@ -0,0 +1,9 @@ + + \ No newline at end of file diff --git a/Templates/BaseGame/game/core/vr/guis/oculusVROverlay.gui b/Templates/BaseGame/game/core/vr/guis/oculusVROverlay.gui new file mode 100644 index 000000000..62a9f719c --- /dev/null +++ b/Templates/BaseGame/game/core/vr/guis/oculusVROverlay.gui @@ -0,0 +1,19 @@ +//--- OBJECT WRITE BEGIN --- +%guiContent = singleton GuiControl(OculusVROverlay) { + canSaveDynamicFields = "0"; + Enabled = "1"; + isContainer = "1"; + Profile = "GuiContentProfile"; + HorizSizing = "width"; + VertSizing = "height"; + Position = "0 0"; + Extent = "512 512"; + MinExtent = "8 8"; + canSave = "1"; + Visible = "1"; + tooltipprofile = "GuiToolTipProfile"; + hovertime = "1000"; + useVariable = "0"; + tile = "0"; +}; +//--- OBJECT WRITE END --- diff --git a/Templates/BaseGame/game/core/vr/scripts/oculusVR.cs b/Templates/BaseGame/game/core/vr/scripts/oculusVR.cs new file mode 100644 index 000000000..fa9562c18 --- /dev/null +++ b/Templates/BaseGame/game/core/vr/scripts/oculusVR.cs @@ -0,0 +1,248 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +// Only load these functions if an Oculus VR device is present +if(!isFunction(isOculusVRDeviceActive)) + return; + +function setupOculusActionMaps() +{ + if (isObject(OculusWarningMap)) + return; + + new ActionMap(OculusWarningMap); + new ActionMap(OculusCanvasMap); + + OculusWarningMap.bind(keyboard, space, dismissOculusVRWarnings); + + OculusCanvasMap.bind( mouse, xaxis, oculusYaw ); + OculusCanvasMap.bind( mouse, yaxis, oculusPitch ); + OculusCanvasMap.bind( mouse, button0, oculusClick ); +} + +function oculusYaw(%val) +{ + OculusCanvas.cursorNudge(%val * 0.10, 0); +} + +function oculusPitch(%val) +{ + OculusCanvas.cursorNudge(0, %val * 0.10); +} + +function oculusClick(%active) +{ + OculusCanvas.cursorClick(0, %active); +} + +function GuiOffscreenCanvas::checkCursor(%this) +{ + %count = %this.getCount(); + for(%i = 0; %i < %count; %i++) + { + %control = %this.getObject(%i); + if ((%control.noCursor $= "") || !%control.noCursor) + { + %this.cursorOn(); + return true; + } + } + // If we get here, every control requested a hidden cursor, so we oblige. + + %this.cursorOff(); + return false; +} + +function GuiOffscreenCanvas::pushDialog(%this, %ctrl, %layer, %center) +{ + Parent::pushDialog(%this, %ctrl, %layer, %center); + %cursorVisible = %this.checkCursor(); + + if (%cursorVisible) + { + echo("OffscreenCanvas visible"); + OculusCanvasMap.pop(); + OculusCanvasMap.push(); + } + else + { + echo("OffscreenCanvas not visible"); + OculusCanvasMap.pop(); + } +} + +function GuiOffscreenCanvas::popDialog(%this, %ctrl) +{ + Parent::popDialog(%this, %ctrl); + %cursorVisible = %this.checkCursor(); + + if (%cursorVisible) + { + echo("OffscreenCanvas visible"); + OculusCanvasMap.pop(); + OculusCanvasMap.push(); + } + else + { + echo("OffscreenCanvas not visible"); + OculusCanvasMap.pop(); + } +} + + +//----------------------------------------------------------------------------- + +function oculusSensorMetricsCallback() +{ + return ovrDumpMetrics(0); +} + + +//----------------------------------------------------------------------------- +function onOculusStatusUpdate(%status) +{ + $LastOculusTrackingState = %status; +} + +//----------------------------------------------------------------------------- + +// Call this function from createCanvas() to have the Canvas attach itself +// to the Rift's display. The Canvas' window will still open on the primary +// display if that is different from the Rift, but it will move to the Rift +// when it goes full screen. If the Rift is not connected then nothing +// will happen. +function pointCanvasToOculusVRDisplay() +{ + $pref::Video::displayOutputDevice = getOVRHMDDisplayDeviceName(0); +} + +//----------------------------------------------------------------------------- + +// Call this function from GameConnection::initialControlSet() just before +// your "Canvas.setContent(PlayGui);" call, or at any time you wish to switch +// to a side-by-side rendering and the appropriate barrel distortion. This +// will turn on side-by-side rendering and tell the GameConnection to use the +// Rift as its display device. +// Parameters: +// %gameConnection - The client GameConnection instance +// %trueStereoRendering - If true will enable stereo rendering with an eye +// offset for each viewport. This will render each frame twice. If false +// then a pseudo stereo rendering is done with only a single render per frame. +function enableOculusVRDisplay(%gameConnection, %trueStereoRendering) +{ + setOVRHMDAsGameConnectionDisplayDevice(%gameConnection); + PlayGui.renderStyle = "stereo side by side"; + setOptimalOVRCanvasSize(Canvas); + + if (!isObject(OculusCanvas)) + { + new GuiOffscreenCanvas(OculusCanvas) { + targetSize = "512 512"; + targetName = "oculusCanvas"; + dynamicTarget = true; + }; + } + + if (!isObject(OculusVROverlay)) + { + exec("core/vr/guis/oculusVROverlay.gui"); + } + + OculusCanvas.setContent(OculusVROverlay); + OculusCanvas.setCursor(DefaultCursor); + PlayGui.setStereoGui(OculusCanvas); + OculusCanvas.setCursorPos("128 128"); + OculusCanvas.cursorOff(); + $GameCanvas = OculusCanvas; + + %ext = Canvas.getExtent(); + $OculusMouseScaleX = 512.0 / 1920.0; + $OculusMouseScaleY = 512.0 / 1060.0; + + //$gfx::wireframe = true; + // Reset all sensors + ovrResetAllSensors(); +} + +// Call this function when ever you wish to turn off the stereo rendering +// and barrel distortion for the Rift. +function disableOculusVRDisplay(%gameConnection) +{ + OculusCanvas.popDialog(); + OculusWarningMap.pop(); + $GameCanvas = Canvas; + + if (isObject(gameConnection)) + { + %gameConnection.clearDisplayDevice(); + } + PlayGui.renderStyle = "standard"; +} + +// Helper function to set the standard Rift control scheme. You could place +// this function in GameConnection::initialControlSet() at the same time +// you call enableOculusVRDisplay(). +function setStandardOculusVRControlScheme(%gameConnection) +{ + if($OculusVR::SimulateInput) + { + // We are simulating a HMD so allow the mouse and gamepad to control + // both yaw and pitch. + %gameConnection.setControlSchemeParameters(true, true, true); + } + else + { + // A HMD is connected so have the mouse and gamepad only add to yaw + %gameConnection.setControlSchemeParameters(true, true, false); + } +} + +//----------------------------------------------------------------------------- + +// Helper function to set the resolution for the Rift. +// Parameters: +// %fullscreen - If true then the display will be forced to full screen. If +// pointCanvasToOculusVRDisplay() was called before the Canvas was created, then +// the full screen display will appear on the Rift. +function setVideoModeForOculusVRDisplay(%fullscreen) +{ + %res = getOVRHMDResolution(0); + Canvas.setVideoMode(%res.x, %res.y, %fullscreen, 32, 4); +} + +//----------------------------------------------------------------------------- + +// Reset all Oculus Rift sensors. This will make the Rift's current heading +// be considered the origin. +function resetOculusVRSensors() +{ + ovrResetAllSensors(); +} + +function dismissOculusVRWarnings(%value) +{ + //if (%value) + //{ + ovrDismissWarnings(); + OculusWarningMap.pop(); + //} +} \ No newline at end of file diff --git a/Templates/BaseGame/game/tools/levels/BlankRoom.postfxpreset.cs b/Templates/BaseGame/game/tools/levels/BlankRoom.postfxpreset.cs index 8b616a84a..23a6c3ced 100644 --- a/Templates/BaseGame/game/tools/levels/BlankRoom.postfxpreset.cs +++ b/Templates/BaseGame/game/tools/levels/BlankRoom.postfxpreset.cs @@ -1,4 +1,4 @@ -$PostFXManager::Settings::ColorCorrectionRamp = "core/images/null_color_ramp.png"; +$PostFXManager::Settings::ColorCorrectionRamp = "core/postFX/images/null_color_ramp.png"; $PostFXManager::Settings::DOF::BlurCurveFar = ""; $PostFXManager::Settings::DOF::BlurCurveNear = ""; $PostFXManager::Settings::DOF::BlurMax = ""; From 5037d7e046a9dba9bcafe4f8e33eb809453d8fc4 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sun, 2 Sep 2018 04:49:58 -0500 Subject: [PATCH 3/4] Updated the main.cs.in file to account for core module-ification. --- Templates/BaseGame/game/main.cs.in | 47 ++++-------------------------- 1 file changed, 5 insertions(+), 42 deletions(-) diff --git a/Templates/BaseGame/game/main.cs.in b/Templates/BaseGame/game/main.cs.in index 3eed267df..1e3e37c44 100644 --- a/Templates/BaseGame/game/main.cs.in +++ b/Templates/BaseGame/game/main.cs.in @@ -16,39 +16,12 @@ $appName = "@TORQUE_APP_NAME@"; //----------------------------------------------------------------------------- // Load up scripts to initialise subsystems. -exec("core/main.cs"); - -// Parse the command line arguments -echo("\n--------- Parsing Arguments ---------"); -parseArgs(); - -// The canvas needs to be initialized before any gui scripts are run since -// some of the controls assume that the canvas exists at load time. -createCanvas($appName); +ModuleDatabase.setModuleExtension("module"); +ModuleDatabase.scanModules( "core", false ); +ModuleDatabase.LoadExplicit( "CoreModule" ); //----------------------------------------------------------------------------- -// Load console. -exec("core/console/main.cs"); - -// Init the physics plugin. -physicsInit(); - -sfxStartup(); - -// Set up networking. -setNetPort(0); - -// Start processing file change events. -startFileChangeNotifications(); - -// If we have editors, initialize them here as well -if (isToolBuild()) -{ - if(isFile("tools/main.cs") && !$isDedicated) - exec("tools/main.cs"); -} - -ModuleDatabase.setModuleExtension("module"); +// Load any gameplay modules ModuleDatabase.scanModules( "data", false ); ModuleDatabase.LoadGroup( "Game" ); @@ -85,14 +58,4 @@ else closeSplashWindow(); } -echo("Engine initialized..."); - -//----------------------------------------------------------------------------- -// Called when the engine is shutting down. -function onExit() -{ - // Stop file change events. - stopFileChangeNotifications(); - - ModuleDatabase.UnloadExplicit( "Game" ); -} \ No newline at end of file +echo("Engine initialized..."); \ No newline at end of file From c17ae947456ecd0b6172ad56dbb3cafa5b6650ce Mon Sep 17 00:00:00 2001 From: Areloch Date: Wed, 19 Sep 2018 16:03:58 -0500 Subject: [PATCH 4/4] Moved VR module from core to a regular module, as not all games are necessarily going to use VR. Also corrected some of the default posteffect settings for the levels. --- Templates/BaseGame/game/core/Core.cs | 2 -- Templates/BaseGame/game/core/vr/Core_VR.cs | 9 --------- Templates/Modules/vr/VR.cs | 9 +++++++++ .../game/core/vr/Core_VR.module => Modules/vr/VR.module} | 6 +++--- .../game/core => Modules}/vr/guis/oculusVROverlay.gui | 0 .../game/core => Modules}/vr/scripts/oculusVR.cs | 0 6 files changed, 12 insertions(+), 14 deletions(-) delete mode 100644 Templates/BaseGame/game/core/vr/Core_VR.cs create mode 100644 Templates/Modules/vr/VR.cs rename Templates/{BaseGame/game/core/vr/Core_VR.module => Modules/vr/VR.module} (75%) rename Templates/{BaseGame/game/core => Modules}/vr/guis/oculusVROverlay.gui (100%) rename Templates/{BaseGame/game/core => Modules}/vr/scripts/oculusVR.cs (100%) diff --git a/Templates/BaseGame/game/core/Core.cs b/Templates/BaseGame/game/core/Core.cs index 480c0331c..5559760ae 100644 --- a/Templates/BaseGame/game/core/Core.cs +++ b/Templates/BaseGame/game/core/Core.cs @@ -24,8 +24,6 @@ function CoreModule::onCreate(%this) ModuleDatabase.LoadExplicit( "Core_Lighting" ); ModuleDatabase.LoadExplicit( "Core_SFX" ); ModuleDatabase.LoadExplicit( "Core_PostFX" ); - ModuleDatabase.LoadExplicit( "Core_VR" ); - ModuleDatabase.LoadExplicit( "Core_VR" ); ModuleDatabase.LoadExplicit( "Core_ClientServer" ); %prefPath = getPrefpath(); diff --git a/Templates/BaseGame/game/core/vr/Core_VR.cs b/Templates/BaseGame/game/core/vr/Core_VR.cs deleted file mode 100644 index 42b2df7e0..000000000 --- a/Templates/BaseGame/game/core/vr/Core_VR.cs +++ /dev/null @@ -1,9 +0,0 @@ - -function Core_VR::onCreate(%this) -{ - exec("./scripts/oculusVR.cs"); -} - -function Core_VR::onDestroy(%this) -{ -} \ No newline at end of file diff --git a/Templates/Modules/vr/VR.cs b/Templates/Modules/vr/VR.cs new file mode 100644 index 000000000..ea0ffd7a5 --- /dev/null +++ b/Templates/Modules/vr/VR.cs @@ -0,0 +1,9 @@ + +function VR::onCreate(%this) +{ + exec("./scripts/oculusVR.cs"); +} + +function VR::onDestroy(%this) +{ +} \ No newline at end of file diff --git a/Templates/BaseGame/game/core/vr/Core_VR.module b/Templates/Modules/vr/VR.module similarity index 75% rename from Templates/BaseGame/game/core/vr/Core_VR.module rename to Templates/Modules/vr/VR.module index 960a5a85a..14ccec0e0 100644 --- a/Templates/BaseGame/game/core/vr/Core_VR.module +++ b/Templates/Modules/vr/VR.module @@ -1,9 +1,9 @@ + Group="Game"> \ No newline at end of file diff --git a/Templates/BaseGame/game/core/vr/guis/oculusVROverlay.gui b/Templates/Modules/vr/guis/oculusVROverlay.gui similarity index 100% rename from Templates/BaseGame/game/core/vr/guis/oculusVROverlay.gui rename to Templates/Modules/vr/guis/oculusVROverlay.gui diff --git a/Templates/BaseGame/game/core/vr/scripts/oculusVR.cs b/Templates/Modules/vr/scripts/oculusVR.cs similarity index 100% rename from Templates/BaseGame/game/core/vr/scripts/oculusVR.cs rename to Templates/Modules/vr/scripts/oculusVR.cs