diff --git a/bin/resources/realisticWater/data/waterbump.png b/bin/resources/realisticWater/data/waterbump.png new file mode 100755 index 00000000..b1927139 Binary files /dev/null and b/bin/resources/realisticWater/data/waterbump.png differ diff --git a/bin/resources/realisticWater/shaders/Water_ps.glsl b/bin/resources/realisticWater/shaders/Water_ps.glsl new file mode 100755 index 00000000..2738ad2e --- /dev/null +++ b/bin/resources/realisticWater/shaders/Water_ps.glsl @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2013, elvman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY elvman ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL elvman BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +const float LOG2 = 1.442695; + +uniform vec3 CameraPosition; // Position of main position +uniform float WaveHeight; + +uniform vec4 WaterColor; +uniform float ColorBlendFactor; + +uniform sampler2D WaterBump; //coverage +uniform sampler2D RefractionMap; //coverage +uniform sampler2D ReflectionMap; //coverage + +uniform bool FogEnabled; +uniform int FogMode; + +varying vec2 bumpMapTexCoord; +varying vec3 refractionMapTexCoord; +varying vec3 reflectionMapTexCoord; +varying vec3 position3D; + +void main() +{ + //bump color + vec4 bumpColor = texture2D(WaterBump, bumpMapTexCoord); + vec2 perturbation = WaveHeight * (bumpColor.rg - 0.5); + + //refraction + vec2 ProjectedRefractionTexCoords = clamp(refractionMapTexCoord.xy / refractionMapTexCoord.z + perturbation, 0.0, 1.0); + //calculate final refraction color + vec4 refractiveColor = texture2D(RefractionMap, ProjectedRefractionTexCoords ); + + //reflection + vec2 ProjectedReflectionTexCoords = clamp(reflectionMapTexCoord.xy / reflectionMapTexCoord.z + perturbation, 0.0, 0.1); + //calculate final reflection color + vec4 reflectiveColor = texture2D(ReflectionMap, ProjectedReflectionTexCoords ); + + //fresnel + vec3 eyeVector = normalize(CameraPosition - position3D); + vec3 upVector = vec3(0.0, 1.0, 0.0); + + //fresnel can not be lower than 0 + float fresnelTerm = max( dot(eyeVector, upVector), 0.0 ); + + float fogFactor = 1.0; + + if (FogEnabled) + { + float z = gl_FragCoord.z / gl_FragCoord.w; + + if (FogMode == 1) //exp + { + float fogFactor = exp2(-gl_Fog.density * z * LOG2); + fogFactor = clamp(fogFactor, 0.0, 1.0); + } + else if (FogMode == 0) //linear + { + fogFactor = (gl_Fog.end - z) / (gl_Fog.end - gl_Fog.start); + } + else if (FogMode == 2) //exp2 + { + float fogFactor = exp2(-gl_Fog.density * gl_Fog.density * z * z * LOG2); + fogFactor = clamp(fogFactor, 0.0, 1.0); + } + } + + vec4 combinedColor = refractiveColor * fresnelTerm + reflectiveColor * (1.0 - fresnelTerm); + + vec4 finalColor = ColorBlendFactor * WaterColor + (1.0 - ColorBlendFactor) * combinedColor; + + gl_FragColor = mix(gl_Fog.color, finalColor, fogFactor ); +} + diff --git a/bin/resources/realisticWater/shaders/Water_ps.hlsl b/bin/resources/realisticWater/shaders/Water_ps.hlsl new file mode 100755 index 00000000..72a34491 --- /dev/null +++ b/bin/resources/realisticWater/shaders/Water_ps.hlsl @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2013, elvman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY elvman ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL elvman BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +float3 CameraPosition; // Position of main position +float WaveHeight; + +float4 WaterColor; +float ColorBlendFactor; + +sampler2D WaterBump; //coverage +sampler2D RefractionMap; //coverage +sampler2D ReflectionMap; //coverage + +// Pixel shader output structure +struct PS_OUTPUT +{ + float4 color : COLOR0; // Pixel color +}; + +struct PS_INPUT +{ + float4 position : POSITION; // vertex position + + float2 bumpMapTexCoord : TEXCOORD0; + float3 refractionMapTexCoord : TEXCOORD1; + float3 reflectionMapTexCoord : TEXCOORD2; + + float3 position3D : TEXCOORD3; +}; + +PS_OUTPUT main( PS_INPUT input ) +{ + PS_OUTPUT output; + + //bump color + float4 bumpColor = tex2D(WaterBump, input.bumpMapTexCoord); + float2 perturbation = WaveHeight * (bumpColor.rg - 0.5); + + //refraction + float2 ProjectedRefractionTexCoords = saturate(input.refractionMapTexCoord.xy / input.refractionMapTexCoord.z + perturbation); + //calculate final refraction color + float4 refractiveColor = tex2D(RefractionMap, ProjectedRefractionTexCoords ); + + //reflection + float2 ProjectedReflectionTexCoords = saturate(input.reflectionMapTexCoord.xy / input.reflectionMapTexCoord.z + perturbation); + //calculate final reflection color + float4 reflectiveColor = tex2D(ReflectionMap, ProjectedReflectionTexCoords ); + + //fresnel + float3 eyeVector = normalize(CameraPosition - input.position3D); + float3 upVector = float3(0.0, 1.0, 0.0); + + //fresnel can not be lower than 0 + float fresnelTerm = max( dot(eyeVector, upVector), 0.0 ); + + float4 combinedColor = refractiveColor * fresnelTerm + reflectiveColor * (1.0 - fresnelTerm); + + output.color = ColorBlendFactor * WaterColor + (1.0 - ColorBlendFactor) * combinedColor; + + return output; +} + diff --git a/bin/resources/realisticWater/shaders/Water_vs.glsl b/bin/resources/realisticWater/shaders/Water_vs.glsl new file mode 100755 index 00000000..caae7706 --- /dev/null +++ b/bin/resources/realisticWater/shaders/Water_vs.glsl @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2013, elvman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY elvman ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL elvman BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +//uniform mat4 View; +uniform mat4 WorldViewProj; // World * View * Projection transformation +uniform mat4 WorldReflectionViewProj; // World * Reflection View * Projection transformation + +uniform float WaveLength; + +uniform float Time; +uniform float WindForce; +uniform vec2 WindDirection; + +// Vertex shader output structure +varying vec2 bumpMapTexCoord; +varying vec3 refractionMapTexCoord; +varying vec3 reflectionMapTexCoord; +varying vec3 position3D; + +void main() +{ + //color = gl_Color; + + // transform position to clip space + vec4 pos = WorldViewProj * gl_Vertex; + gl_Position = pos; + + // calculate vawe coords + bumpMapTexCoord = gl_MultiTexCoord0.xy / WaveLength + Time * WindForce * WindDirection; + + // refraction texcoords + refractionMapTexCoord.x = 0.5 * (pos.w + pos.x); + refractionMapTexCoord.y = 0.5 * (pos.w + pos.y); + refractionMapTexCoord.z = pos.w; + + // reflection texcoords + pos = WorldReflectionViewProj * gl_Vertex; + reflectionMapTexCoord.x = 0.5 * (pos.w + pos.x); + reflectionMapTexCoord.y = 0.5 * (pos.w + pos.y); + reflectionMapTexCoord.z = pos.w; + + // position of the vertex + position3D = gl_Vertex.xyz; +} \ No newline at end of file diff --git a/bin/resources/realisticWater/shaders/Water_vs.hlsl b/bin/resources/realisticWater/shaders/Water_vs.hlsl new file mode 100755 index 00000000..22b5e1fb --- /dev/null +++ b/bin/resources/realisticWater/shaders/Water_vs.hlsl @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2013, elvman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY elvman ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL elvman BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +//float4x4 View; +float4x4 WorldViewProj; // World * View * Projection transformation +float4x4 WorldReflectionViewProj; // World * Reflection View * Projection transformation + +float WaveLength; + +float Time; +float WindForce; +float2 WindDirection; + +// Vertex shader output structure +struct VS_OUTPUT +{ + float4 position : POSITION; // vertex position + + float2 bumpMapTexCoord : TEXCOORD0; + float3 refractionMapTexCoord : TEXCOORD1; + float3 reflectionMapTexCoord : TEXCOORD2; + + float3 position3D : TEXCOORD3; +}; + +struct VS_INPUT +{ + float4 position : POSITION; + float4 color : COLOR0; + float2 texCoord0 : TEXCOORD0; +}; + +VS_OUTPUT main(VS_INPUT input) +{ + VS_OUTPUT output; + + // transform position to clip space + float4 pos = mul(input.position, WorldViewProj); + output.position = pos; + + // calculate vawe coords + output.bumpMapTexCoord = input.texCoord0 / WaveLength + Time * WindForce * WindDirection; + + // refraction texcoords + output.refractionMapTexCoord.x = 0.5 * (pos.w + pos.x); + output.refractionMapTexCoord.y = 0.5 * (pos.w - pos.y); + output.refractionMapTexCoord.z = pos.w; + + // reflection texcoords + pos = mul(input.position, WorldReflectionViewProj); + output.reflectionMapTexCoord.x = 0.5 * (pos.w + pos.x); + output.reflectionMapTexCoord.y = 0.5 * (pos.w - pos.y); + output.reflectionMapTexCoord.z = pos.w; + + // position of the vertex + output.position3D = input.position; + + return output; +} \ No newline at end of file diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index f134cbf1..2d6ef885 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -40,9 +40,11 @@ add_executable(client ${CMAKE_CURRENT_LIST_DIR}/src/system/SystemUpdateKeyInput.cpp ${CMAKE_CURRENT_LIST_DIR}/include/client/misc/CBatchingMesh.hpp + ${CMAKE_CURRENT_LIST_DIR}/include/client/misc/RealisticWater.hpp ${CMAKE_CURRENT_LIST_DIR}/include/client/misc/RGBtoHSV.hpp ${CMAKE_CURRENT_LIST_DIR}/include/client/misc/YAlignedBillboardSceneNode.hpp ${CMAKE_CURRENT_LIST_DIR}/src/misc/CBatchingMesh.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/misc/RealisticWater.cpp ${CMAKE_CURRENT_LIST_DIR}/src/misc/RGBtoHSV.cpp ${CMAKE_CURRENT_LIST_DIR}/src/misc/YAlignedBillboardSceneNode.cpp diff --git a/src/client/include/client/misc/RealisticWater.hpp b/src/client/include/client/misc/RealisticWater.hpp new file mode 100644 index 00000000..70dc0bcf --- /dev/null +++ b/src/client/include/client/misc/RealisticWater.hpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2013, elvman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY elvman ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _REALISTIC_WATER_SCENE_NODE_H +#define _REALISTIC_WATER_SCENE_NODE_H + +#include + +using namespace irr; + +class RealisticWaterSceneNode: public scene::ISceneNode, video::IShaderConstantSetCallBack +{ +public: + RealisticWaterSceneNode(scene::ISceneManager* sceneManager, f32 width, f32 height, + const irr::core::stringc& resourcePath = irr::core::stringc(), + core::dimension2du renderTargetSize=core::dimension2du(512,512),scene::ISceneNode* parent = NULL, s32 id = -1); + virtual ~RealisticWaterSceneNode(); + + // frame + virtual void OnRegisterSceneNode(); + + virtual void OnAnimate(u32 timeMs); + + // renders terrain + virtual void render(); + + // returns the axis aligned bounding box of terrain + virtual const core::aabbox3d& getBoundingBox() const; + + virtual void OnSetConstants(video::IMaterialRendererServices* services, s32 userData); + + void setWindForce(f32 windForce); + void setWindDirection(const core::vector2df& windDirection); + void setWaveHeight(f32 waveHeight); + + void setWaterColor(const video::SColorf& waterColor); + void setColorBlendFactor(f32 colorBlendFactor); + +private: + + scene::ICameraSceneNode* _camera; + scene::ISceneNode* _waterSceneNode; + + video::IVideoDriver* _videoDriver; + scene::ISceneManager* _sceneManager; + + core::dimension2d _size; + + s32 _shaderMaterial; + + scene::IAnimatedMesh* _waterMesh; + + video::ITexture* _refractionMap; + video::ITexture* _reflectionMap; + + f32 _windForce; + core::vector2df _windDirection; + f32 _waveHeight; + + video::SColorf _waterColor; + f32 _colorBlendFactor; + + u32 _time; +}; + +#endif diff --git a/src/client/main.cpp b/src/client/main.cpp index a35d778c..5ff86268 100644 --- a/src/client/main.cpp +++ b/src/client/main.cpp @@ -16,6 +16,8 @@ #include #include +#include + #include #include #include @@ -243,6 +245,14 @@ int main(int argc, const char **argv) system_render_health_bars.setup(smgr); system_button_renderer.setup(smgr, driver); + + const f32 width = 512.0f; + const f32 height = 512.0f; + //std::string resourcePath = "resources"; + irr::core::stringc resourcePath("resources/realisticWater"); + RealisticWaterSceneNode* water = new RealisticWaterSceneNode(smgr, width, height, resourcePath); + smgr->getRootSceneNode()->addChild(water); + // Start and Sync Song sync_time(clock); // long offset = 0; @@ -284,15 +294,15 @@ int main(int argc, const char **argv) device->getCursorControl()->setVisible(true); } - // irr::scene::ISceneNode* camera_light; - // camera_light = smgr->addLightSceneNode(camera_node, - // irr::core::vector3df(0.0f, 0.0f, 0.0f), - // irr::video::SColorf(0.8f, 0.8f, 0.8f), - // 10.0f); + irr::scene::ISceneNode* camera_light; + camera_light = smgr->addLightSceneNode(camera_node, + irr::core::vector3df(0.0f, 4.0f, 0.0f), + irr::video::SColorf(0.8f, 0.8f, 0.8f), + 3.0f); // debug static light - irr::scene::ILightSceneNode *light_node; - light_node = smgr->addLightSceneNode(0, irr::core::vector3df(10.0f, 10.0f, 10.0f), - irr::video::SColorf(0.8f, 0.8f, 0.8f), 5.0f); + // irr::scene::ILightSceneNode *light_node; + // light_node = smgr->addLightSceneNode(0, irr::core::vector3df(10.0f, 10.0f, 10.0f), + // irr::video::SColorf(0.8f, 0.8f, 0.8f), 5.0f); // irr::video::SLight& light_data = light_node->getLightData(); ///////////////////////////////////////////////// diff --git a/src/client/src/misc/RealisticWater.cpp b/src/client/src/misc/RealisticWater.cpp new file mode 100644 index 00000000..91d33758 --- /dev/null +++ b/src/client/src/misc/RealisticWater.cpp @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2013, elvman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY elvman ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "client/misc/RealisticWater.hpp" + +RealisticWaterSceneNode::RealisticWaterSceneNode(scene::ISceneManager* sceneManager, f32 width, f32 height, + const irr::core::stringc& resourcePath, core::dimension2du renderTargetSize, + scene::ISceneNode* parent, s32 id): + scene::ISceneNode(parent, sceneManager, id), _time(0), + _size(width, height), _sceneManager(sceneManager), _refractionMap(NULL), _reflectionMap(NULL), + _windForce(0.2f),_windDirection(0, 1),_waveHeight(0.5f), _waterColor(0.1f, 0.05f, 0.1f, 1.0f), _colorBlendFactor(0.2f), _camera(NULL) +{ + _videoDriver = sceneManager->getVideoDriver(); + + //create new camera + _camera = sceneManager->addCameraSceneNode(0, core::vector3df(0, 0, 0), core::vector3df(0, 0, 0), -1, false); + + _waterMesh = sceneManager->addHillPlaneMesh("RealisticWater", _size, core::dimension2d(1, 1)); + + _waterSceneNode = sceneManager->addMeshSceneNode(_waterMesh->getMesh(0), this, -1, core::vector3df(0, -1.f, 0)); + + video::IGPUProgrammingServices* GPUProgrammingServices = _videoDriver->getGPUProgrammingServices(); + + core::stringc waterPixelShader; + core::stringc waterVertexShader; + + if (_videoDriver->getDriverType() == video::EDT_DIRECT3D9) + { + waterPixelShader = resourcePath + "/shaders/Water_ps.hlsl"; + waterVertexShader = resourcePath + "/shaders/Water_vs.hlsl"; + } + else if (_videoDriver->getDriverType() == video::EDT_OPENGL) + { + waterPixelShader = resourcePath + "/shaders/Water_ps.glsl"; + waterVertexShader = resourcePath + "/shaders/Water_vs.glsl"; + } + + _shaderMaterial = GPUProgrammingServices->addHighLevelShaderMaterialFromFiles( + waterVertexShader.c_str(), "main", video::EVST_VS_1_1, + waterPixelShader.c_str(), "main", video::EPST_PS_1_1, + this); + + _waterSceneNode->setMaterialType((video::E_MATERIAL_TYPE)_shaderMaterial); + + irr::video::ITexture* bumpTexture = _videoDriver->getTexture(resourcePath + "/data/waterbump.png"); + _waterSceneNode->setMaterialTexture(0, bumpTexture); + + _refractionMap = _videoDriver->addRenderTargetTexture(renderTargetSize); + _reflectionMap = _videoDriver->addRenderTargetTexture(renderTargetSize); + + _waterSceneNode->setMaterialTexture(1, _refractionMap); + _waterSceneNode->setMaterialTexture(2, _reflectionMap); +} + +RealisticWaterSceneNode::~RealisticWaterSceneNode() +{ + if (_camera) + { + _camera->drop(); + _camera = NULL; + } + + if (_refractionMap) + { + _refractionMap->drop(); + _refractionMap = NULL; + } + + if (_reflectionMap) + { + _reflectionMap->drop(); + _reflectionMap = NULL; + } + + if (_waterSceneNode) + { + _waterSceneNode->drop(); + _waterSceneNode = NULL; + } + + if (_waterMesh) + { + _waterMesh->drop(); + _waterMesh = NULL; + } +} + +// frame +void RealisticWaterSceneNode::OnRegisterSceneNode() +{ + ISceneNode::OnRegisterSceneNode(); + + if (IsVisible) + { + _sceneManager->registerNodeForRendering(this); + } +} + +void RealisticWaterSceneNode::OnAnimate(u32 timeMs) +{ + ISceneNode::OnAnimate(timeMs); + + _time = timeMs; + + //fixes glitches with incomplete refraction + const f32 CLIP_PLANE_OFFSET_Y = 5.0f; + + if (IsVisible) + { + setVisible(false); //hide the water + + //refraction + _videoDriver->setRenderTarget(_refractionMap, true, true); //render to refraction + + //refraction clipping plane + core::plane3d refractionClipPlane(0, RelativeTranslation.Y + CLIP_PLANE_OFFSET_Y, 0, 0, -1, 0); //refraction clip plane + _videoDriver->setClipPlane(0, refractionClipPlane, true); + + _sceneManager->drawAll(); //draw the scene + + //reflection + _videoDriver->setRenderTarget(_reflectionMap, true, true); //render to reflection + + //get current camera + scene::ICameraSceneNode* currentCamera = _sceneManager->getActiveCamera(); + + //set FOV anf far value from current camera + _camera->setFarValue(currentCamera->getFarValue()); + _camera->setFOV(currentCamera->getFOV()); + + core::vector3df position = currentCamera->getAbsolutePosition(); + position.Y = -position.Y + 2 * RelativeTranslation.Y; //position of the water + _camera->setPosition(position); + + core::vector3df target = currentCamera->getTarget(); + + //invert Y position of current camera + target.Y = -target.Y + 2 * RelativeTranslation.Y; + _camera->setTarget(target); + + //set the reflection camera + _sceneManager->setActiveCamera(_camera); + + //reflection clipping plane + core::plane3d reflectionClipPlane(0, RelativeTranslation.Y - CLIP_PLANE_OFFSET_Y, 0, 0, 1, 0); + _videoDriver->setClipPlane(0, reflectionClipPlane, true); + + _sceneManager->drawAll(); //draw the scene + + //disable clip plane + _videoDriver->enableClipPlane(0, false); + + //set back old render target + _videoDriver->setRenderTarget(0); + + //set back the active camera + _sceneManager->setActiveCamera(currentCamera); + + setVisible(true); //show it again + } +} + +void RealisticWaterSceneNode::render() +{ + /*core::array renderTargets; + //renderTargets.push_back(); + renderTargets.push_back(_refractionMap); + _videoDriver->setRenderTarget(renderTargets, true, true);*/ + //_videoDriver->draw2DImage(_reflectionMap,core::position2d(0,0)); +} + +// returns the axis aligned bounding box of terrain +const core::aabbox3d& RealisticWaterSceneNode::getBoundingBox() const +{ + return _waterSceneNode->getBoundingBox(); +} + +void RealisticWaterSceneNode::OnSetConstants(video::IMaterialRendererServices* services, s32 userData) +{ + video::IVideoDriver* driver = services->getVideoDriver(); + + core::matrix4 projection = driver->getTransform(video::ETS_PROJECTION); + core::matrix4 view = driver->getTransform(video::ETS_VIEW); + core::matrix4 world = driver->getTransform(video::ETS_WORLD); + + core::matrix4 cameraView = _camera->getViewMatrix(); + + //vertex shader constants + //services->setVertexShaderConstant("View", view.pointer(), 16); + + core::matrix4 worldViewProj = projection; + worldViewProj *= view; + worldViewProj *= world; + + core::matrix4 worldReflectionViewProj = projection; + worldReflectionViewProj *= cameraView; + worldReflectionViewProj *= world; + + f32 waveLength = 0.07f; + f32 time = _time / 100000.0f; + core::vector3df cameraPosition = _sceneManager->getActiveCamera()->getPosition(); + + bool fogEnabled = getMaterial(0).getFlag(video::EMF_FOG_ENABLE); + irr::video::SColor color; + irr::video::E_FOG_TYPE fogType; + f32 start; + f32 end; + f32 density; + bool pixelFog; + bool rangeFog; + driver->getFog(color, fogType, start, end, density, pixelFog, rangeFog); + +#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR == 9) + services->setVertexShaderConstant(services->getVertexShaderConstantID("WorldViewProj"), worldViewProj.pointer(), 16); + services->setVertexShaderConstant(services->getVertexShaderConstantID("WorldReflectionViewProj"), worldReflectionViewProj.pointer(), 16); + services->setVertexShaderConstant(services->getVertexShaderConstantID("WaveLength"), &waveLength, 1); + services->setVertexShaderConstant(services->getVertexShaderConstantID("Time"), &time, 1); + services->setVertexShaderConstant(services->getVertexShaderConstantID("WindForce"), &_windForce, 1); + services->setVertexShaderConstant(services->getVertexShaderConstantID("WindDirection"), &_windDirection.X, 2); + services->setPixelShaderConstant(services->getVertexShaderConstantID("CameraPosition"), &cameraPosition.X, 3); + services->setPixelShaderConstant(services->getVertexShaderConstantID("WaveHeight"), &_waveHeight, 1); + services->setPixelShaderConstant(services->getVertexShaderConstantID("WaterColor"), &_waterColor.r, 4); + services->setPixelShaderConstant(services->getVertexShaderConstantID("ColorBlendFactor"), &_colorBlendFactor, 1); +#else + services->setVertexShaderConstant("WorldViewProj", worldViewProj.pointer(), 16); + services->setVertexShaderConstant("WorldReflectionViewProj", worldReflectionViewProj.pointer(), 16); + services->setVertexShaderConstant("WaveLength", &waveLength, 1); + services->setVertexShaderConstant("Time", &time, 1); + services->setVertexShaderConstant("WindForce", &_windForce, 1); + services->setVertexShaderConstant("WindDirection", &_windDirection.X, 2); + services->setPixelShaderConstant("CameraPosition", &cameraPosition.X, 3); + services->setPixelShaderConstant("WaveHeight", &_waveHeight, 1); + services->setPixelShaderConstant("WaterColor", &_waterColor.r, 4); + services->setPixelShaderConstant("ColorBlendFactor", &_colorBlendFactor, 1); +#endif + + //texture constants for GLSL + if (driver->getDriverType() == video::EDT_OPENGL) + { + int var0 = 0; + int var1 = 1; + int var2 = 2; + +#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR == 9) + services->setPixelShaderConstant(services->getVertexShaderConstantID("WaterBump"), &var0, 1); + services->setPixelShaderConstant(services->getVertexShaderConstantID("RefractionMap"), &var1, 1); + services->setPixelShaderConstant(services->getVertexShaderConstantID("ReflectionMap"), &var2, 1); + + services->setPixelShaderConstant(services->getVertexShaderConstantID("FogEnabled"), (int*)&fogEnabled, 1); + services->setPixelShaderConstant(services->getVertexShaderConstantID("FogMode"), (int*)&fogType, 1); +#else + services->setPixelShaderConstant("WaterBump", &var0, 1); + services->setPixelShaderConstant("RefractionMap", &var1, 1); + services->setPixelShaderConstant("ReflectionMap", &var2, 1); + + services->setPixelShaderConstant("FogEnabled", (int*)&fogEnabled, 1); + services->setPixelShaderConstant("FogMode", (int*)&fogType, 1); +#endif + } +} + +void RealisticWaterSceneNode::setWindForce(const f32 windForce) +{ + _windForce = windForce; +} + +void RealisticWaterSceneNode::setWindDirection(const core::vector2df& windDirection) +{ + _windDirection = windDirection; + _windDirection.normalize(); +} + +void RealisticWaterSceneNode::setWaveHeight(const f32 waveHeight) +{ + _waveHeight = waveHeight; +} + +void RealisticWaterSceneNode::setWaterColor(const video::SColorf& waterColor) +{ + _waterColor = waterColor; +} + +void RealisticWaterSceneNode::setColorBlendFactor(const f32 colorBlendFactor) +{ + _colorBlendFactor = colorBlendFactor; +}