├── stdafx.h ├── stdafx.cpp ├── media ├── packs │ ├── Sinbad.zip │ ├── OgreCore.zip │ └── cubemapsJS.zip ├── LightSwirlMarble.jpg ├── Ground.material ├── normals.cg ├── normals.material ├── SphereDepth.cg ├── Smoothing.material ├── BilateralGaussianBlur.cg ├── PointToQuadGS.cg ├── ScreenSpaceParticleFluid.compositor ├── SpherePointSprites.cg ├── FluidSurfaceShading.cg └── ParticleSplatting.material ├── ParticleFluidRendererPortable ├── ParticleFluidRenderer.bat └── ParticleFluidRenderer-Debug.bat ├── particlefluids.qrc ├── .hgignore ├── bin ├── debug │ ├── resources.cfg │ └── Plugins.cfg └── release │ ├── resources.cfg │ └── Plugins.cfg ├── main.cpp ├── README.md ├── particlefluids.h ├── OgreWidget_blog.h ├── ParticleFluids.vcxproj.user ├── ParticleFluids.sln ├── particlefluids.ui ├── qdebugstream.h ├── OgreWidget.h ├── OgreWidget_blog.cpp ├── ParticleFluids.vcxproj.filters ├── ResourceGroupHelper.h ├── particlefluids.cpp ├── ResourceGroupHelper.cpp ├── ParticleFluids.vcproj ├── ParticleFluids.vcxproj └── OgreWidget.cpp /stdafx.h: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /stdafx.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | -------------------------------------------------------------------------------- /media/packs/Sinbad.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwasty/particle-fluids/HEAD/media/packs/Sinbad.zip -------------------------------------------------------------------------------- /ParticleFluidRendererPortable/ParticleFluidRenderer.bat: -------------------------------------------------------------------------------- 1 | cd ParticleFluids\bin\release 2 | ParticleFluids.exe -------------------------------------------------------------------------------- /media/packs/OgreCore.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwasty/particle-fluids/HEAD/media/packs/OgreCore.zip -------------------------------------------------------------------------------- /particlefluids.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /ParticleFluidRendererPortable/ParticleFluidRenderer-Debug.bat: -------------------------------------------------------------------------------- 1 | cd ParticleFluids\bin\debug 2 | ParticleFluids.exe -------------------------------------------------------------------------------- /media/LightSwirlMarble.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwasty/particle-fluids/HEAD/media/LightSwirlMarble.jpg -------------------------------------------------------------------------------- /media/packs/cubemapsJS.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bwasty/particle-fluids/HEAD/media/packs/cubemapsJS.zip -------------------------------------------------------------------------------- /.hgignore: -------------------------------------------------------------------------------- 1 | glob:*.suo 2 | glob:*.ncb 3 | glob:ParticleFluids.vcproj.corei7.BennyWasty.user 4 | glob:Dependencies/ 5 | glob:GeneratedFiles/ 6 | glob:bin/ 7 | glob:obj/ 8 | syntax: glob 9 | *.sdf 10 | *.bak 11 | *.orig 12 | *.old 13 | ParticleFluidRendererPortable/Release/ 14 | -------------------------------------------------------------------------------- /bin/debug/resources.cfg: -------------------------------------------------------------------------------- 1 | # Resource locations to be added to the 'boostrap' path 2 | 3 | [Bootstrap] 4 | Zip=../../media/packs/OgreCore.zip 5 | Zip=../../media/packs/Sinbad.zip 6 | Zip=../../media/packs/cubemapsJS.zip 7 | 8 | # Resource locations to be added to the default path 9 | [General1] 10 | FileSystem=../../media 11 | 12 | -------------------------------------------------------------------------------- /bin/release/resources.cfg: -------------------------------------------------------------------------------- 1 | # Resource locations to be added to the 'boostrap' path 2 | 3 | [Bootstrap] 4 | Zip=../../media/packs/OgreCore.zip 5 | Zip=../../media/packs/Sinbad.zip 6 | Zip=../../media/packs/cubemapsJS.zip 7 | 8 | # Resource locations to be added to the default path 9 | [General1] 10 | FileSystem=../../media 11 | 12 | -------------------------------------------------------------------------------- /media/Ground.material: -------------------------------------------------------------------------------- 1 | material Ground 2 | { 3 | technique 4 | { 5 | pass 6 | { 7 | ambient 0.200000 0.200000 0.200000 1.0 8 | diffuse 0.200000 0.200000 0.200000 1.0 9 | specular 0.5 0.5 0.5 80.0 10 | } 11 | } 12 | } 13 | 14 | material marbleTexture { 15 | technique { 16 | pass { 17 | 18 | texture_unit { 19 | texture LightSwirlMarble.jpg 20 | tex_address_mode wrap 21 | } 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "particlefluids.h" 3 | #include 4 | 5 | //#include 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | //try { 10 | 11 | QApplication a(argc, argv); 12 | ParticleFluids w; 13 | w.show(); 14 | return a.exec(); 15 | 16 | //} 17 | //catch (Ogre::InvalidStateException e) { 18 | // std::cout << e.getDescription(); 19 | //} 20 | } 21 | -------------------------------------------------------------------------------- /bin/release/Plugins.cfg: -------------------------------------------------------------------------------- 1 | # Defines plugins to load 2 | 3 | # Define plugin folder 4 | PluginFolder=. 5 | 6 | # Define plugins 7 | Plugin=RenderSystem_GL 8 | #Plugin=RenderSystem_Direct3D9 9 | #Plugin=RenderSystem_Direct3D10 10 | Plugin=Plugin_OctreeSceneManager 11 | Plugin=Plugin_CgProgramManager 12 | 13 | #Plugin=Plugin_ParticleFX 14 | #Plugin=Plugin_BSPSceneManager 15 | #Plugin=Plugin_PCZSceneManager.dll 16 | #Plugin=Plugin_OctreeZone.dll 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /bin/debug/Plugins.cfg: -------------------------------------------------------------------------------- 1 | # Defines plugins to load 2 | 3 | # Define plugin folder 4 | PluginFolder=. 5 | 6 | # Define plugins 7 | Plugin=RenderSystem_GL_d 8 | #Plugin=RenderSystem_Direct3D9_d 9 | #Plugin=RenderSystem_Direct3D10_d 10 | 11 | Plugin=Plugin_OctreeSceneManager_d 12 | Plugin=Plugin_CgProgramManager_d 13 | 14 | #Plugin=Plugin_ParticleFX_d 15 | #Plugin=Plugin_BSPSceneManager_d 16 | 17 | #Plugin=Plugin_PCZSceneManager_d.dll 18 | #Plugin=Plugin_OctreeZone_d.dll 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /media/normals.cg: -------------------------------------------------------------------------------- 1 | struct VSOut { 2 | float4 pos : POSITION; 3 | float3 normal : TEXCOORD0; 4 | float depth : TEXCOORD1; 5 | }; 6 | 7 | void normalsPassthrough(in float4 pos : POSITION, 8 | in float3 n : NORMAL, 9 | out VSOut o, 10 | uniform float4x4 worldViewProj) { 11 | o.pos = mul(worldViewProj, pos); 12 | o.normal = n; 13 | o.depth = o.pos.z / o.pos.w; 14 | } 15 | 16 | void shade(in VSOut i, out float4 fragColor : COLOR) { 17 | //fragColor = float4(i.normal, 1.0); 18 | fragColor = float4(i.depth, i.depth, i.depth, 1.0); 19 | //fragColor = (1,0,0,1); 20 | } -------------------------------------------------------------------------------- /media/normals.material: -------------------------------------------------------------------------------- 1 | vertex_program normals_VS cg { 2 | source normals.cg 3 | entry_point normalsPassthrough 4 | profiles gp4vp glslv arbvp1 vp20 vp30 5 | 6 | default_params { 7 | param_named_auto worldViewProj worldviewproj_matrix 8 | //param_indexed_auto 0 worldviewproj_matrix 9 | } 10 | } 11 | 12 | 13 | fragment_program normals_PS cg { 14 | source normals.cg 15 | entry_point shade 16 | profiles gp4fp glslf arbfp1 fp20 fp30 17 | } 18 | 19 | 20 | material normals 21 | { 22 | technique 23 | { 24 | pass 25 | { 26 | vertex_program_ref normals_VS 27 | { 28 | } 29 | 30 | fragment_program_ref normals_PS 31 | { 32 | } 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # particle-fluids 2 | Partial implementation of 3 | 4 | > van der Laan, Wladimir J., Simon Green, and Miguel Sainz. "Screen space fluid rendering with curvature flow." Proceedings of the 2009 symposium on Interactive 3D graphics and games. ACM, 2009. 5 | ([Google Scholar](https://scholar.google.de/scholar?hl=de&q=Screen+Space+Fluid+Rendering+with+Curvature+Flow)) 6 | 7 | Good overview: [Screen Space Fluid 8 | Rendering for Games (GDC 2010)](http://developer.download.nvidia.com/presentations/2010/gdc/Direct3D_Effects.pdf) 9 | 10 | ### Video 11 | 13 | -------------------------------------------------------------------------------- /media/SphereDepth.cg: -------------------------------------------------------------------------------- 1 | float2 computeSphereDepth( 2 | float2 texCoord, 3 | float3 eyeSpacePosParticle, 4 | float sphereRadius, 5 | float4x4 projectionMatrix, 6 | out float3 N, // TODO: N really needed as parameter? 7 | out float4 pixelPos) // for thickness; better name? 8 | { 9 | // TODO!: quad size obviously not matching... 10 | // calculate eye-space sphere normal from texture coordinates 11 | //float3 N; 12 | N.xy = texCoord; 13 | float r2 = dot(N.xy, N.xy); 14 | if (r2 > 1.0) discard; // kill pixels outside circle 15 | N.z = sqrt(1.0 - r2); 16 | 17 | // calculate depth 18 | pixelPos = float4(eyeSpacePosParticle + (N)*sphereRadius, 1.0); 19 | 20 | float4 clipSpacePos = mul(projectionMatrix, pixelPos); 21 | 22 | return float2(clipSpacePos.z, clipSpacePos.z / clipSpacePos.w); 23 | } -------------------------------------------------------------------------------- /particlefluids.h: -------------------------------------------------------------------------------- 1 | #ifndef PARTICLEFLUIDS_H 2 | #define PARTICLEFLUIDS_H 3 | 4 | #include 5 | #include "ui_particlefluids.h" 6 | 7 | class OgreWidget; 8 | 9 | class QtProperty; 10 | class QVariant; 11 | class QDebugStream; 12 | 13 | class ParticleFluids : public QMainWindow 14 | { 15 | Q_OBJECT 16 | 17 | public: 18 | ParticleFluids(QWidget *parent = 0, Qt::WFlags flags = 0); 19 | ~ParticleFluids(); 20 | 21 | void setupPhysXGUI(); 22 | 23 | public slots: 24 | void propertyValueChanged(QtProperty* property, const QVariant & value); 25 | 26 | private: 27 | Ui::ParticleFluidsClass ui; 28 | OgreWidget* mOgreWidget; 29 | QDebugStream* mCout; 30 | QDebugStream* mCerr; 31 | 32 | public: 33 | QLabel* mLabelParticleCount; 34 | QLabel* mLabelCamPos; 35 | }; 36 | 37 | #endif // PARTICLEFLUIDS_H 38 | -------------------------------------------------------------------------------- /media/Smoothing.material: -------------------------------------------------------------------------------- 1 | fragment_program bilateralGaussianSeparated cg { 2 | source BilateralGaussianBlur.cg 3 | entry_point bilateralGaussianSeparated 4 | profiles gp4fp fp40 glslf arbfp1 fp20 fp30 fp40 5 | 6 | default_params { 7 | param_named_auto texelSize inverse_texture_size 0 8 | } 9 | } 10 | 11 | material BilateralGaussianX 12 | { 13 | technique 14 | { 15 | pass 16 | { 17 | fragment_program_ref bilateralGaussianSeparated 18 | { 19 | param_named blurDir float2 1.0 0.0 20 | } 21 | 22 | texture_unit samplerDepth {} 23 | } 24 | } 25 | } 26 | 27 | material BilateralGaussianY : BilateralGaussianX 28 | { 29 | technique 30 | { 31 | pass 32 | { 33 | fragment_program_ref bilateralGaussianSeparated 34 | { 35 | param_named blurDir float2 0.0 1.0 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /OgreWidget_blog.h: -------------------------------------------------------------------------------- 1 | // from http://projectify.blogspot.com/2009/06/qt-ogre-vs2008-express.html 2 | #ifndef QTOGRE_OGREWIDGET_H_ 3 | #define QTOGRE_OGREWIDGET_H_ 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | namespace QtOgre 13 | { 14 | class InputEventHandler; 15 | 16 | class OgreWidget : public QWidget 17 | { 18 | Q_OBJECT 19 | 20 | public: 21 | OgreWidget(QWidget* pParentWidget=0, Qt::WindowFlags f=0); 22 | ~OgreWidget(); 23 | 24 | Ogre::RenderWindow* getOgreRenderWindow() const; 25 | 26 | //QPaintEngine* paintEngine() const; 27 | 28 | 29 | 30 | public: 31 | Ogre::RenderWindow* renderWindow() 32 | { 33 | return m_pOgreRenderWindow; 34 | } 35 | Ogre::RenderWindow* m_pOgreRenderWindow; 36 | 37 | protected: 38 | void paintEvent(QPaintEvent* evt); 39 | void resizeEvent(QResizeEvent* evt); 40 | 41 | private: 42 | void initialiseOgre(); 43 | void moveAndResize(); 44 | 45 | QWidget* m_pParentWidget; 46 | 47 | Ogre::RenderSystem* m_ActiveRenderSystem; 48 | Ogre::Root* m_Root; 49 | 50 | QTimer* m_UpdateTimer; 51 | }; 52 | } 53 | 54 | #endif /*QTOGRE_OGREWIDGET_H_*/ -------------------------------------------------------------------------------- /media/BilateralGaussianBlur.cg: -------------------------------------------------------------------------------- 1 | void bilateralGaussianSeparated( 2 | float2 texCoord : TEXCOORD0, 3 | uniform sampler2D samplerDepth : register(s0), 4 | uniform float4 texelSize, 5 | uniform float2 blurDir, 6 | // TODO: texture size? 7 | out float fragColor : COLOR) 8 | { 9 | float filterRadius = 10.0; 10 | float blurDepthFalloff = 2.0; 11 | float blurScale = 2.0 / filterRadius; 12 | 13 | float depth = tex2D(samplerDepth, texCoord).x; 14 | if (depth == 0) 15 | discard; 16 | 17 | float sum = 0; 18 | float wsum = 0; 19 | for(float x=-filterRadius; x<=filterRadius; x+=1.0) { 20 | float sample = tex2D(samplerDepth, texCoord + x*blurDir*texelSize).x; 21 | // spatial domain 22 | float r = x * blurScale; 23 | float w = exp(-r*r); 24 | // range domain 25 | float r2 = (sample - depth) * blurDepthFalloff; 26 | float g = exp(-r2*r2); 27 | sum += sample * w * g; 28 | wsum += w * g; 29 | } 30 | 31 | if (wsum > 0.0) { 32 | sum /= wsum; 33 | } 34 | 35 | fragColor = sum; 36 | //fragColor = 0.5; 37 | //fragColor = depth; 38 | //fragColor = 60*abs(tex2D(samplerDepth, texCoord + blurDir*texelSize).x - depth); 39 | } 40 | -------------------------------------------------------------------------------- /ParticleFluids.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | PATH=$(QTDIR)\bin%3b$(PATH) 5 | 6 | 7 | PATH=$(QTDIR)\bin%3b$(PATH) 8 | 9 | 10 | PATH=$(QTDIR)\bin%3b$(PATH) 11 | 12 | 13 | C:\Qt\4.7.1 14 | .\bin\debug 15 | WindowsLocalDebugger 16 | .\bin\release 17 | WindowsLocalDebugger 18 | 19 | -------------------------------------------------------------------------------- /ParticleFluids.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ParticleFluids", "ParticleFluids.vcxproj", "{52813862-2D9D-4556-8E97-53445EF3051B}" 5 | EndProject 6 | Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "ParticleFluidRendererPortable", "ParticleFluidRendererPortable\ParticleFluidRendererPortable.vdproj", "{F7D77F66-2F35-4390-B620-22A653D87DF2}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Release|Win32 = Release|Win32 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {52813862-2D9D-4556-8E97-53445EF3051B}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {52813862-2D9D-4556-8E97-53445EF3051B}.Debug|Win32.Build.0 = Debug|Win32 16 | {52813862-2D9D-4556-8E97-53445EF3051B}.Release|Win32.ActiveCfg = Release|Win32 17 | {52813862-2D9D-4556-8E97-53445EF3051B}.Release|Win32.Build.0 = Release|Win32 18 | {F7D77F66-2F35-4390-B620-22A653D87DF2}.Debug|Win32.ActiveCfg = Debug 19 | {F7D77F66-2F35-4390-B620-22A653D87DF2}.Debug|Win32.Build.0 = Debug 20 | {F7D77F66-2F35-4390-B620-22A653D87DF2}.Release|Win32.ActiveCfg = Release 21 | {F7D77F66-2F35-4390-B620-22A653D87DF2}.Release|Win32.Build.0 = Release 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | EndGlobal 27 | -------------------------------------------------------------------------------- /media/PointToQuadGS.cg: -------------------------------------------------------------------------------- 1 | TRIANGLE 2 | TRIANGLE_OUT 3 | void passthru_gp(AttribArray position : POSITION, 4 | AttribArray texCoord0 : TEXCOORD0, 5 | AttribArray texCoord1 : TEXCOORD1) 6 | { 7 | for(int i=0; i position : POSITION, 16 | uniform float quadSize, 17 | uniform float4x4 modelViewMatrix, 18 | uniform float4x4 projectionMatrix 19 | /*uniform float4x4 inverseViewMatrix*/) 20 | { 21 | float2 halfSize = float2(quadSize, quadSize) * 0.5; 22 | 23 | // TODO: variable names..position, pos, position_out 24 | float2 quadCorners[4]; 25 | quadCorners[0] = float2(-1.0, +1.0); 26 | quadCorners[1] = float2(-1.0, -1.0); 27 | quadCorners[2] = float2(+1.0, +1.0); 28 | quadCorners[3] = float2(+1.0, -1.0); 29 | 30 | float4 positionEyeSpace = mul(modelViewMatrix, position[0]); 31 | 32 | // TEST: make eyeSpacePos always the actual particle position 33 | float3 eyeSpacePosParticle = positionEyeSpace.xyz; 34 | 35 | for(int i=0; i<4; ++i) { 36 | float4 positionOut = positionEyeSpace; 37 | 38 | positionOut.xy += quadCorners[i] * halfSize; 39 | 40 | positionOut = mul(projectionMatrix, positionOut); 41 | 42 | emitVertex(positionOut : POSITION, 43 | quadCorners[i] : TEXCOORD0, 44 | eyeSpacePosParticle.xyz : TEXCOORD1); 45 | } 46 | //restartStrip(); 47 | 48 | //emitVertex(position[0]); 49 | 50 | } -------------------------------------------------------------------------------- /media/ScreenSpaceParticleFluid.compositor: -------------------------------------------------------------------------------- 1 | compositor ScreenSpaceParticleFluid { 2 | technique { 3 | texture SphereDepth target_width target_height PF_FLOAT32_R 4 | texture SphereDepthPong target_width target_height PF_FLOAT32_R 5 | // PF_FLOAT32_R R8G8B8 6 | texture SceneBackground target_width target_height PF_R8G8B8A8 7 | texture Thickness target_width target_height PF_FLOAT16_R 8 | 9 | 10 | // TODO: pass thickness; make "pong" depth texture "SmoothedDepth" 11 | 12 | target SceneBackground { 13 | pass clear {} 14 | 15 | pass render_scene { 16 | first_render_queue 1 17 | last_render_queue 89 18 | } 19 | } 20 | 21 | target SphereDepth { 22 | input none 23 | 24 | pass clear { 25 | clear { 26 | buffers colour 27 | } 28 | } 29 | 30 | pass render_scene { 31 | first_render_queue 90 32 | last_render_queue 90 33 | } 34 | } 35 | 36 | // TODO!: blur thickness 37 | target Thickness { 38 | input none 39 | 40 | pass clear{} 41 | 42 | pass render_scene { 43 | material_scheme Thickness 44 | first_render_queue 90 45 | last_render_queue 90 46 | } 47 | } 48 | 49 | // Smoothing 50 | target SphereDepthPong { 51 | pass clear{} 52 | pass render_quad { 53 | material BilateralGaussianX 54 | input 0 SphereDepth 55 | } 56 | } 57 | 58 | target SphereDepth { 59 | pass clear{} 60 | pass render_quad { 61 | material BilateralGaussianY 62 | input 0 SphereDepthPong 63 | } 64 | } 65 | 66 | 67 | target_output { 68 | input none 69 | 70 | pass clear { 71 | clear { 72 | buffers colour depth 73 | } 74 | } 75 | 76 | pass render_quad { 77 | material FluidSurfaceShading 78 | input 0 SphereDepth 79 | input 1 SceneBackground 80 | input 2 Thickness 81 | } 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /particlefluids.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | ParticleFluidsClass 4 | 5 | 6 | 7 | 0 8 | 0 9 | 1095 10 | 803 11 | 12 | 13 | 14 | ParticleFluids 15 | 16 | 17 | 18 | 19 | 20 | 0 21 | 0 22 | 1095 23 | 21 24 | 25 | 26 | 27 | 28 | File 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | TopToolBarArea 37 | 38 | 39 | false 40 | 41 | 42 | 43 | 44 | 45 | 46 | 160 47 | 100 48 | 49 | 50 | 51 | PhysX Simulation Parameters 52 | 53 | 54 | 1 55 | 56 | 57 | 58 | 59 | 60 | 8 61 | 62 | 63 | 64 | 65 | 66 | Exit 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | actionExit 77 | triggered() 78 | ParticleFluidsClass 79 | close() 80 | 81 | 82 | -1 83 | -1 84 | 85 | 86 | 299 87 | 199 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /media/SpherePointSprites.cg: -------------------------------------------------------------------------------- 1 | #include "SphereDepth.cg" 2 | 3 | struct VSOutput { 4 | float4 position : POSITION; 5 | float2 texCoord : TEXCOORD0; 6 | float3 eyeSpacePos : TEXCOORD1; 7 | }; 8 | 9 | VSOutput passThroughVS( 10 | float4 position : POSITION) 11 | { 12 | VSOutput OUT; 13 | 14 | OUT.position = position; 15 | 16 | return OUT; 17 | } 18 | 19 | VSOutput particleSphereVS( 20 | float4 position : POSITION, 21 | float2 texCoord : TEXCOORD0, 22 | uniform float4x4 modelViewMatrix, 23 | uniform float4x4 projectionMatrix) 24 | { 25 | VSOutput OUT; 26 | 27 | float4 eyeSpacePos = mul(modelViewMatrix, position); 28 | OUT.position = mul(projectionMatrix, eyeSpacePos); 29 | OUT.eyeSpacePos = eyeSpacePos.xyz; 30 | OUT.texCoord = texCoord; 31 | 32 | return OUT; 33 | } 34 | 35 | // ---------------------------------- 36 | 37 | void simplestPS(out float4 fragColor : COLOR) { 38 | fragColor = float4(0.0, 0.0, 1.0, 1.0); 39 | } 40 | 41 | struct PSOutput { 42 | float fragDepth : DEPTH; 43 | float4 fragColor : COLOR; 44 | }; 45 | 46 | PSOutput particleSphereDiffusePS( 47 | float2 texCoord : TEXCOORD0, 48 | float3 eyeSpacePos : TEXCOORD1, 49 | uniform float sphereRadius, // TODO!: sync with PhysX params... 50 | //float4 color : COLOR0, // TODO later: use for density? 51 | uniform float4x4 projectionMatrix, 52 | uniform float3 lightDir, 53 | uniform float ambient) 54 | { 55 | float4 color = float4(0,0,1,1); 56 | 57 | PSOutput OUT; 58 | 59 | float3 N; 60 | float4 pixelPos; 61 | OUT.fragDepth = computeSphereDepth(texCoord, eyeSpacePos, sphereRadius, projectionMatrix, N, pixelPos); 62 | 63 | // simple diffuse and ambient shading 64 | float diffuse = max(0.0, dot(N, lightDir)); 65 | OUT.fragColor = diffuse * color + ambient * color; 66 | 67 | //OUT.fragColor = float4(N, 1);//OUT.fragDepth;//float4(1,0,0,1); 68 | 69 | return OUT; 70 | } 71 | 72 | void particleSphereDepthPS( 73 | float2 texCoord : TEXCOORD0, 74 | float3 eyeSpacePosParticle : TEXCOORD1, 75 | uniform float sphereRadius, // TODO!: sync with PhysX params... 76 | uniform float4x4 projectionMatrix, 77 | out float fragDepth : DEPTH, 78 | out float fragColor : COLOR) 79 | { 80 | float3 N; 81 | float4 pixelPos; 82 | float2 depth = computeSphereDepth(texCoord, eyeSpacePosParticle, sphereRadius, projectionMatrix, N, pixelPos); 83 | fragColor = depth[0]; 84 | //fragColor = eyeSpacePos; 85 | fragDepth = depth[1]; 86 | } 87 | 88 | void particleSphereThicknessPS( 89 | float2 texCoord : TEXCOORD0, 90 | float3 eyeSpacePosParticle : TEXCOORD1, 91 | uniform float sphereRadius, 92 | uniform float4x4 projectionMatrix, 93 | out float fragColor : COLOR) 94 | // TODO!: write depth as well? 95 | { 96 | float3 N; 97 | float4 pixelPos; 98 | computeSphereDepth(texCoord, eyeSpacePosParticle, sphereRadius, projectionMatrix, N, pixelPos); 99 | // 100 | //fragColor = mul(distance(float4(eyeSpacePos, 0.0), pixelPos), projectionMatrix).length(); 101 | 102 | fragColor = 0.2 * N.z; 103 | } 104 | -------------------------------------------------------------------------------- /qdebugstream.h: -------------------------------------------------------------------------------- 1 | #ifndef QDEBUGSTREAM_H 2 | #define QDEBUGSTREAM_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | class QDebugStream : public std::basic_streambuf 11 | { 12 | public: 13 | // TODO: QDebugStream: another parameter: stream prefix? or in Ogre log? 14 | QDebugStream(std::ostream &stream, QPlainTextEdit* text_edit) : m_stream(stream) 15 | { 16 | log_window = text_edit; 17 | m_old_buf = stream.rdbuf(); 18 | stream.rdbuf(this); 19 | } 20 | ~QDebugStream() 21 | { 22 | // output anything that is left 23 | if (!m_string.empty()) 24 | analyzeText(m_string); 25 | 26 | m_stream.rdbuf(m_old_buf); 27 | } 28 | 29 | protected: 30 | enum MessageType { 31 | Information, 32 | Warning, 33 | Error, 34 | Blank 35 | }; 36 | 37 | virtual int_type overflow(int_type v) 38 | { 39 | if (v == '\n') { 40 | analyzeText(m_string); 41 | m_string.erase(m_string.begin(), m_string.end()); 42 | } 43 | else 44 | m_string += v; 45 | 46 | return v; 47 | } 48 | 49 | virtual std::streamsize xsputn(const char *p, std::streamsize n) 50 | { 51 | m_string.append(p, p + n); 52 | 53 | int pos = 0; 54 | while (pos != std::string::npos) { 55 | pos = m_string.find('\n'); 56 | if (pos != std::string::npos) { 57 | std::string tmp(m_string.begin(), m_string.begin() + pos); 58 | analyzeText(tmp); 59 | m_string.erase(m_string.begin(), m_string.begin() + pos + 1); 60 | } 61 | } 62 | 63 | return n; 64 | } 65 | 66 | virtual void analyzeText(std::string str) { 67 | int pos; 68 | 69 | //pos = str.find("blablub"); // vrs style 70 | //if(pos != std::string::npos) { 71 | // addItem(Warning, str); 72 | // return; 73 | //} 74 | 75 | addItem(Blank, str); 76 | } 77 | 78 | virtual void addItem(MessageType type, std::string str) { 79 | if(str.length() > 1) { 80 | // switch(type) { 81 | // case Information: 82 | //} 83 | 84 | //log_window->scrollToBottom(); 85 | 86 | log_window->appendPlainText(QString("%1: %2").arg(QTime::currentTime().toString()).arg(QString::fromStdString(str))); 87 | } 88 | } 89 | 90 | private: 91 | std::ostream &m_stream; 92 | std::streambuf *m_old_buf; 93 | std::string m_string; 94 | QPlainTextEdit* log_window; 95 | }; 96 | 97 | #endif // QDEBUGSTREAM_H -------------------------------------------------------------------------------- /OgreWidget.h: -------------------------------------------------------------------------------- 1 | // from http://www.ogre3d.org/forums/viewtopic.php?p=367010&sid=5f3feeed878d9121b62dec0d82e7d19e#p367010 (orginally from Ogitor) 2 | 3 | #ifndef OGREWIDGET_H 4 | #define OGREWIDGET_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace NxOgre { 12 | class World; 13 | class TimeController; 14 | class Scene; 15 | class VisualDebugger; 16 | class Fluid; 17 | class FluidEmitter; 18 | class FluidDescription; 19 | } 20 | 21 | namespace Critter { 22 | class RenderSystem; 23 | class Renderable; 24 | } 25 | 26 | class ResourceGroupHelper; 27 | 28 | class OgreWidget : public QWidget, public Ogre::FrameListener 29 | { 30 | Q_OBJECT 31 | 32 | public: 33 | OgreWidget(QWidget *parent = 0); 34 | ~OgreWidget(); 35 | 36 | // Override QWidget::paintEngine to return NULL 37 | QPaintEngine* paintEngine() const; // Turn off QTs paint engine for the Ogre widget. 38 | 39 | // FrameListener 40 | bool frameStarted(const Ogre::FrameEvent &evt); 41 | bool frameRenderingQueued(const Ogre::FrameEvent &evt); 42 | bool frameEnded(const Ogre::FrameEvent &evt); 43 | 44 | void createFluid(); 45 | 46 | public slots: 47 | void setBackgroundColor(QColor c); 48 | //void setCameraPosition(const Ogre::Vector3 &pos); 49 | 50 | signals: 51 | //void cameraPositionChanged(const Ogre::Vector3 &pos); 52 | 53 | protected: 54 | virtual void keyPressEvent(QKeyEvent *e); 55 | virtual void moveEvent(QMoveEvent *e); 56 | virtual void mouseDoubleClickEvent(QMouseEvent *e); 57 | virtual void mouseMoveEvent(QMouseEvent *e); 58 | virtual void mousePressEvent(QMouseEvent *e); 59 | virtual void mouseReleaseEvent(QMouseEvent *e); 60 | virtual void paintEvent(QPaintEvent *e); 61 | virtual void resizeEvent(QResizeEvent *e); 62 | virtual void showEvent(QShowEvent *e); 63 | virtual void wheelEvent(QWheelEvent *e); 64 | 65 | private: 66 | void initOgreSystem(); 67 | void setupResources(); 68 | void setupNxOgre(); 69 | void createScene(); 70 | 71 | void updateFrameStats(); 72 | 73 | private: 74 | static const Ogre::Real turboModifier; 75 | static const QPoint invalidMousePoint; 76 | 77 | private: 78 | Ogre::Root *mRoot; 79 | Ogre::SceneManager *mSceneMgr; 80 | Ogre::RenderWindow *mRenderWindow; 81 | Ogre::Viewport *mViewport; 82 | Ogre::Camera *mCamera; 83 | 84 | QPoint oldPos; 85 | Ogre::SceneNode *selectedNode; 86 | 87 | // NxOgre 88 | NxOgre::World* mPhysicsWorld; 89 | NxOgre::TimeController* mPhysicsTimeController; 90 | NxOgre::Scene* mPhysicsScene; 91 | Critter::RenderSystem* mPhysicsRenderSystem; 92 | NxOgre::VisualDebugger* mVisualDebugger; 93 | Critter::Renderable* mVisualDebuggerRenderable; 94 | Ogre::SceneNode* mVisualDebuggerNode; 95 | 96 | Ogre::Overlay* mDebugOverlay; 97 | 98 | ResourceGroupHelper* mResourceGroupHelper; 99 | 100 | Ogre::AnimationState* mOgreBaseAnim; 101 | Ogre::AnimationState* mOgreTopAnim; 102 | 103 | public: 104 | NxOgre::FluidDescription mFluidDescription; 105 | NxOgre::FluidEmitterDescription mEmitterDescription; 106 | 107 | NxOgre::Fluid* mFluid; 108 | NxOgre::FluidEmitter* mEmitter; 109 | 110 | float mSimulationSpeed; 111 | }; 112 | 113 | #endif OGREWIDGET_H -------------------------------------------------------------------------------- /media/FluidSurfaceShading.cg: -------------------------------------------------------------------------------- 1 | float3 uvToEye(float2 texCoord, float depth, float2 invFocalLen) { 2 | texCoord = texCoord * 2.0 - 1.0; 3 | texCoord = texCoord * invFocalLen * depth; 4 | 5 | return float3(texCoord * invFocalLen * depth, depth); 6 | 7 | //float4 clipPos = float4((texCoord * 2.0 - 1.0) * invFocalLen * depth, depth, 1.0); 8 | //float4 clipPos = float4((texCoord * 2.0 - 1.0) * invFocalLen * depth, depth, 1.0); 9 | 10 | //float4 viewPos = mul(clipPos, invProjectionMatrix); 11 | //return clipPos.xyz;// viewPos.xyz / viewPos.w; 12 | } 13 | 14 | float3 getEyePos(sampler2D samplerDepth, float2 texCoord, float2 invFocalLen) { 15 | return uvToEye(texCoord, tex2D(samplerDepth, texCoord).r, invFocalLen); 16 | } 17 | 18 | 19 | void shadeFluidSurfacePS( 20 | float2 texCoord : TEXCOORD0, 21 | uniform float4x4 invTransWorldview, 22 | uniform float fovy, 23 | uniform sampler2D samplerDepth : register(s0), 24 | uniform float4 packedTextureSize, // float4(width, height, 1 / width, 1 / height) - Ogre auto param 25 | uniform sampler2D samplerBackground : register(s1), 26 | uniform sampler2D samplerThickness : register(s2), 27 | uniform samplerCUBE samplerEnvCube : register(s3), 28 | uniform float3 lightDir, 29 | uniform float3x3 normalMatrix, 30 | uniform float3 lightDir_view_space, 31 | /*uniform float4 lightDirViewSpaceTest,*/ 32 | out float4 fragColor : COLOR) 33 | { 34 | float4 backgroundColor = tex2D(samplerBackground, texCoord); 35 | 36 | float fluidDepth = tex2D(samplerDepth, texCoord).r; 37 | float depthThreshold = 0.1; 38 | if(fluidDepth == 0) { 39 | fragColor = backgroundColor; 40 | return; 41 | } 42 | 43 | float fovx = fovy * packedTextureSize.x / packedTextureSize.y; 44 | float2 invFocalLen = float2(tan(fovx/2), tan(fovy/2)); 45 | 46 | float3 eyePos = uvToEye(texCoord, fluidDepth, invFocalLen); 47 | //fragColor = float4(eyePos, 1.0); 48 | 49 | // calculate differences 50 | float3 ddx = getEyePos(samplerDepth, texCoord + float2(packedTextureSize[2], 0), invFocalLen) - eyePos; 51 | float3 ddx2 = eyePos - getEyePos(samplerDepth, texCoord + float2(-packedTextureSize[2], 0), invFocalLen); 52 | if (abs(ddx.z) > depthThreshold /*abs(ddx2.z)*/){ 53 | ddx = ddx2; 54 | } 55 | 56 | float3 ddy = getEyePos(samplerDepth, texCoord[0] + float2(0, packedTextureSize[3]), invFocalLen) - eyePos; 57 | float3 ddy2 = eyePos - getEyePos(samplerDepth, texCoord + float2(0, -packedTextureSize[3]), invFocalLen); 58 | if (abs(ddy2.z) < depthThreshold /*abs(ddy.z)*/) { 59 | ddy = ddy2; 60 | } 61 | // calculate normal 62 | float3 n = cross(ddx, ddy); 63 | n = normalize(n); 64 | 65 | 66 | // lighting 67 | float4 fluidColor = float4(0.25, 0.35, 1.0, 1.0); //float4(0.25, 0.35, 1.0, 1.0); 68 | float4 colorFalloff = float4(2.0, 1.0, 0.5, 1.0); 69 | float falloffScale = 0.3; 70 | float3 thicknessRefraction = float3(2.0, 2.3, 2.6); 71 | float fresnelBias = 0.1; 72 | float fresnelScale = 0.4; 73 | float fresnelPower = 2.0; 74 | 75 | float shininess = 50.0; 76 | float ambient = 0.3; 77 | 78 | float diffuse = max(0.0, dot(n, lightDir)); 79 | 80 | float3 v = normalize(eyePos); 81 | float3 h = normalize(lightDir + v); 82 | float specular = pow(max(0.0, dot(n, h)), shininess); 83 | 84 | //WIP 85 | float fresnel = 0.2 + 0.8*pow(1.0 - max(0.0, dot(n, v)), 2.0); 86 | float3 r = reflect(-v, n); 87 | r = mul(normalMatrix, r); 88 | float4 reflectColor = texCUBE(samplerEnvCube, r); 89 | float thickness = tex2D(samplerThickness, texCoord).r; 90 | 91 | //attenuate fluid colour 92 | fluidColor = fluidColor * exp(-thickness*falloffScale*colorFalloff); 93 | 94 | float refraction = thickness*thicknessRefraction.x; 95 | float4 sceneColor = tex2D(samplerBackground, texCoord + n.xy + refraction); 96 | float4 finalColor = float4(fluidColor.xyz + reflectColor.xyz*fresnel + specular * float3(1,1,1), 1.0); 97 | float alpha = saturate(fluidColor.w); 98 | 99 | fragColor = lerp(finalColor, sceneColor, alpha); 100 | 101 | 102 | //float4 fluid_diffspec = fluidColor * diffuse + fluidColor * ambient + specular * float4(1.0,1.0,1.0,1.0); 103 | 104 | //fragColor = lerp(fluid_diffspec, backgroundColor, exp(-thickness)); 105 | 106 | 107 | // debug outputs 108 | //fragColor = float4(fluidDepth, (fluidDepth - 2)/2, (fluidDepth - 4)/4, 1.0); 109 | //fragColor = float4(n, 1.0); 110 | //fragColor = float4(thickness.xxx, 1.0); 111 | //fragColor = float4(abs(lightDir_view_space.x), abs(lightDir_view_space.y), abs(lightDir_view_space.z), 1.0); 112 | //fragColor = float4(abs(lightDirViewSpaceTest.x), abs(lightDirViewSpaceTest.y), abs(lightDirViewSpaceTest.z), 1.0); 113 | //eyePos /= 10; 114 | //fragColor = float4(abs(eyePos.x), abs(eyePos.y), abs(eyePos.z), 1.0); 115 | //fragColor = texCUBE(samplerEnvCube, n); 116 | 117 | } 118 | -------------------------------------------------------------------------------- /media/ParticleSplatting.material: -------------------------------------------------------------------------------- 1 | vertex_program SpherePointSpritesVS cg { 2 | source SpherePointSprites.cg 3 | entry_point particleSphereVS 4 | profiles gp4vp glslv arbvp1 vp20 vp30 5 | 6 | default_params { 7 | param_named_auto modelViewMatrix worldview_matrix 8 | param_named_auto projectionMatrix projection_matrix 9 | } 10 | } 11 | 12 | vertex_program PassThroughVS cg { 13 | source SpherePointSprites.cg 14 | entry_point passThroughVS 15 | profiles gp4vp glslv arbvp1 vp20 vp30 16 | } 17 | 18 | geometry_program ParticleGS cg { 19 | source PointToQuadGS.cg 20 | entry_point pointToQuad 21 | profiles gp4gp gpu_gp 22 | 23 | default_params { 24 | param_named quadSize float 0.15 25 | param_named_auto modelViewMatrix worldview_matrix 26 | param_named_auto projectionMatrix projection_matrix 27 | } 28 | } 29 | 30 | fragment_program SimplestPS cg { 31 | source SpherePointSprites.cg 32 | entry_point simplestPS 33 | profiles gp4fp glslf arbfp1 fp20 fp30 34 | } 35 | 36 | fragment_program SpherePointSpritesDiffusePS cg { 37 | source SpherePointSprites.cg 38 | entry_point particleSphereDiffusePS 39 | profiles gp4fp glslf arbfp1 fp20 fp30 40 | //compiler_arguments debug 41 | default_params { 42 | param_named sphereRadius float 0.15 43 | param_named_auto projectionMatrix projection_matrix 44 | param_named_auto lightDir light_direction 0 45 | param_named_auto ambient ambient_light_colour 46 | //param_named lightDir float4 0.0 1.0 0.0 0.0 47 | } 48 | } 49 | 50 | fragment_program SpherePointSpritesDepthPS cg { 51 | source SpherePointSprites.cg 52 | entry_point particleSphereDepthPS 53 | profiles gp4fp glslf arbfp1 fp20 fp30 54 | 55 | default_params { 56 | param_named sphereRadius float 0.15 57 | param_named_auto projectionMatrix projection_matrix 58 | 59 | } 60 | } 61 | 62 | fragment_program SpherePointSpritesThicknessPS cg { 63 | source SpherePointSprites.cg 64 | entry_point particleSphereThicknessPS 65 | profiles gp4fp glslf arbfp1 fp20 fp30 66 | 67 | default_params { 68 | //param_named sphereRadius float 0.15 69 | //param_named_auto projectionMatrix projection_matrix 70 | } 71 | } 72 | 73 | material SpherePointSprites { 74 | technique { 75 | pass { 76 | vertex_program_ref SpherePointSpritesVS {} 77 | 78 | fragment_program_ref SpherePointSpritesDiffusePS {} 79 | } 80 | } 81 | } 82 | 83 | material SpherePointSpritesWithGS { 84 | technique { 85 | pass { 86 | vertex_program_ref PassThroughVS {} 87 | 88 | geometry_program_ref ParticleGS {} 89 | 90 | fragment_program_ref SpherePointSpritesDepthPS {} // SpherePointSpritesDiffusePS 91 | } 92 | } 93 | 94 | technique { 95 | scheme Thickness 96 | 97 | pass { 98 | scene_blend add 99 | depth_check off 100 | 101 | vertex_program_ref PassThroughVS {} 102 | 103 | geometry_program_ref ParticleGS {} 104 | 105 | fragment_program_ref SpherePointSpritesThicknessPS {} 106 | } 107 | } 108 | } 109 | 110 | shared_params lighting_params 111 | { 112 | shared_param_named normalMatrix matrix3x3 113 | shared_param_named lightDir_view_space float3 1.0 1.0 1.0 114 | } 115 | 116 | fragment_program FluidSurfaceShadingPS cg { 117 | source FluidSurfaceShading.cg 118 | entry_point shadeFluidSurfacePS 119 | profiles gp4fp glslf arbfp1 fp20 fp30 120 | default_params 121 | { 122 | // doesn't work in render_quad pass 123 | //param_named_auto invTransWorldview inverse_transpose_worldview_matrix 124 | 125 | param_named_auto fovy fov 126 | param_named_auto packedTextureSize packed_texture_size 0 127 | 128 | param_named_auto lightDir light_position_view_space 129 | 130 | // doesn't work in render_quad pass 131 | //param_named_auto lightDir light_position_view_space 0 132 | shared_params_ref lightDir_view_space 133 | param_named_auto lightDirViewSpaceTest light_position_view_space 0 134 | } 135 | } 136 | 137 | 138 | material FluidSurfaceShading { 139 | technique { 140 | pass { 141 | //lighting off 142 | //depth_check off 143 | 144 | fragment_program_ref FluidSurfaceShadingPS {} 145 | 146 | texture_unit samplerDepth { 147 | //texture ogretext.png 2d 148 | //content_type compositor ScreenSpaceParticleFluid SphereDepth 149 | } 150 | 151 | texture_unit {} 152 | 153 | texture_unit {} 154 | 155 | texture_unit 156 | { 157 | // alternative cubemaps: early_morning, evening, morning, stormy 158 | cubic_texture cloudy_noon.jpg combinedUVW 159 | tex_address_mode clamp 160 | env_map cubic_reflection 161 | } 162 | 163 | } 164 | } 165 | } 166 | 167 | material Examples/CloudyNoonSkyBox 168 | { 169 | technique 170 | { 171 | pass 172 | { 173 | lighting off 174 | depth_write off 175 | 176 | texture_unit 177 | { 178 | cubic_texture cloudy_noon.jpg separateUV 179 | tex_address_mode clamp 180 | } 181 | } 182 | } 183 | } -------------------------------------------------------------------------------- /OgreWidget_blog.cpp: -------------------------------------------------------------------------------- 1 | // from http://projectify.blogspot.com/2009/06/qt-ogre-vs2008-express.html 2 | #include "stdafx.h" 3 | #include "OgreWidget.h" 4 | 5 | #pragma warning( push ) 6 | #pragma warning( disable : 4100 ) 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #pragma warning( pop ) 14 | 15 | #include 16 | 17 | 18 | namespace QtOgre 19 | { 20 | OgreWidget::OgreWidget(QWidget* pParentWidget, Qt::WindowFlags f) 21 | :QWidget(pParentWidget, f | Qt::MSWindowsOwnDC) 22 | ,m_pOgreRenderWindow(0) 23 | ,m_pParentWidget(pParentWidget) 24 | { 25 | QWidget *q_parent = dynamic_cast (parent()); 26 | 27 | //It is possible you might need one of these on other platforms 28 | //setAttribute(Qt::WA_PaintOnScreen); 29 | //setAttribute(Qt::WA_NoSystemBackground); 30 | //setAttribute(Qt::WA_OpaquePaintEvent); 31 | //setAutoFillBackground( false ); 32 | 33 | //Create the ogre root singleton 34 | m_Root = new Ogre::Root(); 35 | //Initialise the ogre system, select the render plugins (if OpenGL is present, OpenGL is selected) 36 | initialiseOgre(); 37 | 38 | //Set window parameters 39 | Ogre::NameValuePairList ogreWindowParams; 40 | //Full Screen Anti Aliasing 41 | ogreWindowParams["FSAA"] = "8"; 42 | //Other code needed for Linux 43 | ogreWindowParams["parentWindowHandle"] = Ogre::StringConverter::toString((unsigned long)q_parent->winId()); 44 | 45 | //Finally create our window. 46 | m_pOgreRenderWindow = Ogre::Root::getSingletonPtr()->createRenderWindow("OgreWindow", width(), height(), false, &ogreWindowParams); 47 | 48 | WId window_id; 49 | //Other code need for linux 50 | m_pOgreRenderWindow->getCustomAttribute ("HWND", &window_id); 51 | 52 | // Take over the ogre created window. 53 | QWidget::create (window_id); 54 | 55 | moveAndResize(); 56 | 57 | //Connect a timer to the update method 58 | m_UpdateTimer = new QTimer; 59 | QObject::connect(m_UpdateTimer, SIGNAL(timeout()), this, SLOT(update())); 60 | //Reducing the timer should give a higher framerate 61 | m_UpdateTimer->start(40); 62 | } 63 | 64 | OgreWidget::~OgreWidget() 65 | { 66 | } 67 | 68 | Ogre::RenderWindow* OgreWidget::getOgreRenderWindow() const 69 | { 70 | return m_pOgreRenderWindow; 71 | } 72 | 73 | /* Adding this was the solution to a flickering issue for someone using Qt and Ogre 74 | QPaintEngine *OgreWidget:: paintEngine() const 75 | { 76 | return 0; 77 | }*/ 78 | 79 | void OgreWidget::paintEvent(QPaintEvent* /*evt*/) 80 | { 81 | Ogre::Root::getSingleton()._fireFrameStarted(); 82 | m_pOgreRenderWindow->update(); 83 | Ogre::Root::getSingleton()._fireFrameRenderingQueued(); 84 | Ogre::Root::getSingleton()._fireFrameEnded(); 85 | } 86 | 87 | void OgreWidget::resizeEvent(QResizeEvent* /*evt*/) 88 | { 89 | moveAndResize(); 90 | } 91 | 92 | void OgreWidget::moveAndResize() 93 | { 94 | m_pOgreRenderWindow->reposition (x(),y()); 95 | m_pOgreRenderWindow->resize(width(), height()); 96 | m_pOgreRenderWindow->windowMovedOrResized(); 97 | 98 | for(int ct = 0; ct < m_pOgreRenderWindow->getNumViewports(); ++ct) 99 | { 100 | Ogre::Viewport* pViewport = m_pOgreRenderWindow->getViewport(ct); 101 | Ogre::Camera* pCamera = pViewport->getCamera(); 102 | pCamera->setAspectRatio(static_cast(pViewport->getActualWidth()) / static_cast(pViewport->getActualHeight())); 103 | } 104 | } 105 | 106 | void OgreWidget::initialiseOgre(void) 107 | { 108 | //This will choose the OpenGL rendersystem as default 109 | //and will try to use Direct3D if loading OpenGL failed 110 | Ogre::RenderSystem* OpenGLRenderSystem = 0; 111 | Ogre::RenderSystem* Direct3D9RenderSystem = 0; 112 | 113 | try 114 | { 115 | #if defined(_DEBUG) 116 | m_Root->loadPlugin("RenderSystem_GL_d"); 117 | #else 118 | m_Root->loadPlugin("RenderSystem_GL"); 119 | #endif 120 | } 121 | catch(...) 122 | { 123 | qWarning("Failed to load OpenGL plugin"); 124 | } 125 | try 126 | { 127 | #if defined(_DEBUG) 128 | m_Root->loadPlugin("RenderSystem_Direct3D9_d"); 129 | #else 130 | m_Root->loadPlugin("RenderSystem_Direct3D9"); 131 | #endif 132 | } 133 | catch(...) 134 | { 135 | qWarning("Failed to load Direct3D9 plugin"); 136 | } 137 | 138 | Ogre::RenderSystemList list = Ogre::Root::getSingletonPtr()->getAvailableRenderers(); 139 | Ogre::RenderSystemList::iterator i = list.begin(); 140 | 141 | while (i != list.end()) 142 | { 143 | if ((*i)->getName() == "OpenGL Rendering Subsystem") 144 | { 145 | OpenGLRenderSystem = *i; 146 | } 147 | if ((*i)->getName() == "Direct3D9 Rendering Subsystem") 148 | { 149 | Direct3D9RenderSystem = *i; 150 | } 151 | i++; 152 | } 153 | 154 | if(!(OpenGLRenderSystem || Direct3D9RenderSystem)) 155 | { 156 | qCritical("No rendering subsystems found"); 157 | exit(0); 158 | } 159 | 160 | if(OpenGLRenderSystem != 0) 161 | { 162 | m_ActiveRenderSystem = OpenGLRenderSystem; 163 | } 164 | else if(Direct3D9RenderSystem != 0) 165 | { 166 | m_ActiveRenderSystem = Direct3D9RenderSystem; 167 | } 168 | 169 | Ogre::Root::getSingletonPtr()->setRenderSystem(m_ActiveRenderSystem); 170 | 171 | Ogre::Root::getSingletonPtr()->initialise(false); 172 | } 173 | } -------------------------------------------------------------------------------- /ParticleFluids.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;cxx;c;def 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h 11 | 12 | 13 | {99349809-55BA-4b9d-BF79-8FDBB0286EB3} 14 | ui 15 | 16 | 17 | {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E} 18 | qrc;* 19 | false 20 | 21 | 22 | {71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11} 23 | moc;h;cpp 24 | False 25 | 26 | 27 | {4350f122-4549-480c-ad8f-aba6fcc480db} 28 | cpp;moc 29 | False 30 | 31 | 32 | {7e9b0fb9-313e-4aca-9419-ca129804b545} 33 | cpp;moc 34 | False 35 | 36 | 37 | {39f69f53-1c00-4bcd-bbc0-24a6e9e2008f} 38 | 39 | 40 | {9c7ace45-4d4c-4904-8d88-0002b27c7aa5} 41 | 42 | 43 | 44 | 45 | Source Files 46 | 47 | 48 | Source Files 49 | 50 | 51 | Source Files 52 | 53 | 54 | Source Files 55 | 56 | 57 | Source Files 58 | 59 | 60 | Generated Files 61 | 62 | 63 | Generated Files\Release 64 | 65 | 66 | Generated Files\Release 67 | 68 | 69 | Generated Files\Debug 70 | 71 | 72 | Generated Files\Debug 73 | 74 | 75 | 76 | 77 | Header Files 78 | 79 | 80 | Header Files 81 | 82 | 83 | Header Files 84 | 85 | 86 | Generated Files 87 | 88 | 89 | Header Files 90 | 91 | 92 | 93 | 94 | Shaders 95 | 96 | 97 | Shaders 98 | 99 | 100 | Shaders 101 | 102 | 103 | Shaders 104 | 105 | 106 | Resource Files 107 | 108 | 109 | Ogre Scripts 110 | 111 | 112 | Ogre Scripts 113 | 114 | 115 | Ogre Scripts 116 | 117 | 118 | Shaders 119 | 120 | 121 | Ogre Scripts 122 | 123 | 124 | Shaders 125 | 126 | 127 | Ogre Scripts 128 | 129 | 130 | 131 | 132 | Header Files 133 | 134 | 135 | Header Files 136 | 137 | 138 | Form Files 139 | 140 | 141 | Resource Files 142 | 143 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /ResourceGroupHelper.h: -------------------------------------------------------------------------------- 1 | // taken from http://www.ogre3d.org/forums/viewtopic.php?f=5&t=46787&start=25#p329272 2 | 3 | #ifndef RESOURCEGROUPHELPER_H 4 | #define RESOURCEGROUPHELPER_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | ///\brief a fake class with different useful methods for manipulating Resourcegroups. 12 | /// please note that it was not tested with background loading. 13 | 14 | class ResourceGroupHelper 15 | { 16 | private: 17 | 18 | /// \brief anti copy constructor (no use) 19 | ResourceGroupHelper(const ResourceGroupHelper&); 20 | /// \brief anti affector (no use) 21 | ResourceGroupHelper& operator=(const ResourceGroupHelper&); 22 | 23 | /// \brief a helper method to visit all overlay 24 | /// it uses a recursive call 25 | void visitRecursivelyRenderablesFrom(Ogre::OverlayContainer* pOverlayContainer, Ogre::Renderable::Visitor& pVisitor, bool debugRenderable = false); 26 | 27 | ///\brief a map [key : nameOfTheRessourceGroup]/[value : last modification time on the hdd from the files of the ResourceGroup] 28 | std::map mRessourceGroupModificationTimes; 29 | 30 | // ------ helper classes 31 | 32 | /// \brief this visitor will be used to set the material on known renderable that allow this operation. 33 | /// for other user class renderable, must be tweaked/changed 34 | class UpdateMaterialRenderableVisitor : public Ogre::Renderable::Visitor 35 | { 36 | private: 37 | UpdateMaterialRenderableVisitor(const UpdateMaterialRenderableVisitor&);///<\brief anti copyconstructor 38 | UpdateMaterialRenderableVisitor& operator=(const UpdateMaterialRenderableVisitor&);///<\brief anti affector 39 | public: 40 | /// \brief default constructor 41 | UpdateMaterialRenderableVisitor(); 42 | /// \brief called for each renderable 43 | virtual void visit(Ogre::Renderable *rend, Ogre::ushort lodIndex, bool isDebug, Ogre::Any *pAny=0); 44 | }; 45 | 46 | ///\brief this class will listen to the log. 47 | /// it will check if there are "errors" or "exception" send to the listener 48 | /// and allows to keep or not the messages. 49 | class ResourceGroupHelperLogListener : public Ogre::LogListener 50 | { 51 | private: 52 | ResourceGroupHelperLogListener(const ResourceGroupHelperLogListener&);///<\brief anti copyconstructor 53 | ResourceGroupHelperLogListener& operator=(const ResourceGroupHelperLogListener&);///<\brief anti affector 54 | std::stringstream mKeptMessages;///<\brief interesting messages that we choose to keep 55 | public: 56 | /// \brief the constructor 57 | ResourceGroupHelperLogListener(); 58 | ///\brief the destructor de-register itself from the log 59 | ~ResourceGroupHelperLogListener(); 60 | /// \brief called for each message 61 | virtual void messageLogged(const Ogre::String &message, Ogre::LogMessageLevel lml, bool maskDebug, const Ogre::String &logName); 62 | /// \brief get a copy of kept messages 63 | std::string getKeptMessages(); 64 | ///\brief tells if mKeptMessages is empty or not 65 | bool areMessagesKept(); 66 | ///\brief clear the kept messages 67 | void clearKeptMessages(); 68 | }; 69 | 70 | public: 71 | /// \brief default constructor 72 | ResourceGroupHelper(void); 73 | 74 | /// \brief destructor 75 | ~ResourceGroupHelper(void); 76 | 77 | /// \brief : a path + the archive type. 78 | typedef std::pair ArchivePathAndType; 79 | 80 | /// \brief get a vector with directory path and corresponding type. 81 | /// can be useful if you want to reload some Resourcegroup. 82 | /// note : does not check the config file. 83 | /// \param the name of the resourcegroup 84 | /// \warning there is no garanty that the path order will be the same than during the first loading. 85 | std::vector getAllPathAndTypesNames(const std::string& pResourceGroupName); 86 | 87 | /// \brief tries to suppress a Resourcegroup and reload it completely using the provided ordered locations. 88 | /// \param the name of the resourcegroup 89 | /// \param the path and types of the archives to be loaded, and in the order to be loaded 90 | /// it will not work correctly if some elements of the Resourcegroup are still used. 91 | /// \return true if the Resourcegroup was found and correctly destroy, false otherwise. 92 | bool reloadAResourceGroup(const std::string& pResourceGroupName,const std::vector& pLocationToAdd); 93 | 94 | /// \brief this serves the same purpose than reloadAResourceGroup, but it does not destroy/recreate the ResourceGroup. 95 | /// \param the name of the resourcegroup 96 | /// on the one hand, you don't need to worry about the path and order of the locations. 97 | /// on the other hand, there is no test that the resources were really cleared and reloaded. 98 | /// personnally I prefer this thought, because it's much smarter & less costly in the end. 99 | bool reloadAResourceGroupWithoutDestroyingIt(const std::string& pResourceGroupName); 100 | 101 | /// \brief return true if the resourcegroup exists 102 | /// \param the name of the resourcegroup 103 | bool resourceGroupExist(const std::string& pResourceGroupName); 104 | 105 | /// \brief updating informations about materials on all 'reachable' renderables 106 | /// that are currently used by the different scenemanagers and overlays 107 | void updateOnEveryRenderable(); 108 | 109 | /// \brief get the latest modification time : check all files date from the resourcegroup 110 | /// \param the name of the resourcegroup 111 | /// \warning time-costly! because access the HDD! 112 | time_t getLatestModificationTime(const std::string& pResourceGroupName); 113 | 114 | //bool filesChanged(const std::string& pResourceGroupName); 115 | 116 | /// \brief test latest modification time. 117 | /// if it did change since the latest call to this function, 118 | /// then the resourcegroup is reloaded 119 | /// and all the renderables are updated 120 | /// bool returns if reload was tried or not. 121 | /// if an error happens during reloading (parsing script + glsl), it is likely to be 122 | /// described in the pOutLoggedMessages param, if useLog. 123 | bool checkTimeAndReloadIfNeeded(const std::string& pResourceGroupName,std::string &pOutLoggedMessages, bool useLog=true); 124 | }; 125 | 126 | #endif -------------------------------------------------------------------------------- /particlefluids.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "particlefluids.h" 3 | #include "OgreWidget.h" 4 | #include "qtvariantproperty.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "qdebugstream.h" 12 | 13 | ParticleFluids::ParticleFluids(QWidget *parent, Qt::WFlags flags) 14 | : QMainWindow(parent, flags) 15 | { 16 | ui.setupUi(this); 17 | QPlainTextEdit* consoleOutput = new QPlainTextEdit(); 18 | consoleOutput->setReadOnly(true); 19 | ui.dockWidgetConsole->setWidget(consoleOutput); 20 | 21 | mCout = new QDebugStream(std::cout, consoleOutput); 22 | mCerr = new QDebugStream(std::cerr, consoleOutput); 23 | 24 | mOgreWidget = new OgreWidget(this); 25 | setCentralWidget(mOgreWidget); 26 | 27 | // let the OgreWidget redraw as often as possible 28 | QTimer* timer = new QTimer(); 29 | timer->setInterval(0); 30 | connect(timer, SIGNAL(timeout()), mOgreWidget, SLOT(update())); 31 | timer->start(); 32 | 33 | setupPhysXGUI(); 34 | 35 | mLabelCamPos = new QLabel(); 36 | statusBar()->addPermanentWidget(mLabelCamPos); 37 | 38 | mLabelParticleCount = new QLabel("Particle Count: 0"); 39 | statusBar()->addPermanentWidget(mLabelParticleCount); 40 | } 41 | 42 | ParticleFluids::~ParticleFluids() 43 | { 44 | delete mCout; 45 | delete mCerr; 46 | } 47 | 48 | void ParticleFluids::setupPhysXGUI() { 49 | QtVariantPropertyManager* variantManager = new QtVariantPropertyManager(this); 50 | QtVariantEditorFactory *variantFactory = new QtVariantEditorFactory(this); 51 | 52 | //QtGroupBoxPropertyBrowser* propertyEditor = new QtGroupBoxPropertyBrowser(ui.dockWidgetPhysX); 53 | //QtTreePropertyBrowser* propertyEditor = new QtTreePropertyBrowser(ui.dockWidgetPhysX); 54 | QtButtonPropertyBrowser* propertyEditor = new QtButtonPropertyBrowser(ui.dockWidgetPhysX); 55 | 56 | propertyEditor->setFactoryForManager(variantManager, variantFactory); 57 | 58 | ui.dockWidgetPhysX->setWidget(propertyEditor); 59 | 60 | propertyEditor->show(); 61 | 62 | QtGroupPropertyManager* groupManager = new QtGroupPropertyManager(this); 63 | 64 | //QtProperty *group = groupManager->addProperty("General"); // Sim speed, sim paused (speed = 0?) 65 | //QtBrowserItem* generalGroupItem = propertyEditor->addProperty(group); 66 | 67 | QtVariantProperty *property = variantManager->addProperty(QVariant::Double, "Simulation Speed"); 68 | property->setValue(1); 69 | property->setAttribute("minimum", 0); 70 | property->setToolTip("the time difference for the PhysX simulation step is multiplied by this factor"); 71 | propertyEditor->addProperty(property); 72 | 73 | QtProperty *group = groupManager->addProperty("Fluid"); 74 | QtBrowserItem* fluidGroupItem = propertyEditor->addProperty(group); 75 | 76 | property = variantManager->addProperty(QVariant::Int, "MaxParticles"); 77 | property->setAttribute("singleStep", 200); 78 | property->setAttribute("minimum", 1); 79 | property->setAttribute("maximum", 65535); 80 | property->setValue(mOgreWidget->mFluidDescription.mMaxParticles); 81 | group->addSubProperty(property); 82 | 83 | property = variantManager->addProperty(QVariant::Double, "KernelRadiusMultiplier"); 84 | property->setValue(mOgreWidget->mFluidDescription.mKernelRadiusMultiplier); 85 | //property->setAttribute("decimals", 4); 86 | property->setAttribute("minimum", 1); 87 | property->setAttribute("singleStep", 0.1); 88 | property->setToolTip("along with restParticlesPerMeter, controls the radius of influence for each particle. \n\ 89 | radius = KernelRadiusMultiplier / RestParticlesPerMeter. Should be set around 2.0 and definitely below 2.5 for optimal performance and simulation quality."); 90 | group->addSubProperty(property); 91 | 92 | property = variantManager->addProperty(QVariant::Double, "RestParticlesPerMeter"); 93 | property->setValue(mOgreWidget->mFluidDescription.mRestParticlesPerMetre); 94 | //property->setAttribute("decimals", 4); 95 | property->setAttribute("minimum", 0.01); 96 | property->setAttribute("singleStep", 0.1); 97 | property->setToolTip("The particle resolution given as particles per linear meter measured when the fluid is in its rest state (relaxed).\n\ 98 | Even if the particle system is simulated without particle interactions, this parameter defines the emission density of the emitters."); 99 | group->addSubProperty(property); 100 | 101 | property = variantManager->addProperty(QVariant::Double, "RestDensity"); 102 | property->setValue(mOgreWidget->mFluidDescription.mRestDensity); 103 | property->setAttribute("minimum", 0.01); 104 | property->setAttribute("singleStep", 10); 105 | property->setToolTip("Target density for the fluid (water is about 1000). mass = restDensity/(restParticlesPerMeter^3).\n\ 106 | The particle mass has an impact on the repulsion effect on emitters and actors."); 107 | group->addSubProperty(property); 108 | 109 | property = variantManager->addProperty(QVariant::Double, "Viscosity"); 110 | property->setValue(mOgreWidget->mFluidDescription.mViscosity); 111 | //property->setAttribute("decimals", 4); 112 | property->setAttribute("minimum", 0.01); 113 | property->setToolTip("Must be positive. Higher values will result in a honey-like behavior.\n Viscosity is an effect which depends on the relative velocity of neighboring particles; it reduces the magnitude of the relative velocity"); 114 | group->addSubProperty(property); 115 | 116 | property = variantManager->addProperty(QVariant::Double, "Stiffness"); 117 | property->setValue(mOgreWidget->mFluidDescription.mStiffness); 118 | //property->setAttribute("decimals", 4); 119 | property->setAttribute("minimum", 0.01); 120 | property->setToolTip("Must be positive. The stiffness of the particle interaction related to the pressure.\n\ 121 | This factor linearly scales the force which acts on particles which are closer to each other than the rest spacing.\n\ 122 | Setting this parameter appropriately is crucial for the simulation. The right value depends on many factors such as viscosity,\n\ 123 | damping, and kernelRadiusMultiplier. Values which are too high will result in an unstable simulation, \n\ 124 | whereas too low values will make the fluid appear \"springy\" (the fluid acts more compressible)."); 125 | group->addSubProperty(property); 126 | 127 | property = variantManager->addProperty(QVariant::Double, "Damping"); 128 | property->setValue(mOgreWidget->mFluidDescription.mDamping); 129 | //property->setAttribute("decimals", 4); 130 | property->setAttribute("minimum", 0); 131 | property->setToolTip("must be nonnegative. Reduces the velocity of the particles over time.\nSetting the damping to 0 will leave the particles unaffected."); 132 | group->addSubProperty(property); 133 | 134 | property = variantManager->addProperty(QVariant::Double, "SurfaceTension"); 135 | property->setValue(mOgreWidget->mFluidDescription.mSurfaceTension); 136 | //property->setAttribute("decimals", 4); 137 | property->setAttribute("minimum", 0); 138 | property->setToolTip("Must be nonnegative. Defines an attractive force between particles. \nHigher values will result in smoother surfaces."); 139 | group->addSubProperty(property); 140 | 141 | property = variantManager->addProperty(QVariant::Double, "MotionLimitMultiplier"); 142 | property->setValue(mOgreWidget->mFluidDescription.mMotionLimitMultiplier); 143 | //property->setAttribute("decimals", 4); 144 | property->setAttribute("minimum", 1); 145 | property->setToolTip("Maximal distance a particle is allowed to travel within one timestep. Default value is 3.6 (i.e., 3.0 * kernelRadiusMultiplier). \n\ 146 | The value must not be higher than the product of packetSizeMultiplier and kernelRadiusMultiplier."); 147 | group->addSubProperty(property); 148 | 149 | property = variantManager->addProperty(QtVariantPropertyManager::enumTypeId(), "SimulationMethod"); 150 | QStringList enums; 151 | enums << "SPH" << "Mixed Mode" << "No Particle Interactions"; 152 | property->setAttribute("enumNames", enums); 153 | group->addSubProperty(property); 154 | 155 | //mFlags 156 | property = variantManager->addProperty(QtVariantPropertyManager::flagTypeId(), "Flags"); 157 | QStringList flags; 158 | flags << "Hardware" << "CollisionTwoWay" << "DisableGravity"; 159 | property->setAttribute("flagNames", flags); 160 | property->setValue(1); // TODO: set fluid flags properly? 161 | property->setToolTip("NX_F_MIXED_MODE - alternates between SPH and simple mode (providing more performance than SPH alone, while maintaining some dense characteristics)."); 162 | group->addSubProperty(property); 163 | 164 | 165 | group = groupManager->addProperty("Emitter"); 166 | propertyEditor->addProperty(group); 167 | 168 | //mPose 169 | 170 | property = variantManager->addProperty(QVariant::Double, "ParticleLifetime"); 171 | property->setValue(mOgreWidget->mEmitterDescription.mParticleLifetime); 172 | property->setAttribute("decimals", 4); 173 | property->setAttribute("minimum", 0); 174 | property->setToolTip("in seconds. if 0: particle will live until collides with drain"); 175 | group->addSubProperty(property); 176 | 177 | //mRate 178 | property = variantManager->addProperty(QVariant::Double, "Rate"); 179 | property->setValue(mOgreWidget->mEmitterDescription.mRate); 180 | property->setAttribute("singleStep", 10); 181 | property->setAttribute("minimum", 0); 182 | property->setToolTip("The rate specifies how many particles are emitted per second.\nThe rate is only considered in the simulation if the type is set to NX_FE_CONSTANT_FLOW_RATE."); 183 | group->addSubProperty(property); 184 | 185 | // mType - FlowRate, Pressure 186 | property = variantManager->addProperty(QtVariantPropertyManager::enumTypeId(), "Type"); 187 | enums = QStringList(); 188 | enums << "ConstantFlowRate" << "ConstantPressure"; 189 | property->setAttribute("enumNames", enums); 190 | // TODO: set flag value properly from emitter description? 191 | group->addSubProperty(property); 192 | 193 | property = variantManager->addProperty(QVariant::Double, "FluidSpeed"); 194 | property->setValue(mOgreWidget->mEmitterDescription.mFluidSpeed); 195 | property->setAttribute("minimum", 0); 196 | property->setToolTip("The velocity magnitude of the emitted fluid particles. Default 1.0?"); 197 | group->addSubProperty(property); 198 | 199 | // shape 200 | // dimensionX, dimensionY 201 | // randomAngle 202 | // randomPos 203 | // if frameShape used: flags NX_FEF_FORCE_ON_BODY, NX_FEF_ADD_BODY_VELOCITY 204 | 205 | propertyEditor->setExpanded(fluidGroupItem, true); 206 | //propertyEditor->setExpanded(generalGroupItem, true); 207 | 208 | connect(variantManager, SIGNAL(valueChanged(QtProperty *, const QVariant &)), 209 | this, SLOT(propertyValueChanged(QtProperty *, const QVariant &))); 210 | } 211 | 212 | void ParticleFluids::propertyValueChanged(QtProperty* property, const QVariant & value) { 213 | ui.statusBar->showMessage(QString("%1 %2").arg(property->propertyName()).arg(value.toString())); 214 | 215 | bool shouldRecreate = false; 216 | 217 | QString pName = property->propertyName(); 218 | if (pName == "Simulation Speed") { 219 | mOgreWidget->mSimulationSpeed = value.toFloat(); 220 | } 221 | else if (pName == "MaxParticles") { 222 | mOgreWidget->mFluidDescription.mMaxParticles = value.toUInt(); 223 | shouldRecreate = true; 224 | } 225 | else if (pName == "KernelRadiusMultiplier") { 226 | mOgreWidget->mFluidDescription.mKernelRadiusMultiplier = value.toFloat(); 227 | shouldRecreate = true; 228 | } 229 | else if (pName == "RestParticlesPerMeter") { 230 | mOgreWidget->mFluidDescription.mRestParticlesPerMetre = value.toFloat(); 231 | shouldRecreate = true; 232 | } 233 | else if (pName == "RestDensity") { 234 | mOgreWidget->mFluidDescription.mRestDensity = value.toFloat(); 235 | shouldRecreate = true; 236 | } 237 | else if (pName == "Viscosity") { 238 | mOgreWidget->mFluidDescription.mViscosity = value.toFloat(); 239 | //mOgreWidget->mFluid->setViscosity(mOgreWidget->mFluidDescription.mViscosity); // doesn't change anything in current fluid 240 | shouldRecreate = true; 241 | } 242 | else if (pName == "Stiffness") { 243 | mOgreWidget->mFluidDescription.mStiffness = value.toFloat(); 244 | mOgreWidget->mFluid->setStiffness(mOgreWidget->mFluidDescription.mStiffness); 245 | } 246 | else if (pName == "Damping") { 247 | mOgreWidget->mFluidDescription.mDamping = value.toFloat(); 248 | mOgreWidget->mFluid->setDamping(mOgreWidget->mFluidDescription.mDamping); 249 | } 250 | else if (pName == "SurfaceTension") { 251 | mOgreWidget->mFluidDescription.mSurfaceTension = value.toFloat(); 252 | mOgreWidget->mFluid->setSurfaceTension(mOgreWidget->mFluidDescription.mSurfaceTension); 253 | } 254 | else if (pName == "MotionLimitMultiplier") { 255 | mOgreWidget->mFluidDescription.mMotionLimitMultiplier = value.toFloat(); 256 | shouldRecreate = true; 257 | } 258 | else if (pName == "SimulationMethod") { 259 | int e = value.toInt(); 260 | int converted; 261 | if (e == 0) 262 | converted = NxOgre::Enums::FluidSimulationMethod_SPH; 263 | else if (e == 1) 264 | converted = NxOgre::Enums::FluidSimulationMethod_MixedMode; 265 | else if (e == 2) 266 | converted = NxOgre::Enums::FluidSimulationMethod_NoParticleInteraction; 267 | 268 | mOgreWidget->mFluidDescription.mSimulationMethod = converted; 269 | mOgreWidget->mFluid->setSimulationMethod(converted); 270 | } 271 | // Flags 272 | else if (pName == "Hardware") { 273 | mOgreWidget->mFluidDescription.mFlags ^= NxOgre::Enums::FluidFlags_Hardware; 274 | //mOgreWidget->mFluid->setFlag(NxOgre::Enums::FluidFlags_Hardware, value.toBool()); // doesn't change anything in current fluid 275 | shouldRecreate = true; 276 | } 277 | else if (pName == "CollisionTwoWay") { // TODO!: test CollisionTwoWay flag 278 | mOgreWidget->mFluidDescription.mFlags ^= NxOgre::Enums::FluidFlags_CollisionTwoWay; 279 | mOgreWidget->mFluid->setFlag(NxOgre::Enums::FluidFlags_CollisionTwoWay, value.toBool()); 280 | } 281 | else if (pName == "DisableGravity") { 282 | mOgreWidget->mFluidDescription.mFlags ^= NxOgre::Enums::FluidFlags_DisableGravity; 283 | mOgreWidget->mFluid->setFlag(NxOgre::Enums::FluidFlags_DisableGravity, value.toBool()); 284 | } 285 | else if (pName == "ParticleLifetime") { 286 | mOgreWidget->mEmitterDescription.mParticleLifetime = value.toFloat(); 287 | mOgreWidget->mEmitter->setParticleLifetime(value.toFloat()); 288 | } 289 | // Now Emitter parameters 290 | else if (pName == "Rate") { 291 | mOgreWidget->mEmitterDescription.mRate = value.toFloat(); 292 | mOgreWidget->mEmitter->setRate(value.toFloat()); 293 | } 294 | else if (pName == "Type") { 295 | if (value.toInt() == 0) 296 | mOgreWidget->mEmitterDescription.mType = NxOgre::Enums::FluidEmitterType_FlowRate; 297 | else if (value.toInt() == 1) 298 | mOgreWidget->mEmitterDescription.mType = NxOgre::Enums::FluidEmitterType_Pressure; 299 | 300 | shouldRecreate = true; 301 | } 302 | else if (pName == "FluidSpeed") { 303 | mOgreWidget->mEmitterDescription.mFluidSpeed = value.toFloat(); 304 | mOgreWidget->mEmitter->setFluidSpeed(value.toFloat()); 305 | } 306 | 307 | if (shouldRecreate) 308 | mOgreWidget->createFluid(); 309 | } -------------------------------------------------------------------------------- /ResourceGroupHelper.cpp: -------------------------------------------------------------------------------- 1 | // taken from http://www.ogre3d.org/forums/viewtopic.php?f=5&t=46787&start=25#p329272 2 | #include "stdafx.h" 3 | #include "ResourceGroupHelper.h" 4 | #include "OgreResourceGroupManager.h" 5 | #include "OgreLogManager.h" 6 | #include "OgreRoot.h" 7 | #include "OgreMovableObject.h" 8 | #include "OgreMaterialManager.h" 9 | #include "OgreEntity.h" 10 | #include "OgreSubEntity.h" 11 | #include "OgreBillBoardChain.h" 12 | #include "OgreBillBoardSet.h" 13 | #include "OgreOverlayElement.h" 14 | #include "OgreOverlay.h" 15 | #include "OgreOverlayManager.h" 16 | #include "OgreOverlayContainer.h" 17 | #include "OgreException.h" 18 | 19 | ResourceGroupHelper::UpdateMaterialRenderableVisitor::UpdateMaterialRenderableVisitor(): 20 | Ogre::Renderable::Visitor() 21 | { 22 | } 23 | 24 | void ResourceGroupHelper::UpdateMaterialRenderableVisitor::visit( 25 | Ogre::Renderable *rend, Ogre::ushort lodIndex, bool isDebug, Ogre::Any *pAny) 26 | { 27 | const Ogre::MaterialPtr mat = rend->getMaterial(); 28 | if(!mat.isNull()) 29 | { 30 | std::string newMatName = mat->getName(); 31 | Ogre::MaterialPtr newMat = Ogre::MaterialManager::getSingleton().getByName(newMatName); 32 | if(newMat.isNull()) 33 | { 34 | // this can happen if there was error during the reloading of the material. 35 | // in that case, we keep the ancient one. 36 | // Ogre::LogManager::getSingleton().logMessage(newMatName+" : new material is null!"); 37 | return; 38 | } 39 | 40 | // unfortunately, the renderable gives access only to a const MaterialPtr. 41 | // and there is no 'setMaterial' or 'setMaterialName' method on renderables. 42 | // so I have to try to down cast with known classes... 43 | { 44 | Ogre::SubEntity* lRend = dynamic_cast(rend); 45 | if(lRend){lRend->setMaterialName(newMatName);return;} 46 | } 47 | { 48 | Ogre::SimpleRenderable* lRend = dynamic_cast(rend); 49 | if(lRend){lRend->setMaterial(newMatName);return;} 50 | } 51 | { 52 | Ogre::ShadowRenderable* lRend = dynamic_cast(rend); 53 | if(lRend){lRend->setMaterial(newMat);return;} 54 | } 55 | { 56 | Ogre::BillboardChain* lRend = dynamic_cast(rend); 57 | if(lRend){lRend->setMaterialName(newMatName);return;} 58 | } 59 | { 60 | Ogre::BillboardSet* lRend = dynamic_cast(rend); 61 | if(lRend){lRend->setMaterialName(newMatName);return;} 62 | } 63 | { 64 | Ogre::OverlayElement* lRend = dynamic_cast(rend); 65 | if(lRend){lRend->setMaterialName(newMatName);return;} 66 | } 67 | }else{ 68 | // was there for debug... 69 | //Ogre::LogManager::getSingleton().logMessage("material of renderable is null!"); 70 | } 71 | } 72 | 73 | ResourceGroupHelper::ResourceGroupHelperLogListener::ResourceGroupHelperLogListener(): 74 | Ogre::LogListener(),mKeptMessages() 75 | { 76 | Ogre::LogManager* logMgr = Ogre::LogManager::getSingletonPtr(); 77 | if(logMgr) 78 | { 79 | bool logExist = true; 80 | try{logMgr->getDefaultLog();}catch(Ogre::Exception&) 81 | { 82 | logExist = false; 83 | } 84 | if(logExist) 85 | { 86 | logMgr->getDefaultLog()->addListener(this); 87 | } 88 | } 89 | } 90 | 91 | ResourceGroupHelper::ResourceGroupHelperLogListener::~ResourceGroupHelperLogListener() 92 | { 93 | Ogre::LogManager* logMgr = Ogre::LogManager::getSingletonPtr(); 94 | if(logMgr) 95 | { 96 | bool logExist = true; 97 | try{logMgr->getDefaultLog();}catch(Ogre::Exception&) 98 | { 99 | logExist = false; 100 | } 101 | if(logExist) 102 | { 103 | logMgr->getDefaultLog()->removeListener(this); 104 | } 105 | } 106 | } 107 | 108 | bool ResourceGroupHelper::ResourceGroupHelperLogListener::areMessagesKept() 109 | { 110 | return mKeptMessages.peek()==EOF; 111 | } 112 | 113 | std::string ResourceGroupHelper::ResourceGroupHelperLogListener::getKeptMessages() 114 | { 115 | return mKeptMessages.str(); 116 | } 117 | 118 | void ResourceGroupHelper::ResourceGroupHelperLogListener::clearKeptMessages() 119 | { 120 | mKeptMessages.str(std::string()); 121 | } 122 | 123 | void ResourceGroupHelper::ResourceGroupHelperLogListener::messageLogged 124 | (const Ogre::String &message, Ogre::LogMessageLevel lml, bool maskDebug, const Ogre::String &logName) 125 | { 126 | Ogre::String copy = message; 127 | Ogre::StringUtil::toLowerCase(copy); 128 | Ogre::String pattern1 = "*error*"; 129 | Ogre::String pattern2 = "*exception*"; 130 | bool lErrorfound = Ogre::StringUtil::match(message,pattern1,true) || Ogre::StringUtil::match(message,pattern2,true); 131 | if(lErrorfound) 132 | { 133 | mKeptMessages< ResourceGroupHelper::getAllPathAndTypesNames(const std::string& pResourceGroupName) 159 | { 160 | // note : unfortunately no access to the order in which path where loaded 161 | Ogre::FileInfoListPtr fli_dirs = Ogre::ResourceGroupManager::getSingleton().listResourceFileInfo(pResourceGroupName,true); 162 | 163 | std::vector lDirectoryInfos; 164 | 165 | if(!fli_dirs.isNull()) 166 | { 167 | Ogre::FileInfoList::iterator itFliD = fli_dirs->begin(); 168 | Ogre::FileInfoList::iterator itFliDEnd = fli_dirs->end(); 169 | for(; itFliD!=itFliDEnd;itFliD++) 170 | { 171 | Ogre::FileInfo& lFinfoD = (*itFliD); 172 | if(lFinfoD.archive) 173 | { 174 | ResourceGroupHelper::ArchivePathAndType arch; 175 | arch.first = lFinfoD.path + lFinfoD.archive->getName(); 176 | arch.second = lFinfoD.archive->getType(); 177 | lDirectoryInfos.push_back(arch); 178 | } 179 | } 180 | } 181 | return lDirectoryInfos; 182 | } 183 | 184 | 185 | 186 | bool ResourceGroupHelper::reloadAResourceGroup(const std::string& pResourceGroupName,const std::vector& pLocationToAdd) 187 | { 188 | if(!resourceGroupExist(pResourceGroupName)) 189 | { 190 | // not present. something wrong. 191 | return false; 192 | } 193 | 194 | Ogre::ResourceGroupManager& resGroupMgr = Ogre::ResourceGroupManager::getSingleton(); 195 | resGroupMgr.destroyResourceGroup(pResourceGroupName); 196 | 197 | if(resourceGroupExist(pResourceGroupName)) 198 | { 199 | // still present. something wrong. 200 | return false; 201 | } 202 | 203 | resGroupMgr.createResourceGroup(pResourceGroupName); 204 | 205 | std::vector::const_iterator iterLoc= pLocationToAdd.begin(); 206 | std::vector::const_iterator iterLocEnd= pLocationToAdd.end(); 207 | for(;iterLoc!=iterLocEnd;iterLoc++) 208 | { 209 | // add the location in the resourceGroup 210 | resGroupMgr.addResourceLocation(iterLoc->first,iterLoc->second,pResourceGroupName,false); 211 | } 212 | resGroupMgr.initialiseResourceGroup(pResourceGroupName); 213 | return true; 214 | } 215 | 216 | 217 | 218 | bool ResourceGroupHelper::reloadAResourceGroupWithoutDestroyingIt(const std::string& pResourceGroupName) 219 | { 220 | //try { 221 | if(!resourceGroupExist(pResourceGroupName)) 222 | { 223 | // not present. something wrong. 224 | return false; 225 | } 226 | Ogre::ResourceGroupManager& resGroupMgr = Ogre::ResourceGroupManager::getSingleton(); 227 | resGroupMgr.clearResourceGroup(pResourceGroupName); 228 | resGroupMgr.initialiseResourceGroup(pResourceGroupName); 229 | //} 230 | //catch (Ogre::InvalidParametersException e) { 231 | // std::cout << e.getDescription(); 232 | //} 233 | 234 | return true; 235 | } 236 | 237 | 238 | bool ResourceGroupHelper::resourceGroupExist(const std::string& pResourceGroupName) 239 | { 240 | bool lIsPresent = false; 241 | Ogre::ResourceGroupManager& resGroupMgr = Ogre::ResourceGroupManager::getSingleton(); 242 | Ogre::StringVector lAllResourceGroups = resGroupMgr.getResourceGroups(); 243 | Ogre::StringVector::iterator iter = lAllResourceGroups.begin(); 244 | Ogre::StringVector::iterator iterEnd = lAllResourceGroups.end(); 245 | for(;iter!=iterEnd;iter++) 246 | { 247 | if((*iter) == pResourceGroupName) 248 | { 249 | lIsPresent = true; 250 | } 251 | } 252 | return lIsPresent; 253 | } 254 | 255 | 256 | void ResourceGroupHelper::updateOnEveryRenderable() 257 | { 258 | 259 | //1/ get all the available object type (entity, light, user defined types ...) 260 | std::vector allAvailableTypes; 261 | Ogre::Root::MovableObjectFactoryIterator iterFactory = Ogre::Root::getSingleton().getMovableObjectFactoryIterator(); 262 | for(;iterFactory.hasMoreElements();) 263 | { 264 | Ogre::MovableObjectFactory* factory = iterFactory.getNext(); 265 | allAvailableTypes.push_back(factory->getType()); 266 | } 267 | 268 | UpdateMaterialRenderableVisitor lRenderableVisitor; 269 | 270 | //2/ for each scene manager, lets visit renderables! 271 | // unfortunately that does not cover all renderables type... (overlays...) 272 | Ogre::SceneManagerEnumerator::SceneManagerIterator iterSceneManager = Ogre::Root::getSingleton().getSceneManagerIterator(); 273 | for(;iterSceneManager.hasMoreElements();) 274 | { 275 | Ogre::SceneManager * scMgr = iterSceneManager.getNext(); 276 | 277 | std::vector::iterator iterMovableType = allAvailableTypes.begin(); 278 | std::vector::iterator iterMovableTypeEnd = allAvailableTypes.end(); 279 | for(;iterMovableType!=iterMovableTypeEnd;iterMovableType++) 280 | { 281 | Ogre::SceneManager::MovableObjectIterator iterMovable = scMgr->getMovableObjectIterator(*iterMovableType); 282 | for(;iterMovable.hasMoreElements();) 283 | { 284 | Ogre::MovableObject * movable = iterMovable.getNext(); 285 | movable->visitRenderables(&lRenderableVisitor,false); 286 | } 287 | } 288 | } 289 | 290 | // 3 / visit overlays! 291 | { 292 | Ogre::OverlayManager::OverlayMapIterator iterOverlay = Ogre::OverlayManager::getSingleton().getOverlayIterator(); 293 | for(;iterOverlay.hasMoreElements();) 294 | { 295 | Ogre::Overlay* lOverlay = iterOverlay.getNext(); 296 | // get the first level of OverlayContainer in the Overlay 297 | Ogre::Overlay::Overlay2DElementsIterator iterOverlayElem = lOverlay->get2DElementsIterator(); 298 | for(;iterOverlayElem.hasMoreElements();) 299 | { 300 | Ogre::OverlayContainer * lOverlayCont = iterOverlayElem.getNext(); 301 | visitRecursivelyRenderablesFrom(lOverlayCont,lRenderableVisitor, false); 302 | } 303 | } 304 | } 305 | } 306 | 307 | 308 | void ResourceGroupHelper::visitRecursivelyRenderablesFrom(Ogre::OverlayContainer* pOverlayContainer, Ogre::Renderable::Visitor& pVisitor, bool debugRenderable) 309 | { 310 | // call on 'this' 311 | pOverlayContainer->visitRenderables(&pVisitor,false); 312 | 313 | // call on 'leaf' (cf composite pattern) 314 | { 315 | Ogre::OverlayContainer::ChildIterator childIter = pOverlayContainer->getChildIterator(); 316 | for(;childIter.hasMoreElements();) 317 | { 318 | Ogre::OverlayElement* lOverElem = childIter.getNext(); 319 | lOverElem->visitRenderables(&pVisitor,false); 320 | } 321 | } 322 | 323 | // call on 'not-leaf' (cf composite pattern) 324 | { 325 | Ogre::OverlayContainer::ChildContainerIterator childContainerIter = pOverlayContainer->getChildContainerIterator(); 326 | for(;childContainerIter.hasMoreElements();) 327 | { 328 | Ogre::OverlayContainer * childContainer = childContainerIter.getNext(); 329 | visitRecursivelyRenderablesFrom(childContainer, pVisitor,debugRenderable); 330 | } 331 | } 332 | } 333 | 334 | time_t ResourceGroupHelper::getLatestModificationTime(const std::string& pResourceGroupName) 335 | { 336 | time_t result(0); 337 | 338 | Ogre::ResourceGroupManager& rgMgr = Ogre::ResourceGroupManager::getSingleton(); 339 | Ogre::FileInfoListPtr fli_files = rgMgr.listResourceFileInfo(pResourceGroupName,false); 340 | if(fli_files.isNull()) 341 | { 342 | // something went wrong (example : no files)! 343 | return result; 344 | } 345 | 346 | // for each file, we check the modification date. 347 | // we keep the latest one. 348 | Ogre::FileInfoList::iterator iterFiles = fli_files->begin(); 349 | Ogre::FileInfoList::iterator iterFilesEnd = fli_files->end(); 350 | for(;iterFiles!=iterFilesEnd;iterFiles++) 351 | { 352 | Ogre::FileInfo& file = *iterFiles; 353 | if(file.archive) 354 | { 355 | time_t modifTime = file.archive->getModifiedTime(file.filename); 356 | if(result < modifTime) 357 | { 358 | result = modifTime; 359 | } 360 | } 361 | } 362 | return result; 363 | } 364 | 365 | //bool ResourceGroupHelper::filesChanged(const std::string& pResourceGroupName) { 366 | // time_t lastModificationTime = getLatestModificationTime(pResourceGroupName); 367 | // 368 | // std::map::iterator iterInfoTime = mRessourceGroupModificationTimes.find(pResourceGroupName); 369 | // if(iterInfoTime!=mRessourceGroupModificationTimes.end() && (iterInfoTime->second < lastModificationTime)) 370 | // return true; 371 | // 372 | // return false; 373 | //} 374 | 375 | bool ResourceGroupHelper::checkTimeAndReloadIfNeeded(const std::string& pResourceGroupName, std::string &pOutLoggedMessages, bool useLog) 376 | { 377 | bool result = false; 378 | 379 | // 1/ get last modification time. 380 | time_t lastModificationTime = getLatestModificationTime(pResourceGroupName); 381 | 382 | std::map::iterator iterInfoTime = mRessourceGroupModificationTimes.find(pResourceGroupName); 383 | if(iterInfoTime!=mRessourceGroupModificationTimes.end()) 384 | { 385 | if(iterInfoTime->second < lastModificationTime) 386 | { 387 | // update the value 388 | iterInfoTime->second = lastModificationTime; 389 | 390 | Ogre::LogManager::getSingleton().logMessage("----- Reloading materials -----"); 391 | // use log if needed 392 | if(useLog) 393 | { 394 | // constructor register itself, and destructor unregister itself 395 | ResourceGroupHelperLogListener lLogListener; 396 | // try to reload 397 | reloadAResourceGroupWithoutDestroyingIt(pResourceGroupName); 398 | pOutLoggedMessages = lLogListener.getKeptMessages(); 399 | }else{ 400 | // try to reload 401 | reloadAResourceGroupWithoutDestroyingIt(pResourceGroupName); 402 | } 403 | 404 | // update the material of reachable renderables 405 | updateOnEveryRenderable(); 406 | 407 | result = true; 408 | } 409 | }else{ 410 | mRessourceGroupModificationTimes[pResourceGroupName] = lastModificationTime; 411 | } 412 | return result; 413 | } -------------------------------------------------------------------------------- /ParticleFluids.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 25 | 28 | 31 | 34 | 37 | 40 | 52 | 55 | 58 | 61 | 69 | 72 | 75 | 78 | 81 | 84 | 87 | 90 | 91 | 97 | 100 | 103 | 106 | 109 | 112 | 125 | 128 | 131 | 134 | 142 | 145 | 148 | 151 | 154 | 157 | 160 | 163 | 164 | 165 | 166 | 167 | 168 | 173 | 176 | 177 | 180 | 181 | 184 | 185 | 188 | 189 | 192 | 195 | 199 | 200 | 203 | 207 | 208 | 209 | 210 | 215 | 218 | 221 | 228 | 229 | 232 | 239 | 240 | 241 | 244 | 247 | 254 | 255 | 258 | 265 | 266 | 267 | 270 | 271 | 274 | 275 | 278 | 279 | 280 | 285 | 288 | 291 | 298 | 299 | 302 | 309 | 310 | 311 | 312 | 318 | 321 | 324 | 331 | 332 | 335 | 342 | 343 | 344 | 345 | 351 | 354 | 357 | 361 | 362 | 365 | 369 | 370 | 371 | 374 | 375 | 380 | 383 | 387 | 390 | 391 | 392 | 395 | 399 | 402 | 403 | 404 | 405 | 410 | 413 | 417 | 420 | 421 | 422 | 425 | 429 | 432 | 433 | 434 | 435 | 436 | 439 | 442 | 443 | 446 | 447 | 450 | 451 | 452 | 453 | 454 | 458 | 462 | 466 | 470 | 474 | 478 | 479 | 480 | -------------------------------------------------------------------------------- /ParticleFluids.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Template 14 | Win32 15 | 16 | 17 | 18 | {52813862-2D9D-4556-8E97-53445EF3051B} 19 | ParticleFluids 20 | Qt4VSv1.0 21 | 22 | 23 | 24 | Application 25 | 26 | 27 | Application 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | <_ProjectFileVersion>10.0.40219.1 41 | bin\$(Configuration)\ 42 | obj\$(Configuration)\ 43 | bin\$(Configuration)\ 44 | obj\$(Configuration)\ 45 | AllRules.ruleset 46 | 47 | 48 | AllRules.ruleset 49 | 50 | 51 | AllRules.ruleset 52 | 53 | 54 | 55 | 56 | 57 | .\GeneratedFiles;$(QTDIR)\include;.\GeneratedFiles\$(Configuration);$(QTDIR)\include\qtmain;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;.\;$(OGRE_SRC)\include\;$(OGRE_SRC)\include\OGRE;$(OGRE_SRC)\Dependencies\include\;.\Dependencies\NxOgre\sdk;.\Dependencies\Critter\sdk;.\Dependencies\qtpropertybrowser\src;%(AdditionalIncludeDirectories) 58 | UNICODE;WIN32;QT_LARGEFILE_SUPPORT;QT_THREAD_SUPPORT;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;QT_GUI_LIB;QT_DLL;%(PreprocessorDefinitions) 59 | MultiThreadedDLL 60 | false 61 | Use 62 | StdAfx.h 63 | $(IntDir)$(TargetName).pch 64 | 65 | 66 | true 67 | 68 | 69 | qtmain.lib;QtCore4.lib;QtGui4.lib;OgreMain.lib;OIS.lib;NxOgre.lib;CritterStatic.lib;QtSolutions_PropertyBrowser-head.lib;%(AdditionalDependencies) 70 | bin\$(Configuration)\$(ProjectName).exe 71 | $(QTDIR)\lib;$(OGRE_SRC)\lib\release;$(OGRE_SRC)\Dependencies\lib\Release;.\Dependencies\NxOgre\sdk;.\Dependencies\Critter\sdk;.\Dependencies\qtpropertybrowser\lib;%(AdditionalLibraryDirectories) 72 | false 73 | Windows 74 | 75 | 76 | 77 | 78 | Disabled 79 | .\GeneratedFiles;$(QTDIR)\include;.\GeneratedFiles\$(Configuration);$(QTDIR)\include\qtmain;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;.\;$(OGRE_SRC)\include\;$(OGRE_SRC)\include\OGRE;$(OGRE_SRC)\Dependencies\include\;.\Dependencies\NxOgre\sdk;.\Dependencies\Critter\sdk;.\Dependencies\qtpropertybrowser\src;%(AdditionalIncludeDirectories) 80 | UNICODE;WIN32;QT_LARGEFILE_SUPPORT;QT_THREAD_SUPPORT;QT_CORE_LIB;QT_GUI_LIB;QT_DLL;%(PreprocessorDefinitions) 81 | MultiThreadedDebugDLL 82 | false 83 | Use 84 | StdAfx.h 85 | $(IntDir)$(TargetName).pch 86 | ProgramDatabase 87 | true 88 | 89 | 90 | qtmaind.lib;QtCored4.lib;QtGuid4.lib;OgreMain_d.lib;OIS_d.lib;NxOgreDebug.lib;CritterDebugStatic.lib;QtSolutions_PropertyBrowser-headd.lib;%(AdditionalDependencies) 91 | bin\$(Configuration)\$(ProjectName).exe 92 | $(QTDIR)\lib;$(OGRE_SRC)\lib\debug;$(OGRE_SRC)\Dependencies\lib\Debug;.\Dependencies\NxOgre\sdk;.\Dependencies\Critter\sdk;.\Dependencies\qtpropertybrowser\lib;%(AdditionalLibraryDirectories) 93 | true 94 | Windows 95 | 96 | 97 | 98 | 99 | true 100 | .\GeneratedFiles;$(QTDIR)\include;.\GeneratedFiles\$(Configuration);$(QTDIR)\include\qtmain;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;.\;$(OGRE_SRC)\include\;$(OGRE_SRC)\include\OGRE;$(OGRE_SRC)\Dependencies\include\;.\Dependencies\NxOgre\sdk;.\Dependencies\Critter\sdk;.\Dependencies\qtpropertybrowser\src;%(AdditionalIncludeDirectories) 101 | QT_DLL;%(PreprocessorDefinitions) 102 | 103 | 104 | %(AdditionalDependencies) 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | Create 114 | Create 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | true 124 | true 125 | 126 | 127 | true 128 | true 129 | 130 | 131 | true 132 | true 133 | 134 | 135 | true 136 | true 137 | 138 | 139 | 140 | 141 | Moc%27ing %(Filename)%(Extension)... 142 | "$(QTDIR)\bin\moc.exe" -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_THREAD_SUPPORT -DQT_CORE_LIB -DQT_GUI_LIB -DQT_DLL "-I." "-I.\GeneratedFiles" "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(Configuration)\." "-I$(QTDIR)\include\qtmain" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I." "-I$(OGRE_SRC)\include" "-I$(OGRE_SRC)\include\OGRE" "-I$(OGRE_SRC)\Dependencies\include" "-I.\Dependencies\NxOgre\sdk" "-I.\Dependencies\Critter\sdk" "-I.\Dependencies\qtpropertybrowser\src" "-I." "-I." "-I." "OgreWidget.h" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fStdAfx.h" "-f..\..\OgreWidget.h" 143 | $(QTDIR)\bin\moc.exe;%(FullPath);%(AdditionalInputs) 144 | .\GeneratedFiles\$(Configuration)\moc_%(Filename).cpp;%(Outputs) 145 | Moc%27ing %(Filename)%(Extension)... 146 | "$(QTDIR)\bin\moc.exe" -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_THREAD_SUPPORT -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_DLL "-I." "-I.\GeneratedFiles" "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(Configuration)\." "-I$(QTDIR)\include\qtmain" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I." "-I$(OGRE_SRC)\include" "-I$(OGRE_SRC)\include\OGRE" "-I$(OGRE_SRC)\Dependencies\include" "-I.\Dependencies\NxOgre\sdk" "-I.\Dependencies\Critter\sdk" "-I.\Dependencies\qtpropertybrowser\src" "-I." "-I." "-I." "OgreWidget.h" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fStdAfx.h" "-f..\..\OgreWidget.h" 147 | $(QTDIR)\bin\moc.exe;%(FullPath);%(AdditionalInputs) 148 | .\GeneratedFiles\$(Configuration)\moc_%(Filename).cpp;%(Outputs) 149 | 150 | 151 | Moc%27ing %(Filename)%(Extension)... 152 | "$(QTDIR)\bin\moc.exe" -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_THREAD_SUPPORT -DQT_CORE_LIB -DQT_GUI_LIB -DQT_DLL "-I." "-I.\GeneratedFiles" "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(Configuration)\." "-I$(QTDIR)\include\qtmain" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I." "-I$(OGRE_SRC)\include" "-I$(OGRE_SRC)\include\OGRE" "-I$(OGRE_SRC)\Dependencies\include" "-I.\Dependencies\NxOgre\sdk" "-I.\Dependencies\Critter\sdk" "-I.\Dependencies\qtpropertybrowser\src" "-I." "-I." "-I." "particlefluids.h" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fStdAfx.h" "-f..\..\particlefluids.h" 153 | $(QTDIR)\bin\moc.exe;%(FullPath);%(AdditionalInputs) 154 | .\GeneratedFiles\$(Configuration)\moc_%(Filename).cpp;%(Outputs) 155 | Moc%27ing %(Filename)%(Extension)... 156 | "$(QTDIR)\bin\moc.exe" -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_THREAD_SUPPORT -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_DLL "-I." "-I.\GeneratedFiles" "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(Configuration)\." "-I$(QTDIR)\include\qtmain" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I." "-I$(OGRE_SRC)\include" "-I$(OGRE_SRC)\include\OGRE" "-I$(OGRE_SRC)\Dependencies\include" "-I.\Dependencies\NxOgre\sdk" "-I.\Dependencies\Critter\sdk" "-I.\Dependencies\qtpropertybrowser\src" "-I." "-I." "-I." "particlefluids.h" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fStdAfx.h" "-f..\..\particlefluids.h" 157 | $(QTDIR)\bin\moc.exe;%(FullPath);%(AdditionalInputs) 158 | .\GeneratedFiles\$(Configuration)\moc_%(Filename).cpp;%(Outputs) 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | Uic%27ing %(Filename)%(Extension)... 169 | "$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)" 170 | 171 | $(QTDIR)\bin\uic.exe;%(AdditionalInputs) 172 | .\GeneratedFiles\ui_%(Filename).h;%(Outputs) 173 | Uic%27ing %(Filename)%(Extension)... 174 | "$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)" 175 | 176 | $(QTDIR)\bin\uic.exe;%(AdditionalInputs) 177 | .\GeneratedFiles\ui_%(Filename).h;%(Outputs) 178 | 179 | 180 | Rcc%27ing %(Filename)%(Extension)... 181 | "$(QTDIR)\bin\rcc.exe" -name "%(Filename)" -no-compress "%(FullPath)" -o .\GeneratedFiles\qrc_%(Filename).cpp 182 | 183 | %(FullPath);%(AdditionalInputs) 184 | .\GeneratedFiles\qrc_%(Filename).cpp;%(Outputs) 185 | Rcc%27ing %(Filename)%(Extension)... 186 | "$(QTDIR)\bin\rcc.exe" -name "%(Filename)" -no-compress "%(FullPath)" -o .\GeneratedFiles\qrc_%(Filename).cpp 187 | 188 | %(FullPath);%(AdditionalInputs) 189 | .\GeneratedFiles\qrc_%(Filename).cpp;%(Outputs) 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | -------------------------------------------------------------------------------- /OgreWidget.cpp: -------------------------------------------------------------------------------- 1 | // base OgreWidget functionality from http://www.ogre3d.org/forums/viewtopic.php?p=367010&sid=5f3feeed878d9121b62dec0d82e7d19e#p367010 (orginally from Ogitor) 2 | #include "stdafx.h" 3 | #include "ogrewidget.h" 4 | #include "particlefluids.h" 5 | #include "ResourceGroupHelper.h" 6 | 7 | #include 8 | 9 | using namespace Ogre; 10 | 11 | const QPoint OgreWidget::invalidMousePoint(-1,-1); 12 | const Ogre::Real OgreWidget::turboModifier(10); 13 | 14 | OgreWidget::OgreWidget(QWidget *parent) 15 | :QWidget(parent), 16 | mRoot(0), mSceneMgr(0), mRenderWindow(0), mViewport(0), 17 | mCamera(0), oldPos(invalidMousePoint), selectedNode(0), mFluid(0), mSimulationSpeed(1), mResourceGroupHelper(new ResourceGroupHelper()) 18 | { 19 | setAttribute(Qt::WA_OpaquePaintEvent); 20 | setAttribute(Qt::WA_PaintOnScreen); 21 | setMinimumSize(240,240); 22 | setFocusPolicy(Qt::ClickFocus); 23 | 24 | // initial fluid parameters 25 | mFluidDescription.mMaxParticles = 60000; 26 | mFluidDescription.mKernelRadiusMultiplier = 2.0f; 27 | mFluidDescription.mRestParticlesPerMetre = 7.0f; 28 | mFluidDescription.mRestDensity = 1000.0f; 29 | mFluidDescription.mViscosity = 40.0f; 30 | mFluidDescription.mStiffness = 50.0f; 31 | mFluidDescription.mDamping = 0; // nonnegative 32 | mFluidDescription.mSurfaceTension = 0; 33 | mFluidDescription.mMotionLimitMultiplier = 3.0f; 34 | mFluidDescription.mPacketSizeMultiplier = 8; 35 | mFluidDescription.mCollisionDistanceMultiplier = 0.12f; 36 | mFluidDescription.mSimulationMethod = NxOgre::Enums::FluidSimulationMethod_SPH; 37 | mFluidDescription.mFlags |= NxOgre::Enums::FluidFlags_Hardware; // FluidFlags_CollisionTwoWay NxOgre::Enums::FluidFlags_DisableGravity 38 | mFluidDescription.mFlags ^= NxOgre::Enums::FluidFlags_Visualisation; 39 | //mFluidDescription.mExternalAcceleration.set(0,-9.81, 0); 40 | 41 | mEmitterDescription.mPose.set(0, 8, -3); 42 | mEmitterDescription.mDimensionX = 0.6; // TODO: make mEmitterDescription.mDimensionX/Y GUI-accessible? 43 | mEmitterDescription.mDimensionY = 0.6; 44 | mEmitterDescription.mParticleLifetime = 0; 45 | mEmitterDescription.mRate = 500; 46 | mEmitterDescription.mFluidSpeed = 3.5; 47 | mEmitterDescription.mType = NxOgre::Enums::FluidEmitterType_FlowRate;// NxOgre::Enums::FluidEmitterType_FlowRate FluidEmitterType_Pressure 48 | mEmitterDescription.mShape = NxOgre::Enums::FluidEmitterShape_Ellipse; 49 | mEmitterDescription.mRandomAngle = 0.25f; 50 | mEmitterDescription.mRandomPosition.set(0.25f, 0.25f, 0.25f); 51 | mEmitterDescription.mReplusionCoefficient = 0.02f; 52 | //edesc.mReplusionCoefficient = 0.8f; --> from other code snippet 53 | //edesc.mDimensionX = 4.0f; 54 | //edesc.mDimensionY = 4.0f; 55 | } 56 | 57 | OgreWidget::~OgreWidget() 58 | { 59 | if(mRenderWindow) 60 | { 61 | mRenderWindow->removeAllViewports(); 62 | } 63 | 64 | if(mRoot) 65 | { 66 | mRoot->detachRenderTarget(mRenderWindow); 67 | 68 | if(mSceneMgr) 69 | { 70 | mRoot->destroySceneManager(mSceneMgr); 71 | } 72 | } 73 | 74 | delete mRoot; 75 | } 76 | 77 | void OgreWidget::setBackgroundColor(QColor c) 78 | { 79 | if(mViewport) 80 | { 81 | Ogre::ColourValue ogreColour; 82 | ogreColour.setAsARGB(c.rgba()); 83 | mViewport->setBackgroundColour(ogreColour); 84 | } 85 | } 86 | 87 | //void OgreWidget::setCameraPosition(const Ogre::Vector3 &pos) 88 | //{ 89 | // mCamera->setPosition(pos); 90 | // //mCamera->lookAt(0,50,0); 91 | // //update(); 92 | // //emit cameraPositionChanged(pos); 93 | //} 94 | 95 | void OgreWidget::keyPressEvent(QKeyEvent *e) 96 | { 97 | // TODO?: camera moving speed? 98 | static QMap keyCoordModificationMapping; 99 | static bool mappingInitialised = false; 100 | 101 | if(!mappingInitialised) 102 | { 103 | keyCoordModificationMapping[Qt::Key_W] = Ogre::Vector3( 0, 0,-1); 104 | keyCoordModificationMapping[Qt::Key_S] = Ogre::Vector3( 0, 0, 1); 105 | keyCoordModificationMapping[Qt::Key_A] = Ogre::Vector3(-1, 0, 0); 106 | keyCoordModificationMapping[Qt::Key_D] = Ogre::Vector3( 1, 0, 0); 107 | keyCoordModificationMapping[Qt::Key_E] = Ogre::Vector3( 0, 1, 0); 108 | keyCoordModificationMapping[Qt::Key_Q] = Ogre::Vector3( 0,-1, 0); 109 | 110 | mappingInitialised = true; 111 | } 112 | 113 | QMap::iterator keyPressed = 114 | keyCoordModificationMapping.find(e->key()); 115 | if(keyPressed != keyCoordModificationMapping.end() && mCamera) 116 | { 117 | float scale = (e->modifiers() & Qt::ShiftModifier) ? 0.05 : 0.25; 118 | //const Ogre::Vector3 &actualCamPos = mCamera->getPosition(); 119 | //setCameraPosition(actualCamPos + keyPressed.value()); 120 | mCamera->moveRelative(keyPressed.value() * scale); 121 | 122 | e->accept(); 123 | } 124 | else if (e->key() == Qt::Key_P) { 125 | // TODO: visual debugger: Button in Toolbar 126 | static bool visualDebuggerOn = false; 127 | if (!visualDebuggerOn) 128 | mVisualDebugger->enable(); 129 | else 130 | mVisualDebugger->disable(); 131 | visualDebuggerOn = !visualDebuggerOn; 132 | } 133 | else 134 | { 135 | e->ignore(); 136 | } 137 | } 138 | 139 | void OgreWidget::mouseDoubleClickEvent(QMouseEvent *e) 140 | { 141 | if(e->buttons().testFlag(Qt::LeftButton)) 142 | { 143 | // TODO: raytest: show pos in status bar instead showing bb 144 | Ogre::Real x = e->pos().x() / (float)width(); 145 | Ogre::Real y = e->pos().y() / (float)height(); 146 | 147 | Ogre::Ray ray = mCamera->getCameraToViewportRay(x, y); 148 | Ogre::RaySceneQuery *query = mSceneMgr->createRayQuery(ray); 149 | Ogre::RaySceneQueryResult &queryResult = query->execute(); 150 | Ogre::RaySceneQueryResult::iterator queryResultIterator = queryResult.begin(); 151 | 152 | if(queryResultIterator != queryResult.end()) 153 | { 154 | if(queryResultIterator->movable) 155 | { 156 | selectedNode = queryResultIterator->movable->getParentSceneNode(); 157 | selectedNode->showBoundingBox(true); 158 | } 159 | } 160 | else 161 | { 162 | selectedNode->showBoundingBox(false); 163 | selectedNode = 0; 164 | } 165 | 166 | mSceneMgr->destroyQuery(query); 167 | 168 | update(); 169 | e->accept(); 170 | } 171 | else 172 | { 173 | e->ignore(); 174 | } 175 | } 176 | 177 | void OgreWidget::mouseMoveEvent(QMouseEvent *e) 178 | { 179 | if(e->buttons().testFlag(Qt::LeftButton) && oldPos != invalidMousePoint) 180 | { 181 | const QPoint &pos = e->pos(); 182 | Ogre::Real deltaX = pos.x() - oldPos.x(); 183 | Ogre::Real deltaY = pos.y() - oldPos.y(); 184 | 185 | if(e->modifiers().testFlag(Qt::ControlModifier)) 186 | { 187 | deltaX *= turboModifier; 188 | deltaY *= turboModifier; 189 | } 190 | 191 | //Ogre::Vector3 camTranslation(deltaX, deltaY, 0); 192 | //const Ogre::Vector3 &actualCamPos = mCamera->getPosition(); 193 | //setCameraPosition(actualCamPos + camTranslation); 194 | static Real cameraRotationPerMouseMovement = 0.2; 195 | mCamera->yaw(Degree(-cameraRotationPerMouseMovement * deltaX)); 196 | mCamera->pitch(Degree(-cameraRotationPerMouseMovement * deltaY)); 197 | 198 | oldPos = pos; 199 | e->accept(); 200 | } 201 | else 202 | { 203 | e->ignore(); 204 | } 205 | } 206 | 207 | void OgreWidget::mousePressEvent(QMouseEvent *e) 208 | { 209 | if(e->buttons().testFlag(Qt::LeftButton)) 210 | { 211 | oldPos = e->pos(); 212 | e->accept(); 213 | } 214 | else if (e->buttons().testFlag(Qt::RightButton)) { 215 | mPhysicsScene->setGravity(-mPhysicsScene->getGravity()); 216 | } 217 | else 218 | { 219 | e->ignore(); 220 | } 221 | } 222 | 223 | void OgreWidget::mouseReleaseEvent(QMouseEvent *e) 224 | { 225 | if(!e->buttons().testFlag(Qt::LeftButton)) 226 | { 227 | oldPos = QPoint(invalidMousePoint); 228 | e->accept(); 229 | } 230 | else 231 | { 232 | e->ignore(); 233 | } 234 | } 235 | 236 | void OgreWidget::moveEvent(QMoveEvent *e) 237 | { 238 | QWidget::moveEvent(e); 239 | 240 | if(e->isAccepted() && mRenderWindow) 241 | { 242 | mRenderWindow->windowMovedOrResized(); 243 | update(); 244 | } 245 | } 246 | 247 | QPaintEngine* OgreWidget::paintEngine() const 248 | { 249 | // We don't want another paint engine to get in the way for our Ogre based paint engine. 250 | // So we return nothing. 251 | return NULL; 252 | } 253 | 254 | void OgreWidget::paintEvent(QPaintEvent *e) 255 | { 256 | //mRoot->_fireFrameStarted(); 257 | //mRenderWindow->update(); 258 | 259 | mRoot->renderOneFrame(); 260 | 261 | //mRoot->_fireFrameEnded(); 262 | 263 | e->accept(); 264 | } 265 | 266 | bool OgreWidget::frameStarted(const Ogre::FrameEvent &evt) { 267 | // set view space light direction as shader parameter (because auto params not properly available in Compositor render_quad pass...) 268 | Matrix3 normalMatrix; 269 | mCamera->getViewMatrix().inverseAffine().transpose().extract3x3Matrix(normalMatrix); 270 | GpuProgramManager::getSingleton().getSharedParameters("lighting_params")->setNamedConstant("normalMatrix", normalMatrix); 271 | 272 | 273 | Vector3 lightDir_view_space = -normalMatrix * mSceneMgr->getLight("SunLight")->getDirection(); 274 | GpuProgramManager::getSingleton().getSharedParameters("lighting_params")->setNamedConstant("lightDir_view_space", lightDir_view_space); 275 | 276 | return true; 277 | } 278 | 279 | 280 | bool OgreWidget::frameRenderingQueued(const Ogre::FrameEvent &evt) { 281 | mPhysicsWorld->advance(evt.timeSinceLastFrame*mSimulationSpeed); 282 | 283 | mOgreBaseAnim->addTime(evt.timeSinceLastFrame); 284 | mOgreTopAnim->addTime(evt.timeSinceLastFrame); 285 | 286 | updateFrameStats(); 287 | 288 | return true; 289 | } 290 | 291 | 292 | bool OgreWidget::frameEnded(const Ogre::FrameEvent &evt) { 293 | static Real summedTime = 0; 294 | summedTime += evt.timeSinceLastFrame; 295 | // TODO!!!!: reloading doesn't work with the shared param stuff... 296 | //if (summedTime >= 1) { // TODO!: checkTimeAndReloadIfNeeded every x seconds: make toggle off button? for performance? 297 | // summedTime = 0; 298 | 299 | // //if (mResourceGroupHelper->filesChanged("General1")) { // TODO!: bit hackish and redundant... 300 | // //reload changed ressources 301 | // //SimpleRenderable* fluidRenderable = dynamic_cast(mFluid->getRenderable()); 302 | // //String fluidMaterialName = fluidRenderable->getMaterial()->getName(); 303 | // CompositorManager::getSingleton().removeCompositor(mViewport, "ScreenSpaceParticleFluid"); 304 | // //GpuProgramManager::getSingleton().removeAll(); 305 | // if (mResourceGroupHelper->checkTimeAndReloadIfNeeded("General1", std::string(), false)) { 306 | // //fluidRenderable->setMaterial("BaseWhite"); 307 | // //fluidRenderable->setMaterial(fluidMaterialName); 308 | 309 | // } 310 | // CompositorManager::getSingleton().addCompositor(mViewport, "ScreenSpaceParticleFluid"); 311 | // CompositorManager::getSingleton().setCompositorEnabled(mViewport, "ScreenSpaceParticleFluid", true); 312 | // //} 313 | 314 | //} 315 | 316 | return true; 317 | } 318 | 319 | void OgreWidget::resizeEvent(QResizeEvent *e) 320 | { 321 | QWidget::resizeEvent(e); 322 | 323 | if(e->isAccepted()) 324 | { 325 | const QSize &newSize = e->size(); 326 | if(mRenderWindow) 327 | { 328 | mRenderWindow->resize(newSize.width(), newSize.height()); 329 | mRenderWindow->windowMovedOrResized(); 330 | } 331 | if(mCamera) 332 | { 333 | Ogre::Real aspectRatio = Ogre::Real(newSize.width()) / Ogre::Real(newSize.height()); 334 | mCamera->setAspectRatio(aspectRatio); 335 | } 336 | 337 | if(mViewport && CompositorManager::getSingleton().hasCompositorChain(mViewport)) 338 | { 339 | CompositorChain* chain = CompositorManager::getSingleton().getCompositorChain(mViewport); 340 | unsigned int length = chain->getNumCompositors(); 341 | for(unsigned int i = 0; i < length; i++) 342 | { 343 | chain->setCompositorEnabled(i, false); 344 | chain->setCompositorEnabled(i, true); 345 | } 346 | } 347 | } 348 | } 349 | 350 | void OgreWidget::showEvent(QShowEvent *e) 351 | { 352 | if(!mRoot) 353 | { 354 | initOgreSystem(); 355 | } 356 | 357 | QWidget::showEvent(e); 358 | } 359 | 360 | void OgreWidget::wheelEvent(QWheelEvent *e) 361 | { 362 | //Ogre::Vector3 zTranslation(0,0, -e->delta() / 60); 363 | 364 | //if(e->modifiers().testFlag(Qt::ControlModifier)) 365 | //{ 366 | // zTranslation.z *= turboModifier; 367 | //} 368 | 369 | //const Ogre::Vector3 &actualCamPos = mCamera->getPosition(); 370 | //setCameraPosition(actualCamPos + zTranslation); 371 | // TODO?: mouse wheel zoom 372 | 373 | e->accept(); 374 | } 375 | 376 | void OgreWidget::initOgreSystem() 377 | { 378 | mRoot = new Ogre::Root(); 379 | 380 | // TODO?: config options: do better 381 | Ogre::RenderSystem *renderSystem = mRoot->getRenderSystemByName("OpenGL Rendering Subsystem"); 382 | mRoot->setRenderSystem(renderSystem); 383 | mRoot->initialise(false); 384 | 385 | mSceneMgr = mRoot->createSceneManager(Ogre::ST_GENERIC); 386 | 387 | Ogre::NameValuePairList viewConfig; 388 | Ogre::String widgetHandle; 389 | widgetHandle = Ogre::StringConverter::toString((size_t)((HWND)winId())); 390 | viewConfig["externalWindowHandle"] = widgetHandle; 391 | //viewConfig["useNVPerfHUD"] = "true"; 392 | mRenderWindow = mRoot->createRenderWindow("Ogre rendering window", 393 | width(), height(), false, &viewConfig); 394 | 395 | mCamera = mSceneMgr->createCamera("Camera"); 396 | Ogre::Vector3 camPos(8.5, 6, 11.5); 397 | mCamera->setPosition(camPos); 398 | mCamera->lookAt(0,3,0); 399 | //emit cameraPositionChanged(camPos); 400 | 401 | mViewport = mRenderWindow->addViewport(mCamera); 402 | mViewport->setBackgroundColour(Ogre::ColourValue(0,0,0)); 403 | mCamera->setAspectRatio(Ogre::Real(width()) / Ogre::Real(height())); 404 | mCamera->setNearClipDistance(0.1); 405 | mCamera->setFarClipDistance(100); 406 | 407 | setupResources(); 408 | setupNxOgre(); 409 | createScene(); 410 | 411 | mDebugOverlay = OverlayManager::getSingleton().getByName("Core/DebugOverlay"); 412 | mDebugOverlay->remove2D(mDebugOverlay->getChild("Core/LogoPanel")); 413 | mDebugOverlay->show(); 414 | 415 | mRoot->addFrameListener(this); 416 | } 417 | 418 | void OgreWidget::setupResources() 419 | { 420 | // Load resource paths from config file 421 | Ogre::ConfigFile cf; 422 | cf.load("resources.cfg"); 423 | 424 | // Go through all sections & settings in the file 425 | Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator(); 426 | 427 | Ogre::String secName, typeName, archName; 428 | while (seci.hasMoreElements()) 429 | { 430 | secName = seci.peekNextKey(); 431 | Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext(); 432 | Ogre::ConfigFile::SettingsMultiMap::iterator i; 433 | for (i = settings->begin(); i != settings->end(); ++i) 434 | { 435 | typeName = i->first; 436 | archName = i->second; 437 | Ogre::ResourceGroupManager::getSingleton().addResourceLocation( 438 | archName, typeName, secName); 439 | } 440 | } 441 | 442 | //GpuProgramManager::getSingleton().createSharedParameters("lighting_params"); 443 | 444 | // Initialise, parse scripts etc 445 | Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); 446 | } 447 | 448 | void OgreWidget::setupNxOgre() { 449 | //NxOgre::WorldDescription wdesc; 450 | //wdesc. 451 | mPhysicsWorld = NxOgre::World::createWorld(); 452 | mPhysicsWorld->getRemoteDebugger()->connect(); 453 | 454 | mPhysicsScene = mPhysicsWorld->createScene(); 455 | mPhysicsScene->setGravity(NxOgre::Vec3(0.0f,-9.81f,0.0f)); 456 | mPhysicsRenderSystem = new Critter::RenderSystem(mPhysicsScene); 457 | 458 | NxOgre::VisualDebuggerDescription desc; 459 | desc.showAll(); 460 | mVisualDebugger = mPhysicsRenderSystem->createVisualDebugger(); 461 | mVisualDebugger->disable(); 462 | } 463 | 464 | void OgreWidget::createScene() 465 | { 466 | mSceneMgr->setAmbientLight(Ogre::ColourValue(0.3,0.3,0.3)); 467 | 468 | Light *light = mSceneMgr->createLight("SunLight"); 469 | light->setType(Light::LT_DIRECTIONAL); 470 | light->setDirection(-Vector3::UNIT_Y+Vector3::UNIT_X*0.2); 471 | light->setDiffuseColour(0.5, 0.5, 0.5); 472 | light->setSpecularColour(1.0, 1.0, 1.0); 473 | 474 | 475 | //Ogre::Entity *entity = mSceneMgr->createEntity("Axes", "axes.mesh"); 476 | //Ogre::SceneNode *node = mSceneMgr->getRootSceneNode()->createChildSceneNode("node"); 477 | //node->attachObject(entity); 478 | //node->yaw(Ogre::Radian(Ogre::Degree(-90))); 479 | 480 | // visual ground plane 481 | Plane plane(Vector3::UNIT_Y, 0); 482 | MeshManager::getSingleton().createPlane("ground", 483 | ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane, 484 | 500,500,20,20,true,1,5,5,Vector3::UNIT_Z); 485 | 486 | Entity* groundEnt = mSceneMgr->createEntity("GroundEntity", "ground"); 487 | mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(groundEnt); 488 | groundEnt->setMaterialName("marbleTexture"); 489 | groundEnt->setCastShadows(false); 490 | 491 | mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox", 50); 492 | 493 | // physical ground plane 494 | NxOgre::PlaneGeometryDescription pdesc; 495 | mPhysicsScene->createSceneGeometry(pdesc); 496 | 497 | // box for surrounding the fluid 498 | mPhysicsScene->createSceneGeometry(NxOgre::BoxDescription(16,25,1), NxOgre::Vec3(0,0,-4)); 499 | mPhysicsScene->createSceneGeometry(NxOgre::BoxDescription(16,25,1), NxOgre::Vec3(0,0, 4)); 500 | mPhysicsScene->createSceneGeometry(NxOgre::BoxDescription(1,25,16), NxOgre::Vec3(-4,0, 0)); 501 | mPhysicsScene->createSceneGeometry(NxOgre::BoxDescription(1,25,16), NxOgre::Vec3(4,0, 0)); 502 | //mPhysicsScene->createSceneGeometry(NxOgre::BoxDescription(16,1,18), NxOgre::Vec3(0,4, 0)); 503 | 504 | createFluid(); 505 | 506 | //mPhysicsScene->createActor(NxOgre::BoxDescription(1,1,1), NxOgre::Vec3(0,10,0)); 507 | 508 | // compositor for fluid 509 | CompositorManager::getSingleton().addCompositor(mViewport, "ScreenSpaceParticleFluid"); 510 | CompositorManager::getSingleton().setCompositorEnabled(mViewport, "ScreenSpaceParticleFluid", true); 511 | 512 | // add Ogre model for comparing shading of fluid and normal meshes 513 | SceneNode* ogreNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); 514 | Entity* ogreEnt = mSceneMgr->createEntity("Sinbad", "Sinbad.mesh"); 515 | ogreNode->attachObject(ogreEnt); 516 | float scale = 0.3; 517 | ogreNode->setScale(Vector3(scale)); 518 | ogreNode->setPosition(5, ogreEnt->getBoundingBox().getHalfSize().y*scale, 0); 519 | 520 | // Set animation blend mode to additive / cumulative. 521 | ogreEnt->getSkeleton()->setBlendMode(ANIMBLEND_CUMULATIVE); 522 | 523 | // Get the two halves of the idle animation. 524 | mOgreBaseAnim = ogreEnt->getAnimationState("IdleBase"); 525 | mOgreTopAnim = ogreEnt->getAnimationState("IdleTop"); 526 | 527 | // Enable both of them and set them to loop. 528 | mOgreBaseAnim->setLoop(true); 529 | mOgreTopAnim->setLoop(true); 530 | mOgreBaseAnim->setEnabled(true); 531 | mOgreTopAnim->setEnabled(true); 532 | 533 | //ogreEnt->setMaterialName("normals"); 534 | 535 | // TODO!!!: Ogre model: renderqueue switch to render as background / part of fluid 536 | //ogreEnt->setRenderQueueGroup(RENDER_QUEUE_9); 537 | 538 | } 539 | 540 | void OgreWidget::createFluid() { 541 | if (mFluid) { 542 | //TODO?: unstable physx: Fluid::destroyEmitter not linking -> not implemented, but was empty before anyway 543 | //mFluid->destroyEmitter(mEmitter); 544 | mPhysicsRenderSystem->destroyFluid(mFluid); 545 | mFluid = 0; 546 | } 547 | 548 | mFluid = mPhysicsRenderSystem->createFluid(mFluidDescription, "SpherePointSpritesWithGS"/*"BaseWhiteNoLighting"*/, Critter::Enums::FluidType_Position); //FluidType_Velocity FluidType_Position FluidType_OgreParticle 549 | dynamic_cast(mFluid->getRenderable())->setRenderQueueGroup(RENDER_QUEUE_9); 550 | 551 | mEmitter = mFluid->createEmitter(mEmitterDescription); 552 | } 553 | 554 | void OgreWidget::updateFrameStats(void) 555 | { 556 | static String currFps = "Current FPS: "; 557 | static String avgFps = "Average FPS: "; 558 | static String bestFps = "Best FPS: "; 559 | static String worstFps = "Worst FPS: "; 560 | static String tris = "Triangle Count: "; 561 | static String batches = "Batch Count: "; 562 | 563 | // update stats when necessary 564 | try { 565 | OverlayElement* guiAvg = OverlayManager::getSingleton().getOverlayElement("Core/AverageFps"); 566 | OverlayElement* guiCurr = OverlayManager::getSingleton().getOverlayElement("Core/CurrFps"); 567 | OverlayElement* guiBest = OverlayManager::getSingleton().getOverlayElement("Core/BestFps"); 568 | OverlayElement* guiWorst = OverlayManager::getSingleton().getOverlayElement("Core/WorstFps"); 569 | 570 | const RenderTarget::FrameStats& stats = mRenderWindow->getStatistics(); 571 | guiAvg->setCaption(avgFps + StringConverter::toString(stats.avgFPS)); 572 | guiCurr->setCaption(currFps + StringConverter::toString(stats.lastFPS)); 573 | guiBest->setCaption(bestFps + StringConverter::toString(stats.bestFPS) 574 | +" "+StringConverter::toString(stats.bestFrameTime)+" ms"); 575 | guiWorst->setCaption(worstFps + StringConverter::toString(stats.worstFPS) 576 | +" "+StringConverter::toString(stats.worstFrameTime)+" ms"); 577 | 578 | OverlayElement* guiTris = OverlayManager::getSingleton().getOverlayElement("Core/NumTris"); 579 | guiTris->setCaption(tris + StringConverter::toString(stats.triangleCount)); 580 | 581 | OverlayElement* guiBatches = OverlayManager::getSingleton().getOverlayElement("Core/NumBatches"); 582 | guiBatches->setCaption(batches + StringConverter::toString(stats.batchCount)); 583 | 584 | OverlayElement* guiDbg = OverlayManager::getSingleton().getOverlayElement("Core/DebugText"); 585 | //guiDbg->setCaption(mDebugText); 586 | } 587 | catch(...) { /* ignore */ } 588 | 589 | //int particleCount = *mFluid->getParticleData()->mNbParticles.get(); 590 | int particleCount = mFluid->getNbParticles(); 591 | ((ParticleFluids*)parent())->mLabelParticleCount->setText(QString("Particle Count : %1").arg(particleCount)); 592 | 593 | static Vector3 oldPos = Vector3(); 594 | Vector3 curPos = mCamera->getPosition(); 595 | if (mCamera->getPosition() != oldPos) { 596 | ((ParticleFluids*)parent())->mLabelCamPos->setText(QString("Camera Position : %1") 597 | .arg(StringConverter::toString(mCamera->getPosition()).c_str())); 598 | } 599 | } 600 | --------------------------------------------------------------------------------