diff --git a/changes.txt b/changes.txt index df6532b9..490dc90c 100644 --- a/changes.txt +++ b/changes.txt @@ -9,6 +9,9 @@ Changes in ogl-es (not yet released - will be merged with trunk at some point) -------------------------- Changes in 1.9 (not yet released) +- Bugfix: OpenGL no longer antialiasing stencil buffer when driver has antialiasing disabled. +- Add IShadowVolumeSceneNode::setOptimization to allow disabling optimizations for meshes were contour shadows fail. +- Stencil shadows work now also with directional light - Drivers can now try to create textures from images in more exotic color formats (like floating point formats). It depends on the driver how much that works (so far mainly OpenGL can handle it somewhat). - Fix OpenGL to no longer switch colors red and blue in 24-bit RGB format. But warnings added to documentation to avoid 24-bit textures as they are generally just trouble. - No longer try to convert ECF_R5G6B5 to ECF_A1R5G5B5 on OpenGL (just made texture-loading seem to fail). diff --git a/examples/08.SpecialFX/main.cpp b/examples/08.SpecialFX/main.cpp index ddac5d88..c72674b7 100644 --- a/examples/08.SpecialFX/main.cpp +++ b/examples/08.SpecialFX/main.cpp @@ -112,17 +112,16 @@ int main() */ // create light - - node = smgr->addLightSceneNode(0, core::vector3df(0,0,0), + scene::ILightSceneNode * lightNode = smgr->addLightSceneNode(0, core::vector3df(0,0,0), video::SColorf(1.0f, 0.6f, 0.7f, 1.0f), 800.0f); scene::ISceneNodeAnimator* anim = 0; - anim = smgr->createFlyCircleAnimator (core::vector3df(0,150,0),250.0f); - node->addAnimator(anim); + anim = smgr->createFlyCircleAnimator (core::vector3df(0,150,0),250.0f, 0.0005f); + lightNode ->addAnimator(anim); anim->drop(); // attach billboard to light - node = smgr->addBillboardSceneNode(node, core::dimension2d(50, 50)); + node = smgr->addBillboardSceneNode(lightNode, core::dimension2d(50, 50)); node->setMaterialFlag(video::EMF_LIGHTING, false); node->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR); node->setMaterialTexture(0, driver->getTexture(mediaPath + "particlewhite.bmp")); @@ -259,15 +258,29 @@ int main() anode->setPosition(core::vector3df(-50,20,-60)); anode->setAnimationSpeed(15); + /* + Shadows still have to be drawn even then the node causing them is not visible itself. + We have to disable culling if the node is animated or it's transformations change + as otherwise the shadow is not updated correctly. + If you have many objects and this becomes a speed problem you will have to figure + out some manual culling (for exampling hiding all objects beyond a certain distance). + */ + anode->setAutomaticCulling(scene::EAC_OFF); + // add shadow anode->addShadowVolumeSceneNode(); smgr->setShadowColor(video::SColor(150,0,0,0)); - // make the model a little bit bigger and normalize its normals - // because of the scaling, for correct lighting + // make the model a bit bigger anode->setScale(core::vector3df(2,2,2)); + // because of the scaling we have to normalize its normals for correct lighting anode->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true); + // let the dwarf slowly rotate around it's y axis + scene::ISceneNodeAnimator* ra = smgr->createRotationAnimator(irr::core::vector3df(0, 0.1f, 0)); + anode->addAnimator(ra); + ra->drop(); + /* Finally we simply have to draw everything, that's all. */ diff --git a/examples/27.PostProcessing/Makefile b/examples/27.PostProcessing/Makefile new file mode 100644 index 00000000..c5905005 --- /dev/null +++ b/examples/27.PostProcessing/Makefile @@ -0,0 +1,38 @@ +# Makefile for Irrlicht Examples +# It's usually sufficient to change just the target name and source file list +# and be sure that CXX is set to a valid compiler +Target = 27.PostProcessing +Sources = main.cpp + +# general compiler settings +CPPFLAGS = -I../../include -I/usr/X11R6/include +CXXFLAGS = -O3 -ffast-math +#CXXFLAGS = -g -Wall + +#default target is Linux +all: all_linux + +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif + +# target specific settings +all_linux: LDFLAGS = -L/usr/X11R6/lib$(LIBSELECT) -L../../lib/Linux -lIrrlicht -lGL -lXxf86vm -lXext -lX11 -lXcursor +all_linux clean_linux: SYSTEM=Linux +all_win32: LDFLAGS = -L../../lib/Win32-gcc -lIrrlicht -lopengl32 -lm +all_win32 clean_win32: SYSTEM=Win32-gcc +all_win32 clean_win32: SUF=.exe +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = ../../bin/$(SYSTEM)/$(Target)$(SUF) + +all_linux all_win32: + $(warning Building...) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(Sources) -o $(DESTPATH) $(LDFLAGS) + +clean: clean_linux clean_win32 + $(warning Cleaning...) + +clean_linux clean_win32: + @$(RM) $(DESTPATH) + +.PHONY: all all_win32 clean clean_linux clean_win32 diff --git a/examples/27.PostProcessing/PostProcessing.cbp b/examples/27.PostProcessing/PostProcessing.cbp new file mode 100644 index 00000000..b9fc0873 --- /dev/null +++ b/examples/27.PostProcessing/PostProcessing.cbp @@ -0,0 +1,56 @@ + + + + + + diff --git a/examples/27.PostProcessing/PostProcessing_vc10.vcxproj b/examples/27.PostProcessing/PostProcessing_vc10.vcxproj new file mode 100644 index 00000000..65e47f37 --- /dev/null +++ b/examples/27.PostProcessing/PostProcessing_vc10.vcxproj @@ -0,0 +1,231 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 27.PostProcessing + {2B885150-210F-4CA7-957E-2C3D75974308} + PostProcessing + + + + Application + false + MultiByte + + + Application + false + MultiByte + + + Application + false + MultiByte + + + Application + false + MultiByte + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/PostProcessing.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/PostProcessing.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/PostProcessing.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/PostProcessing.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/27.PostProcessing/PostProcessing_vc10.vcxproj.user b/examples/27.PostProcessing/PostProcessing_vc10.vcxproj.user new file mode 100644 index 00000000..695b5c78 --- /dev/null +++ b/examples/27.PostProcessing/PostProcessing_vc10.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/examples/27.PostProcessing/PostProcessing_vc11.vcxproj b/examples/27.PostProcessing/PostProcessing_vc11.vcxproj new file mode 100644 index 00000000..8a732900 --- /dev/null +++ b/examples/27.PostProcessing/PostProcessing_vc11.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 27.PostProcessing + {F864F96D-F6AE-43E2-9A12-218B1A081255} + PostProcessing + + + + Application + false + MultiByte + v110 + + + Application + false + MultiByte + v110 + + + Application + false + MultiByte + v110 + + + Application + false + MultiByte + v110 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/PostProcessing.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/PostProcessing.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/PostProcessing.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/PostProcessing.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/27.PostProcessing/PostProcessing_vc11.vcxproj.user b/examples/27.PostProcessing/PostProcessing_vc11.vcxproj.user new file mode 100644 index 00000000..695b5c78 --- /dev/null +++ b/examples/27.PostProcessing/PostProcessing_vc11.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/examples/27.PostProcessing/PostProcessing_vc12.vcxproj b/examples/27.PostProcessing/PostProcessing_vc12.vcxproj new file mode 100644 index 00000000..8aef23bd --- /dev/null +++ b/examples/27.PostProcessing/PostProcessing_vc12.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 27.PostProcessing + {17E74625-568E-4008-897E-CAD12A332B0C} + PostProcessing + + + + Application + false + MultiByte + v110 + + + Application + false + MultiByte + v110 + + + Application + false + MultiByte + v110 + + + Application + false + MultiByte + v110 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/PostProcessing.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/PostProcessing.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/PostProcessing.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/PostProcessing.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/27.PostProcessing/PostProcessing_vc12.vcxproj.user b/examples/27.PostProcessing/PostProcessing_vc12.vcxproj.user new file mode 100644 index 00000000..695b5c78 --- /dev/null +++ b/examples/27.PostProcessing/PostProcessing_vc12.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/examples/27.PostProcessing/PostProcessing_vc14.vcxproj b/examples/27.PostProcessing/PostProcessing_vc14.vcxproj new file mode 100644 index 00000000..a39c5551 --- /dev/null +++ b/examples/27.PostProcessing/PostProcessing_vc14.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 27.PostProcessing + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2} + PostProcessing + + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + Application + false + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + ..\..\bin\Win32-VisualStudio\ + ..\..\bin\Win64-VisualStudio\ + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + .\Debug/PostProcessing.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Debug/PostProcessing.tlb + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + true + Console + + + + + + + .\Release/PostProcessing.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win32-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win32-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + .\Release/PostProcessing.tlb + + + + + MaxSpeed + OnlyExplicitInline + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c07 + + + ..\..\bin\Win64-VisualStudio\27.PostProcessing.exe + ..\..\lib\Win64-visualstudio;%(AdditionalLibraryDirectories) + Console + + + + + + + Disabled + Disabled + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + EnableFastChecks + EnableFastChecks + MaxSpeed + MaxSpeed + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/examples/27.PostProcessing/PostProcessing_vc14.vcxproj.user b/examples/27.PostProcessing/PostProcessing_vc14.vcxproj.user new file mode 100644 index 00000000..695b5c78 --- /dev/null +++ b/examples/27.PostProcessing/PostProcessing_vc14.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/examples/27.PostProcessing/main.cpp b/examples/27.PostProcessing/main.cpp new file mode 100644 index 00000000..e60b7b69 --- /dev/null +++ b/examples/27.PostProcessing/main.cpp @@ -0,0 +1,417 @@ +/** Example 027 Post Processing + +@author Boshen Guan + +This tutorial shows how to implement post processing for D3D9 and OpenGL with +the engine. In order to do post processing, scene objects are firstly rendered +to render target. With the help of screen quad, the render target texture +is then drawn on the quad with shader-defined effects applied. + +This tutorial shows how to create a screen quad. It also shows how to create a +render target texture and associate it with the quad. Effects are defined as +shaders which are applied during rendering the quad with the render target +texture attached to it. + +A simple color inverse example is presented in this tutorial. The effect is +written in HLSL and GLSL. + +We include all headers and define necessary variables as we have done before. +*/ +#include "driverChoice.h" +#include "exampleHelper.h" + +#include + +using namespace irr; + +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#endif + +/* +We write a class derived from IShaderConstantSetCallBack class and implement +OnSetConstants callback interface. In this callback, we will set constants +used by the shader. +In this example, our HLSL shader needs texture size as input in its vertex +shader. Therefore, we set texture size in OnSetConstants callback using +setVertexShaderConstant function. +*/ + +IrrlichtDevice* device = 0; +video::ITexture* rt = 0; + +class QuadShaderCallBack : public video::IShaderConstantSetCallBack +{ +public: + QuadShaderCallBack() : FirstUpdate(true), TextureSizeID(-1), TextureSamplerID(-1) + { } + + virtual void OnSetConstants(video::IMaterialRendererServices* services, + s32 userData) + { + core::dimension2d size = rt->getSize(); + + // get texture size array + f32 textureSize[] = + { + (f32)size.Width, (f32)size.Height + }; + + if ( FirstUpdate ) + { + TextureSizeID = services->getVertexShaderConstantID("TextureSize"); + TextureSamplerID = services->getPixelShaderConstantID("TextureSampler"); + } + + // set texture size to vertex shader + services->setVertexShaderConstant(TextureSizeID, reinterpret_cast(textureSize), 2); + + // set texture for an OpenGL driver + s32 textureLayer = 0; + services->setPixelShaderConstant(TextureSamplerID, &textureLayer, 1); + } + +private: + bool FirstUpdate; + s32 TextureSizeID; + s32 TextureSamplerID; +}; + +class ScreenQuad : public IReferenceCounted +{ +public: + + ScreenQuad(video::IVideoDriver* driver) + : Driver(driver) + { + // --------------------------------> u + // |[1](-1, 1)----------[2](1, 1) + // | | ( 0, 0) / | (1, 0) + // | | / | + // | | / | + // | | / | + // | | / | + // | | / | + // | | / | + // | | / | + // | | / | + // |[0](-1, -1)---------[3](1, -1) + // | ( 0, 1) (1, 1) + // V + // v + + /* + A screen quad is composed of two adjacent triangles with 4 vertices. + Vertex [0], [1] and [2] create the first triangle and Vertex [0], + [2] and [3] create the second one. To map texture on the quad, UV + coordinates are assigned to the vertices. The origin of UV coordinate + locates on the top-left corner. And the value of UVs range from 0 to 1. + */ + + // define vertices array + + Vertices[0] = irr::video::S3DVertex(-1.0f, -1.0f, 0.0f, 1, 1, 0, irr::video::SColor(0,255,255,255), 0.0f, 1.0f); + Vertices[1] = irr::video::S3DVertex(-1.0f, 1.0f, 0.0f, 1, 1, 0, irr::video::SColor(0,255,255,255), 0.0f, 0.0f); + Vertices[2] = irr::video::S3DVertex( 1.0f, 1.0f, 0.0f, 1, 1, 0, irr::video::SColor(0,255,255,255), 1.0f, 0.0f); + Vertices[3] = irr::video::S3DVertex( 1.0f, -1.0f, 0.0f, 1, 1, 0, irr::video::SColor(0,255,255,255), 1.0f, 1.0f); + + // define indices for triangles + + Indices[0] = 0; + Indices[1] = 1; + Indices[2] = 2; + Indices[3] = 0; + Indices[4] = 2; + Indices[5] = 3; + + // turn off lighting as default + Material.setFlag(video::EMF_LIGHTING, false); + + // set texture warp settings to clamp to edge pixel + for (u32 i = 0; i < video::MATERIAL_MAX_TEXTURES; i++) + { + Material.TextureLayer[i].TextureWrapU = video::ETC_CLAMP_TO_EDGE; + Material.TextureLayer[i].TextureWrapV = video::ETC_CLAMP_TO_EDGE; + } + } + + virtual ~ScreenQuad() {} + + + //! render the screen quad + virtual void render() + { + // set the material of screen quad + Driver->setMaterial(Material); + + // set matrices to fit the quad to full viewport + Driver->setTransform(video::ETS_WORLD, core::IdentityMatrix); + Driver->setTransform(video::ETS_VIEW, core::IdentityMatrix); + Driver->setTransform(video::ETS_PROJECTION, core::IdentityMatrix); + + // draw screen quad + Driver->drawVertexPrimitiveList(Vertices, 4, Indices, 2); + } + + //! sets a flag of material to a new value + virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) + { + Material.setFlag(flag, newvalue); + } + + //! sets the texture of the specified layer in material to the new texture. + void setMaterialTexture(u32 textureLayer, video::ITexture* texture) + { + Material.setTexture(textureLayer, texture); + } + + //! sets the material type to a new material type. + virtual void setMaterialType(video::E_MATERIAL_TYPE newType) + { + Material.MaterialType = newType; + } + +private: + + video::IVideoDriver *Driver; + video::S3DVertex Vertices[4]; + u16 Indices[6]; + video::SMaterial Material; +}; + +/* +We start up the engine just like before. Then shader programs are selected +according to the driver type. +*/ +int main() +{ + // ask user for driver + video::E_DRIVER_TYPE driverType=driverChoiceConsole(); + if (driverType==video::EDT_COUNT) + return 1; + + // create device + device = createDevice(driverType, core::dimension2d(640, 480)); + + if (device == 0) + return 1; // could not create selected driver. + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + + /* + In this example, high level post processing shaders are loaded for both + Direct3D and OpenGL drivers. + File pp_d3d9.hlsl is for Direct3D 9, and pp_opengl.frag/pp_opengl.vert + are for OpenGL. + */ + + const io::path mediaPath = getExampleMediaPath(); + io::path vsFileName; // filename for the vertex shader + io::path psFileName; // filename for the pixel shader + + switch(driverType) + { + case video::EDT_DIRECT3D9: + psFileName = mediaPath + "pp_d3d9.hlsl"; + vsFileName = psFileName; // both shaders are in the same file + break; + + case video::EDT_OPENGL: + psFileName = mediaPath + "pp_opengl.frag"; + vsFileName = mediaPath + "pp_opengl.vert"; + break; + } + + /* + Check for hardware capability of executing the corresponding shaders + on selected renderer. This is not necessary though. + */ + + if (!driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) && + !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)) + { + device->getLogger()->log("WARNING: Pixel shaders disabled "\ + "because of missing driver/hardware support."); + psFileName = ""; + } + + if (!driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) && + !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)) + { + device->getLogger()->log("WARNING: Vertex shaders disabled "\ + "because of missing driver/hardware support."); + vsFileName = ""; + } + + /* + An animated mesh is loaded to be displayed. As in most examples, + we'll take the fairy md2 model. + */ + + // load and display animated fairy mesh + + scene::IAnimatedMeshSceneNode* fairy = smgr->addAnimatedMeshSceneNode( + smgr->getMesh(mediaPath + "faerie.md2")); + + if (fairy) + { + fairy->setMaterialTexture(0, + driver->getTexture(mediaPath + "faerie2.bmp")); // set diffuse texture + fairy->setMaterialFlag(video::EMF_LIGHTING, false); // disable dynamic lighting + fairy->setPosition(core::vector3df(-10,0,-100)); + fairy->setMD2Animation ( scene::EMAT_STAND ); + } + + // add scene camera + smgr->addCameraSceneNode(0, core::vector3df(10,10,-80), + core::vector3df(-10,10,-100)); + + /* + We create a render target texture (RTT) with the same size as frame buffer. + Instead of rendering the scene directly to the frame buffer, we firstly + render it to this RTT. Post processing is then applied based on this RTT. + RTT size needs not to be the same with frame buffer though. However in this + example, we expect the result of rendering to RTT to be consistent with the + result of rendering directly to the frame buffer. Therefore, the size of + RTT keeps the same with frame buffer. + */ + + // create render target + + if (driver->queryFeature(video::EVDF_RENDER_TO_TARGET)) + { + rt = driver->addRenderTargetTexture(core::dimension2d(640, 480), "RTT1"); + } + else + { + device->getLogger()->log("Your hardware or this renderer is not able to use the "\ + "render to texture feature. RTT Disabled."); + } + + /* + Post processing is achieved by rendering a screen quad with this RTT (with + previously rendered result) as a texture on the quad. A screen quad is + geometry of flat plane composed of two adjacent triangles covering the + entire area of viewport. In this pass of rendering, RTT works just like + a normal texture and is drawn on the quad during rendering. We can then + take control of this rendering process by applying various shader-defined + materials to the quad. In other words, we can achieve different effect by + writing different shaders. + This process is called post processing because it normally does not rely + on scene geometry. The inputs of this process are just textures, or in + other words, just images. With the help of screen quad, we can draw these + images on the screen with different effects. For example, we can adjust + contrast, make grayscale, add noise, do more fancy effect such as blur, + bloom, ghost, or just like in this example, we invert the color to produce + negative image. + Note that post processing is not limited to use only one texture. It can + take multiple textures as shader inputs to provide desired result. In + addition, post processing can also be chained to produce compound result. + */ + + // we create a screen quad + ScreenQuad *screenQuad = new ScreenQuad(driver); + + // turn off mip maps and bilinear filter since we do not want interpolated result + screenQuad->setMaterialFlag(video::EMF_USE_MIP_MAPS, false); + screenQuad->setMaterialFlag(video::EMF_BILINEAR_FILTER, false); + + // set quad texture to RTT we just create + screenQuad->setMaterialTexture(0, rt); + + /* + Let's create material for the quad. Like in other example, we create material + using IGPUProgrammingServices and call addShaderMaterialFromFiles, which + returns a material type identifier. + */ + + // create materials + + video::IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices(); + s32 ppMaterialType = 0; + + if (gpu) + { + // We write a QuadShaderCallBack class that implements OnSetConstants + // callback of IShaderConstantSetCallBack class at the beginning of + // this tutorial. We set shader constants in this callback. + + // create an instance of callback class + + QuadShaderCallBack* mc = new QuadShaderCallBack(); + + // create material from post processing shaders + + ppMaterialType = gpu->addHighLevelShaderMaterialFromFiles( + vsFileName, "vertexMain", video::EVST_VS_1_1, + psFileName, "pixelMain", video::EPST_PS_1_1, mc); + + mc->drop(); + } + + // set post processing material type to the quad + screenQuad->setMaterialType((video::E_MATERIAL_TYPE)ppMaterialType); + + /* + Now draw everything. That's all. + */ + + int lastFPS = -1; + + while(device->run()) + { + if (device->isWindowActive()) + { + driver->beginScene(true, true, video::SColor(255,0,0,0)); + + if (rt) + { + // draw scene into render target + + // set render target to RTT + driver->setRenderTarget(rt, true, true, video::SColor(255,0,0,0)); + + // draw scene to RTT just like normal rendering + smgr->drawAll(); + + // after rendering to RTT, we change render target back + driver->setRenderTarget(0, true, true, video::SColor(255,0,0,0)); + + // render screen quad to apply post processing + screenQuad->render(); + } + else + { + // draw scene normally + smgr->drawAll(); + } + + driver->endScene(); + + int fps = driver->getFPS(); + + if (lastFPS != fps) + { + core::stringw str = L"Irrlicht Engine - Post processing example ["; + str += driver->getName(); + str += "] FPS:"; + str += fps; + + device->setWindowCaption(str.c_str()); + lastFPS = fps; + } + } + } + + // do not forget to manually drop the screen quad + + screenQuad->drop(); + + device->drop(); + + return 0; +} + +/* +**/ diff --git a/examples/BuildAllExamples_vc10.sln b/examples/BuildAllExamples_vc10.sln index cc6667e3..52f85843 100644 --- a/examples/BuildAllExamples_vc10.sln +++ b/examples/BuildAllExamples_vc10.sln @@ -146,6 +146,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "25.XmlHandling", "25.XmlHan EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "30.Profiling", "30.Profiling\Profiling_vc10.vcxproj", "{65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "27.PostProcessing", "27.PostProcessing\PostProcessing_vc10.vcxproj", "{2B885150-210F-4CA7-957E-2C3D75974308}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -410,6 +412,14 @@ Global {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release|Win32.Build.0 = Release|Win32 {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release|x64.ActiveCfg = Release|x64 {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release|x64.Build.0 = Release|x64 + {2B885150-210F-4CA7-957E-2C3D75974308}.Debug|Win32.ActiveCfg = Debug|Win32 + {2B885150-210F-4CA7-957E-2C3D75974308}.Debug|Win32.Build.0 = Debug|Win32 + {2B885150-210F-4CA7-957E-2C3D75974308}.Debug|x64.ActiveCfg = Debug|x64 + {2B885150-210F-4CA7-957E-2C3D75974308}.Debug|x64.Build.0 = Debug|x64 + {2B885150-210F-4CA7-957E-2C3D75974308}.Release|Win32.ActiveCfg = Release|Win32 + {2B885150-210F-4CA7-957E-2C3D75974308}.Release|Win32.Build.0 = Release|Win32 + {2B885150-210F-4CA7-957E-2C3D75974308}.Release|x64.ActiveCfg = Release|x64 + {2B885150-210F-4CA7-957E-2C3D75974308}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/examples/BuildAllExamples_vc11.sln b/examples/BuildAllExamples_vc11.sln index 1722204c..25bfd7f5 100644 --- a/examples/BuildAllExamples_vc11.sln +++ b/examples/BuildAllExamples_vc11.sln @@ -149,6 +149,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "30.Profiling", "30.Profilin {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "27.PostProcessing", "27.PostProcessing\PostProcessing_vc11.vcxproj", "{F864F96D-F6AE-43E2-9A12-218B1A081255}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -413,6 +415,14 @@ Global {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release|Win32.Build.0 = Release|Win32 {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release|x64.ActiveCfg = Release|x64 {65D9DE2E-B73E-4ADF-96D1-BF4A8B7F4F97}.Release|x64.Build.0 = Release|x64 + {F864F96D-F6AE-43E2-9A12-218B1A081255}.Debug|Win32.ActiveCfg = Debug|Win32 + {F864F96D-F6AE-43E2-9A12-218B1A081255}.Debug|Win32.Build.0 = Debug|Win32 + {F864F96D-F6AE-43E2-9A12-218B1A081255}.Debug|x64.ActiveCfg = Debug|x64 + {F864F96D-F6AE-43E2-9A12-218B1A081255}.Debug|x64.Build.0 = Debug|x64 + {F864F96D-F6AE-43E2-9A12-218B1A081255}.Release|Win32.ActiveCfg = Release|Win32 + {F864F96D-F6AE-43E2-9A12-218B1A081255}.Release|Win32.Build.0 = Release|Win32 + {F864F96D-F6AE-43E2-9A12-218B1A081255}.Release|x64.ActiveCfg = Release|x64 + {F864F96D-F6AE-43E2-9A12-218B1A081255}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/examples/BuildAllExamples_vc12.sln b/examples/BuildAllExamples_vc12.sln index 4c87d9fc..b5a77416 100644 --- a/examples/BuildAllExamples_vc12.sln +++ b/examples/BuildAllExamples_vc12.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Express 2013 for Windows Desktop -VisualStudioVersion = 12.0.30501.0 +# Visual Studio 2013 +VisualStudioVersion = 12.0.40629.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "01.HelloWorld", "01.HelloWorld\HelloWorld_vc12.vcxproj", "{5AD4C95C-BA38-4692-BA4B-8C25A86208F9}" ProjectSection(ProjectDependencies) = postProject @@ -151,6 +151,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo", "Demo\Demo_vc12.vcxp EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Irrlicht", "..\source\Irrlicht\Irrlicht12.0.vcxproj", "{E08E042A-6C45-411B-92BE-3CC31331019F}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "27.PostProcessing", "27.PostProcessing\PostProcessing_vc12.vcxproj", "{17E74625-568E-4008-897E-CAD12A332B0C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -1065,6 +1067,34 @@ Global {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|Win32.Build.0 = Static lib - Release|Win32 {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|x64.ActiveCfg = Static lib - Release|x64 {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|x64.Build.0 = Static lib - Release|x64 + {17E74625-568E-4008-897E-CAD12A332B0C}.Debug|Win32.ActiveCfg = Debug|Win32 + {17E74625-568E-4008-897E-CAD12A332B0C}.Debug|Win32.Build.0 = Debug|Win32 + {17E74625-568E-4008-897E-CAD12A332B0C}.Debug|x64.ActiveCfg = Debug|x64 + {17E74625-568E-4008-897E-CAD12A332B0C}.Debug|x64.Build.0 = Debug|x64 + {17E74625-568E-4008-897E-CAD12A332B0C}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {17E74625-568E-4008-897E-CAD12A332B0C}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {17E74625-568E-4008-897E-CAD12A332B0C}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {17E74625-568E-4008-897E-CAD12A332B0C}.Release - Fast FPU|x64.Build.0 = Release|x64 + {17E74625-568E-4008-897E-CAD12A332B0C}.Release|Win32.ActiveCfg = Release|Win32 + {17E74625-568E-4008-897E-CAD12A332B0C}.Release|Win32.Build.0 = Release|Win32 + {17E74625-568E-4008-897E-CAD12A332B0C}.Release|x64.ActiveCfg = Release|x64 + {17E74625-568E-4008-897E-CAD12A332B0C}.Release|x64.Build.0 = Release|x64 + {17E74625-568E-4008-897E-CAD12A332B0C}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {17E74625-568E-4008-897E-CAD12A332B0C}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {17E74625-568E-4008-897E-CAD12A332B0C}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {17E74625-568E-4008-897E-CAD12A332B0C}.SDL-Debug|x64.Build.0 = Debug|x64 + {17E74625-568E-4008-897E-CAD12A332B0C}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {17E74625-568E-4008-897E-CAD12A332B0C}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {17E74625-568E-4008-897E-CAD12A332B0C}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {17E74625-568E-4008-897E-CAD12A332B0C}.Static lib - Debug|x64.Build.0 = Debug|x64 + {17E74625-568E-4008-897E-CAD12A332B0C}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {17E74625-568E-4008-897E-CAD12A332B0C}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {17E74625-568E-4008-897E-CAD12A332B0C}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {17E74625-568E-4008-897E-CAD12A332B0C}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {17E74625-568E-4008-897E-CAD12A332B0C}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {17E74625-568E-4008-897E-CAD12A332B0C}.Static lib - Release|Win32.Build.0 = Release|Win32 + {17E74625-568E-4008-897E-CAD12A332B0C}.Static lib - Release|x64.ActiveCfg = Release|x64 + {17E74625-568E-4008-897E-CAD12A332B0C}.Static lib - Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/examples/BuildAllExamples_vc14.sln b/examples/BuildAllExamples_vc14.sln index baa04847..9529fd64 100644 --- a/examples/BuildAllExamples_vc14.sln +++ b/examples/BuildAllExamples_vc14.sln @@ -1,7 +1,7 @@  -Microsoft Visual Studio Solution File, Format Version 14.00 +Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.23107.0 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "01.HelloWorld", "01.HelloWorld\HelloWorld_vc14.vcxproj", "{5AD4C95C-BA38-4692-BA4B-8C25A86208F9}" ProjectSection(ProjectDependencies) = postProject @@ -146,6 +146,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo", "Demo\Demo_vc14.vcxp EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Irrlicht", "..\source\Irrlicht\Irrlicht14.0.vcxproj", "{E08E042A-6C45-411B-92BE-3CC31331019F}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "27.PostProcessing", "27.PostProcessing\PostProcessing_vc14.vcxproj", "{F25F2AC4-AEDA-4A95-9769-01A2652B54A2}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -1032,6 +1034,34 @@ Global {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|Win32.Build.0 = Static lib - Release|Win32 {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|x64.ActiveCfg = Static lib - Release|x64 {E08E042A-6C45-411B-92BE-3CC31331019F}.Static lib - Release|x64.Build.0 = Static lib - Release|x64 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Debug|Win32.ActiveCfg = Debug|Win32 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Debug|Win32.Build.0 = Debug|Win32 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Debug|x64.ActiveCfg = Debug|x64 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Debug|x64.Build.0 = Debug|x64 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Release - Fast FPU|Win32.Build.0 = Release|Win32 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Release - Fast FPU|x64.ActiveCfg = Release|x64 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Release - Fast FPU|x64.Build.0 = Release|x64 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Release|Win32.ActiveCfg = Release|Win32 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Release|Win32.Build.0 = Release|Win32 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Release|x64.ActiveCfg = Release|x64 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Release|x64.Build.0 = Release|x64 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.SDL-Debug|Win32.ActiveCfg = Debug|Win32 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.SDL-Debug|Win32.Build.0 = Debug|Win32 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.SDL-Debug|x64.ActiveCfg = Debug|x64 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.SDL-Debug|x64.Build.0 = Debug|x64 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Static lib - Debug|Win32.ActiveCfg = Debug|Win32 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Static lib - Debug|Win32.Build.0 = Debug|Win32 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Static lib - Debug|x64.ActiveCfg = Debug|x64 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Static lib - Debug|x64.Build.0 = Debug|x64 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Static lib - Release - Fast FPU|Win32.ActiveCfg = Release|Win32 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Static lib - Release - Fast FPU|Win32.Build.0 = Release|Win32 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Static lib - Release - Fast FPU|x64.ActiveCfg = Release|x64 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Static lib - Release - Fast FPU|x64.Build.0 = Release|x64 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Static lib - Release|Win32.ActiveCfg = Release|Win32 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Static lib - Release|Win32.Build.0 = Release|Win32 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Static lib - Release|x64.ActiveCfg = Release|x64 + {F25F2AC4-AEDA-4A95-9769-01A2652B54A2}.Static lib - Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/examples/Demo/CDemo.cpp b/examples/Demo/CDemo.cpp index 553f85e1..49dd7b6e 100644 --- a/examples/Demo/CDemo.cpp +++ b/examples/Demo/CDemo.cpp @@ -427,7 +427,9 @@ void CDemo::loadSceneData() model1->setMaterialFlag(video::EMF_LIGHTING, false); model1->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true); model1->setMaterialType(video::EMT_SPHERE_MAP); - model1->addShadowVolumeSceneNode(); + model1->setAutomaticCulling(scene::EAC_OFF); // avoid shadows not updating + scene::IShadowVolumeSceneNode * shadVol = model1->addShadowVolumeSceneNode(); + shadVol->setOptimization(scene::ESV_NONE); // Sydney has broken shadows otherwise } model2 = sm->addAnimatedMeshSceneNode(mesh); @@ -439,7 +441,9 @@ void CDemo::loadSceneData() model2->setMaterialTexture(0, device->getVideoDriver()->getTexture(mediaPath + "sydney.bmp")); model2->setMaterialFlag(video::EMF_LIGHTING, true); model2->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true); - model2->addShadowVolumeSceneNode(); + model2->setAutomaticCulling(scene::EAC_OFF); // avoid shadows not updating + scene::IShadowVolumeSceneNode * shadVol = model2->addShadowVolumeSceneNode(); + shadVol->setOptimization(scene::ESV_NONE); // Sydney has broken shadows otherwise } } diff --git a/include/EDriverFeatures.h b/include/EDriverFeatures.h index 8f3438ca..6d7fee40 100644 --- a/include/EDriverFeatures.h +++ b/include/EDriverFeatures.h @@ -142,6 +142,9 @@ namespace video //! Support for filtering across different faces of the cubemap EVDF_TEXTURE_CUBEMAP_SEAMLESS, + //! Support for clamping vertices beyond far-plane to depth instead of capping them. + EVDF_DEPTH_CLAMP, + //! Only used for counting the elements of this enum EVDF_COUNT }; diff --git a/include/IAnimatedMeshSceneNode.h b/include/IAnimatedMeshSceneNode.h index 1652705c..5a399039 100644 --- a/include/IAnimatedMeshSceneNode.h +++ b/include/IAnimatedMeshSceneNode.h @@ -47,9 +47,7 @@ namespace scene virtual void OnAnimationEnd(IAnimatedMeshSceneNode* node) = 0; }; - //! Scene node capable of displaying an animated mesh and its shadow. - /** The shadow is optional: If a shadow should be displayed too, just - invoke the IAnimatedMeshSceneNode::createShadowVolumeSceneNode().*/ + //! Scene node capable of displaying an animated mesh. class IAnimatedMeshSceneNode : public ISceneNode { public: @@ -90,28 +88,31 @@ namespace scene /** \return Frames per second played. */ virtual f32 getAnimationSpeed() const =0; - //! Creates shadow volume scene node as child of this node. /** The shadow can be rendered using the ZPass or the zfail method. ZPass is a little bit faster because the shadow volume creation is easier, but with this method there occur ugly looking artifacts when the camera is inside the shadow volume. - These error do not occur with the ZFail method. + These error do not occur with the ZFail method, but it can + have trouble with clipping to the far-plane (it usually works + well in OpenGL and fails with other drivers). \param shadowMesh: Optional custom mesh for shadow volume. \param id: Id of the shadow scene node. This id can be used to identify the node later. \param zfailmethod: If set to true, the shadow will use the zfail method, if not, zpass is used. \param infinity: Value used by the shadow volume algorithm to - scale the shadow volume (for zfail shadow volume we support only - finite shadows, so camera zfar must be larger than shadow back cap, - which is depend on infinity parameter). + scale the shadow volume. For zfail shadow volumes on some drivers + only suppport finite shadows, so camera zfar must be larger than + shadow back cap,which is depending on the infinity parameter). + Infinity value also scales by the scaling factors of the model. + If shadows don't show up with zfail then try reducing infinity. + If shadows are cut-off then try increasing infinity. \return Pointer to the created shadow scene node. This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual IShadowVolumeSceneNode* addShadowVolumeSceneNode(const IMesh* shadowMesh=0, s32 id=-1, bool zfailmethod=true, f32 infinity=1000.0f) = 0; - //! Get a pointer to a joint in the mesh (if the mesh is a bone based mesh). /** With this method it is possible to attach scene nodes to joints for example possible to attach a weapon to the left hand diff --git a/include/ICameraSceneNode.h b/include/ICameraSceneNode.h index e289628a..2743dae8 100644 --- a/include/ICameraSceneNode.h +++ b/include/ICameraSceneNode.h @@ -38,6 +38,8 @@ namespace scene Note that the matrix will only stay as set by this method until one of the following Methods are called: setNearValue, setFarValue, setAspectRatio, setFOV. + NOTE: The frustum is not updated before render() is called + unless you explicitly call updateMatrices() \param projection The new projection matrix of the camera. \param isOrthogonal Set this to true if the matrix is an orthogonal one (e.g. from matrix4::buildProjectionMatrixOrtho). diff --git a/include/IMeshSceneNode.h b/include/IMeshSceneNode.h index 2fc70396..03c5c522 100644 --- a/include/IMeshSceneNode.h +++ b/include/IMeshSceneNode.h @@ -38,21 +38,25 @@ public: /** \return Pointer to mesh which is displayed by this node. */ virtual IMesh* getMesh(void) = 0; - //! Creates shadow volume scene node as child of this node. /** The shadow can be rendered using the ZPass or the zfail method. ZPass is a little bit faster because the shadow volume creation is easier, but with this method there occur ugly looking artifacts when the camera is inside the shadow volume. - These error do not occur with the ZFail method. + These error do not occur with the ZFail method, but it can + have trouble with clipping to the far-plane (it usually works + well in OpenGL and fails with other drivers). \param shadowMesh: Optional custom mesh for shadow volume. \param id: Id of the shadow scene node. This id can be used to identify the node later. \param zfailmethod: If set to true, the shadow will use the zfail method, if not, zpass is used. \param infinity: Value used by the shadow volume algorithm to - scale the shadow volume (for zfail shadow volume we support only - finite shadows, so camera zfar must be larger than shadow back cap, - which is depend on infinity parameter). + scale the shadow volume. For zfail shadow volumes on some drivers + only suppport finite shadows, so camera zfar must be larger than + shadow back cap,which is depending on the infinity parameter). + Infinity value also scales by the scaling factors of the model. + If shadows don't show up with zfail then try reducing infinity. + If shadows are cut-off then try increasing infinity. \return Pointer to the created shadow scene node. This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ diff --git a/include/IShadowVolumeSceneNode.h b/include/IShadowVolumeSceneNode.h index 82c2ad32..f19e6aab 100644 --- a/include/IShadowVolumeSceneNode.h +++ b/include/IShadowVolumeSceneNode.h @@ -13,6 +13,22 @@ namespace scene { class IMesh; + enum ESHADOWVOLUME_OPTIMIZATION + { + //! Create volumes around every triangle + ESV_NONE, + + //! Create volumes only around the silhouette of the mesh + /** This can reduce the number of volumes drastically, + but will have an upfront-cost where it calculates adjacency of + triangles. Also it will not work with all models. Basically + if you see strange black shadow lines then you have a model + for which it won't work. + We get that information about adjacency by comparing the positions of + all edges in the mesh (even if they are in different meshbuffers). */ + ESV_SILHOUETTE_BY_POS + }; + //! Scene node for rendering a shadow volume into a stencil buffer. class IShadowVolumeSceneNode : public ISceneNode { @@ -29,6 +45,17 @@ namespace scene //! Updates the shadow volumes for current light positions. virtual void updateShadowVolumes() = 0; + + //! Set optimization used to create shadow volumes + /** Default is ESV_SILHOUETTE_BY_POS. If the shadow + looks bad then give ESV_NONE a try (which will be slower). + Alternatively you can try to fix the model, it's often + because it's not closed (aka if you'd put water in it then + that would leak out). */ + virtual void setOptimization(ESHADOWVOLUME_OPTIMIZATION optimization) = 0; + + //! Get currently active optimization used to create shadow volumes + virtual ESHADOWVOLUME_OPTIMIZATION getOptimization() const = 0; }; } // end namespace scene diff --git a/media/027shot.jpg b/media/027shot.jpg new file mode 100644 index 00000000..274bada7 Binary files /dev/null and b/media/027shot.jpg differ diff --git a/media/pp_d3d9.hlsl b/media/pp_d3d9.hlsl new file mode 100644 index 00000000..33d47ec9 --- /dev/null +++ b/media/pp_d3d9.hlsl @@ -0,0 +1,43 @@ + +// Texture size to calculate texel center +float2 TextureSize; + +// Vertex shader output struct +struct VS_OUTPUT +{ + float4 Position : POSITION0; + float2 TexCoords : TEXCOORD0; +}; + +VS_OUTPUT vertexMain( + float4 Position : POSITION0, + float2 TexCoords : TEXCOORD0 + ) +{ + VS_OUTPUT OUT; + OUT.Position = Position; + + // In practice, instead of passing in TextureSize, + // pass 1.0 / TextureSize for better performance + + // TexCoords is set to the texel center + OUT.TexCoords = TexCoords + 1.0 / TextureSize / 2.0; + + return OUT; +} + +// Texture sampler +sampler2D TextureSampler; + +float4 pixelMain ( float2 Texcoords : TEXCOORD0 ) : COLOR0 +{ + // Texture is sampled at Texcoords using tex2D + float4 Color = tex2D(TextureSampler, Texcoords); + + // Change Texcoords to sample pixels around + + // Inverse the color to produce negative image effect + Color.rgb = 1.0 - Color.rgb; + + return Color; +}; diff --git a/media/pp_opengl.frag b/media/pp_opengl.frag new file mode 100644 index 00000000..85ab768a --- /dev/null +++ b/media/pp_opengl.frag @@ -0,0 +1,17 @@ + +// Texture sampler +uniform sampler2D TextureSampler; + +// TexCoords from vertex shader +varying vec2 TexCoords; + +void main (void) +{ + // Texture is sampled at Texcoords using texture2D + vec4 Color = texture2D(TextureSampler, TexCoords); + + // Inverse the color to produce negative image effect + Color.rgb = 1.0 - Color.rgb; + + gl_FragColor = Color; +} \ No newline at end of file diff --git a/media/pp_opengl.vert b/media/pp_opengl.vert new file mode 100644 index 00000000..d1c9ae66 --- /dev/null +++ b/media/pp_opengl.vert @@ -0,0 +1,24 @@ + +// Pass to fragment shader with the same name +varying vec2 TexCoords; + +void main(void) +{ + gl_Position = gl_Vertex; + + // The origin of the texture coordinates locates at bottom-left + // corner rather than top-left corner as defined on screen quad. + // Instead of using texture coordinates passed in by OpenGL, we + // calculate TexCoords based on vertex position as follows. + // + // Vertex[0] (-1, -1) to (0, 0) + // Vertex[1] (-1, 1) to (0, 1) + // Vertex[2] ( 1, 1) to (1, 1) + // Vertex[3] ( 1, -1) to (1, 0) + // + // Texture coordinate system in OpenGL operates differently from + // DirectX 3D. It is not necessary to offset TexCoords to texel + // center by adding 1.0 / TextureSize / 2.0 + + TexCoords = (gl_Vertex.xy * 0.5 + 0.5); +} diff --git a/source/Irrlicht/CAnimatedMeshSceneNode.cpp b/source/Irrlicht/CAnimatedMeshSceneNode.cpp index 5e7a3393..d8c8491d 100644 --- a/source/Irrlicht/CAnimatedMeshSceneNode.cpp +++ b/source/Irrlicht/CAnimatedMeshSceneNode.cpp @@ -533,11 +533,7 @@ const core::aabbox3d& CAnimatedMeshSceneNode::getBoundingBox() const } -//! returns the material based on the zero based index i. To get the amount -//! of materials used by this scene node, use getMaterialCount(). -//! This function is needed for inserting the node into the scene hirachy on a -//! optimal position for minimizing renderstate changes, but can also be used -//! to directly modify the material of a scene node. +//! returns the material based on the zero based index i. video::SMaterial& CAnimatedMeshSceneNode::getMaterial(u32 i) { if (i >= Materials.size()) diff --git a/source/Irrlicht/CAnimatedMeshSceneNode.h b/source/Irrlicht/CAnimatedMeshSceneNode.h index fe9011e9..6a5914e9 100644 --- a/source/Irrlicht/CAnimatedMeshSceneNode.h +++ b/source/Irrlicht/CAnimatedMeshSceneNode.h @@ -70,7 +70,7 @@ namespace scene //! returns the material based on the zero based index i. To get the amount //! of materials used by this scene node, use getMaterialCount(). - //! This function is needed for inserting the node into the scene hirachy on a + //! This function is needed for inserting the node into the scene hierarchy on a //! optimal position for minimizing renderstate changes, but can also be used //! to directly modify the material of a scene node. virtual video::SMaterial& getMaterial(u32 i) _IRR_OVERRIDE_; @@ -84,7 +84,7 @@ namespace scene s32 id, bool zfailmethod=true, f32 infinity=1000.0f) _IRR_OVERRIDE_; //! Returns a pointer to a child node, which has the same transformation as - //! the corrsesponding joint, if the mesh in this scene node is a skinned mesh. + //! the corresponding joint, if the mesh in this scene node is a skinned mesh. virtual IBoneSceneNode* getJointNode(const c8* jointName) _IRR_OVERRIDE_; //! same as getJointNode(const c8* jointName), but based on id @@ -95,7 +95,7 @@ namespace scene //! Removes a child from this scene node. //! Implemented here, to be able to remove the shadow properly, if there is one, - //! or to remove attached childs. + //! or to remove attached child. virtual bool removeChild(ISceneNode* child) _IRR_OVERRIDE_; //! Starts a MD2 animation. diff --git a/source/Irrlicht/CCubeSceneNode.h b/source/Irrlicht/CCubeSceneNode.h index 8f8aba82..f8ad068f 100644 --- a/source/Irrlicht/CCubeSceneNode.h +++ b/source/Irrlicht/CCubeSceneNode.h @@ -34,7 +34,7 @@ namespace scene //! returns the material based on the zero based index i. To get the amount //! of materials used by this scene node, use getMaterialCount(). - //! This function is needed for inserting the node into the scene hirachy on a + //! This function is needed for inserting the node into the scene hierarchy on a //! optimal position for minimizing renderstate changes, but can also be used //! to directly modify the material of a scene node. virtual video::SMaterial& getMaterial(u32 i) _IRR_OVERRIDE_; @@ -75,7 +75,7 @@ namespace scene //! Removes a child from this scene node. //! Implemented here, to be able to remove the shadow properly, if there is one, - //! or to remove attached childs. + //! or to remove attached child. virtual bool removeChild(ISceneNode* child) _IRR_OVERRIDE_; private: diff --git a/source/Irrlicht/CD3D9Driver.cpp b/source/Irrlicht/CD3D9Driver.cpp index 8f9b24f1..98501b39 100644 --- a/source/Irrlicht/CD3D9Driver.cpp +++ b/source/Irrlicht/CD3D9Driver.cpp @@ -2408,9 +2408,8 @@ void CD3D9Driver::setRenderStatesStencilShadowMode(bool zfail, u32 debugDataVisi pID3DDevice->SetRenderState(D3DRS_STENCILMASK, 0xffffffff); pID3DDevice->SetRenderState(D3DRS_STENCILWRITEMASK, 0xffffffff); - pID3DDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); - pID3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ZERO ); - pID3DDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE ); + BridgeCalls->setBlend(true); + BridgeCalls->setBlendFunc(D3DBLEND_ZERO, D3DBLEND_ONE); pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESS); diff --git a/source/Irrlicht/CD3D9Driver.h b/source/Irrlicht/CD3D9Driver.h index f607c553..d066f8e5 100644 --- a/source/Irrlicht/CD3D9Driver.h +++ b/source/Irrlicht/CD3D9Driver.h @@ -321,7 +321,7 @@ namespace video private: - //! enumeration for rendering modes such as 2d and 3d for minizing the switching of renderStates. + //! enumeration for rendering modes such as 2d and 3d for minimizing the switching of renderStates. enum E_RENDER_MODE { ERM_NONE = 0, // no render state has been set yet. @@ -415,7 +415,7 @@ namespace video bool Transformation3DChanged; const ITexture* CurrentTexture[MATERIAL_MAX_TEXTURES]; bool LastTextureMipMapsAvailable[MATERIAL_MAX_TEXTURES]; - core::matrix4 Matrices[ETS_COUNT]; // matrizes of the 3d mode we need to restore when we switch back from the 2d mode. + core::matrix4 Matrices[ETS_COUNT]; // matrices of the 3d mode we need to restore when we switch back from the 2d mode. HINSTANCE D3DLibrary; IDirect3D9* pID3D; @@ -459,7 +459,7 @@ namespace video bool AlphaToCoverageSupport; }; - //! This bridge between Irlicht pseudo D3D9 calls + //! This bridge between Irrlicht pseudo D3D9 calls //! and true D3D9 calls. class CD3D9CallBridge diff --git a/source/Irrlicht/CMeshSceneNode.h b/source/Irrlicht/CMeshSceneNode.h index 329bacca..b7b10be3 100644 --- a/source/Irrlicht/CMeshSceneNode.h +++ b/source/Irrlicht/CMeshSceneNode.h @@ -37,7 +37,7 @@ namespace scene //! returns the material based on the zero based index i. To get the amount //! of materials used by this scene node, use getMaterialCount(). - //! This function is needed for inserting the node into the scene hirachy on a + //! This function is needed for inserting the node into the scene hierarchy on a //! optimal position for minimizing renderstate changes, but can also be used //! to directly modify the material of a scene node. virtual video::SMaterial& getMaterial(u32 i) _IRR_OVERRIDE_; @@ -78,7 +78,7 @@ namespace scene //! Removes a child from this scene node. //! Implemented here, to be able to remove the shadow properly, if there is one, - //! or to remove attached childs. + //! or to remove attached child. virtual bool removeChild(ISceneNode* child) _IRR_OVERRIDE_; protected: diff --git a/source/Irrlicht/COctreeSceneNode.cpp b/source/Irrlicht/COctreeSceneNode.cpp index 79a1a1e2..63e9e43d 100644 --- a/source/Irrlicht/COctreeSceneNode.cpp +++ b/source/Irrlicht/COctreeSceneNode.cpp @@ -579,11 +579,7 @@ bool COctreeSceneNode::createTree(IMesh* mesh) } -//! returns the material based on the zero based index i. To get the amount -//! of materials used by this scene node, use getMaterialCount(). -//! This function is needed for inserting the node into the scene hirachy on a -//! optimal position for minimizing renderstate changes, but can also be used -//! to directly modify the material of a scene node. +//! returns the material based on the zero based index i. video::SMaterial& COctreeSceneNode::getMaterial(u32 i) { if ( i >= Materials.size() ) diff --git a/source/Irrlicht/COctreeSceneNode.h b/source/Irrlicht/COctreeSceneNode.h index 87509869..89de7eda 100644 --- a/source/Irrlicht/COctreeSceneNode.h +++ b/source/Irrlicht/COctreeSceneNode.h @@ -75,7 +75,7 @@ namespace scene //! Removes a child from this scene node. //! Implemented here, to be able to remove the shadow properly, if there is one, - //! or to remove attached children. + //! or to remove attached child. virtual bool removeChild(ISceneNode* child) _IRR_OVERRIDE_; //! Set if/how vertex buffer object are used for the meshbuffers diff --git a/source/Irrlicht/COpenGLDriver.cpp b/source/Irrlicht/COpenGLDriver.cpp index 782c8f19..154261e7 100644 --- a/source/Irrlicht/COpenGLDriver.cpp +++ b/source/Irrlicht/COpenGLDriver.cpp @@ -3289,6 +3289,11 @@ void COpenGLDriver::drawStencilShadowVolume(const core::array& #ifdef GL_NV_depth_clamp if (FeatureAvailable[IRR_NV_depth_clamp]) glEnable(GL_DEPTH_CLAMP_NV); +#elif defined(GL_ARB_depth_clamp) + if (FeatureAvailable[IRR_ARB_depth_clamp]) + { + glEnable(GL_DEPTH_CLAMP); + } #endif // The first parts are not correctly working, yet. @@ -3370,6 +3375,11 @@ void COpenGLDriver::drawStencilShadowVolume(const core::array& #ifdef GL_NV_depth_clamp if (FeatureAvailable[IRR_NV_depth_clamp]) glDisable(GL_DEPTH_CLAMP_NV); +#elif defined(GL_ARB_depth_clamp) + if (FeatureAvailable[IRR_ARB_depth_clamp]) + { + glDisable(GL_DEPTH_CLAMP); + } #endif glDisable(GL_POLYGON_OFFSET_FILL); diff --git a/source/Irrlicht/COpenGLExtensionHandler.cpp b/source/Irrlicht/COpenGLExtensionHandler.cpp index 3416da24..16162640 100644 --- a/source/Irrlicht/COpenGLExtensionHandler.cpp +++ b/source/Irrlicht/COpenGLExtensionHandler.cpp @@ -863,6 +863,9 @@ bool COpenGLExtensionHandler::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const return (Version >= 130) || FeatureAvailable[IRR_ARB_texture_cube_map] || FeatureAvailable[IRR_EXT_texture_cube_map]; case EVDF_TEXTURE_CUBEMAP_SEAMLESS: return FeatureAvailable[IRR_ARB_seamless_cube_map]; + case EVDF_DEPTH_CLAMP: + return FeatureAvailable[IRR_NV_depth_clamp] || FeatureAvailable[IRR_ARB_depth_clamp]; + default: return false; }; diff --git a/source/Irrlicht/CShadowVolumeSceneNode.cpp b/source/Irrlicht/CShadowVolumeSceneNode.cpp index 2f2a2971..9c7b3ab1 100644 --- a/source/Irrlicht/CShadowVolumeSceneNode.cpp +++ b/source/Irrlicht/CShadowVolumeSceneNode.cpp @@ -25,8 +25,9 @@ namespace scene CShadowVolumeSceneNode::CShadowVolumeSceneNode(const IMesh* shadowMesh, ISceneNode* parent, ISceneManager* mgr, s32 id, bool zfailmethod, f32 infinity) : IShadowVolumeSceneNode(parent, mgr, id), + AdjacencyDirtyFlag(true), ShadowMesh(0), IndexCount(0), VertexCount(0), ShadowVolumesUsed(0), - Infinity(infinity), UseZFailMethod(zfailmethod) + Infinity(infinity), UseZFailMethod(zfailmethod), Optimization(ESV_SILHOUETTE_BY_POS) { #ifdef _DEBUG setDebugName("CShadowVolumeSceneNode"); @@ -75,15 +76,22 @@ void CShadowVolumeSceneNode::createShadowVolume(const core::vector3df& light, bo Edges.set_used(IndexCount*2); u32 numEdges = 0; - numEdges=createEdgesAndCaps(light, svp, bb); + numEdges=createEdgesAndCaps(light, isDirectional, svp, bb); // for all edges add the near->far quads + core::vector3df lightDir1(light*Infinity); + core::vector3df lightDir2(light*Infinity); for (u32 i=0; i* bb) { u32 numEdges=0; @@ -116,16 +128,37 @@ u32 CShadowVolumeSceneNode::createEdgesAndCaps(const core::vector3df& light, bb->reset(0,0,0); // Check every face if it is front or back facing the light. + core::vector3df lightDir0(light); + core::vector3df lightDir1(light); + core::vector3df lightDir2(light); for (u32 i=0; igetVideoDriver()->setMaterial(m); +#ifdef IRR_USE_REVERSE_EXTRUDED + SceneManager->getVideoDriver()->draw3DTriangle(core::triangle3df(v0+lightDir0,v1+lightDir0,v2+lightDir0), irr::video::SColor(255,255, 0, 0)); +#else + SceneManager->getVideoDriver()->draw3DTriangle(core::triangle3df(v0-lightDir0,v1-lightDir0,v2-lightDir0), irr::video::SColor(255,255, 0, 0)); +#endif + } #endif if (UseZFailMethod && FaceData[i]) @@ -140,9 +173,14 @@ u32 CShadowVolumeSceneNode::createEdgesAndCaps(const core::vector3df& light, svp->push_back(v0); // add back cap - const core::vector3df i0 = v0+(v0-light).normalize()*Infinity; - const core::vector3df i1 = v1+(v1-light).normalize()*Infinity; - const core::vector3df i2 = v2+(v2-light).normalize()*Infinity; + if ( !isDirectional ) + { + lightDir1 = (v1-light).normalize(); + lightDir2 = (v2-light).normalize(); + } + const core::vector3df i0 = v0+lightDir0*Infinity; + const core::vector3df i1 = v1+lightDir1*Infinity; + const core::vector3df i2 = v2+lightDir2*Infinity; svp->push_back(i0); svp->push_back(i1); @@ -164,41 +202,55 @@ u32 CShadowVolumeSceneNode::createEdgesAndCaps(const core::vector3df& light, const u16 wFace1 = Indices[3*i+1]; const u16 wFace2 = Indices[3*i+2]; - const u16 adj0 = Adjacency[3*i+0]; - const u16 adj1 = Adjacency[3*i+1]; - const u16 adj2 = Adjacency[3*i+2]; - - // add edges if face is adjacent to back-facing face - // or if no adjacent face was found -#ifdef IRR_USE_ADJACENCY - if (adj0 == i || FaceData[adj0] == false) -#endif + if ( Optimization == ESV_NONE ) { // add edge v0-v1 Edges[2*numEdges+0] = wFace0; Edges[2*numEdges+1] = wFace1; ++numEdges; - } -#ifdef IRR_USE_ADJACENCY - if (adj1 == i || FaceData[adj1] == false) -#endif - { // add edge v1-v2 Edges[2*numEdges+0] = wFace1; Edges[2*numEdges+1] = wFace2; ++numEdges; - } -#ifdef IRR_USE_ADJACENCY - if (adj2 == i || FaceData[adj2] == false) -#endif - { // add edge v2-v0 Edges[2*numEdges+0] = wFace2; Edges[2*numEdges+1] = wFace0; ++numEdges; } + else + { + const u16 adj0 = Adjacency[3*i+0]; + const u16 adj1 = Adjacency[3*i+1]; + const u16 adj2 = Adjacency[3*i+2]; + + // add edges if face is adjacent to back-facing face + // or if no adjacent face was found + if (adj0 == i || FaceData[adj0] == false) + { + // add edge v0-v1 + Edges[2*numEdges+0] = wFace0; + Edges[2*numEdges+1] = wFace1; + ++numEdges; + } + + if (adj1 == i || FaceData[adj1] == false) + { + // add edge v1-v2 + Edges[2*numEdges+0] = wFace1; + Edges[2*numEdges+1] = wFace2; + ++numEdges; + } + + if (adj2 == i || FaceData[adj2] == false) + { + // add edge v2-v0 + Edges[2*numEdges+0] = wFace2; + Edges[2*numEdges+1] = wFace0; + ++numEdges; + } + } } } return numEdges; @@ -225,6 +277,10 @@ void CShadowVolumeSceneNode::updateShadowVolumes() const u32 oldIndexCount = IndexCount; const u32 oldVertexCount = VertexCount; + VertexCount = 0; + IndexCount = 0; + ShadowVolumesUsed = 0; + const IMesh* const mesh = ShadowMesh; if (!mesh) return; @@ -237,10 +293,6 @@ void CShadowVolumeSceneNode::updateShadowVolumes() // calculate total amount of vertices and indices - VertexCount = 0; - IndexCount = 0; - ShadowVolumesUsed = 0; - u32 i; u32 totalVertices = 0; u32 totalIndices = 0; @@ -249,8 +301,24 @@ void CShadowVolumeSceneNode::updateShadowVolumes() for (i=0; igetMeshBuffer(i); - totalIndices += buf->getIndexCount(); - totalVertices += buf->getVertexCount(); + if ( buf->getIndexType() == video::EIT_16BIT + && buf->getPrimitiveType() == scene::EPT_TRIANGLES ) + { + totalIndices += buf->getIndexCount(); + totalVertices += buf->getVertexCount(); + } + else + { + os::Printer::log("ShadowVolumeSceneNode only supports meshbuffers with 16 bit indices and triangles", ELL_WARNING); + return; + } + } + if ( totalIndices != (u32)(u16)totalIndices) + { + // We could switch to 32-bit indices, not much work and just bit of extra memory (< 192k) per shadow volume. + // If anyone ever complains and really needs that just switch it. But huge shadows are usually a bad idea as they will be slow. + os::Printer::log("ShadowVolumeSceneNode does not yet support shadowvolumes which need more than 16 bit indices", ELL_WARNING); + return; } // allocate memory if necessary @@ -259,7 +327,8 @@ void CShadowVolumeSceneNode::updateShadowVolumes() Indices.set_used(totalIndices); FaceData.set_used(totalIndices / 3); - // copy mesh + // copy mesh + // (could speed this up for static meshes by adding some user flag to prevents copying) for (i=0; igetMeshBuffer(i); @@ -275,27 +344,45 @@ void CShadowVolumeSceneNode::updateShadowVolumes() } // recalculate adjacency if necessary - if (oldVertexCount != VertexCount || oldIndexCount != IndexCount) + if (oldVertexCount != VertexCount || oldIndexCount != IndexCount || AdjacencyDirtyFlag) calculateAdjacency(); - core::matrix4 mat = Parent->getAbsoluteTransformation(); - mat.makeInverse(); + core::matrix4 matInv(Parent->getAbsoluteTransformation()); + matInv.makeInverse(); + core::matrix4 matTransp(Parent->getAbsoluteTransformation(), core::matrix4::EM4CONST_TRANSPOSED); const core::vector3df parentpos = Parent->getAbsolutePosition(); - // TODO: Only correct for point lights. for (i=0; igetVideoDriver()->getDynamicLight(i); - core::vector3df lpos = dl.Position; - if (dl.CastShadows && - fabs((lpos - parentpos).getLengthSQ()) <= (dl.Radius*dl.Radius*4.0f)) + + if ( dl.Type == video::ELT_DIRECTIONAL ) { - mat.transformVect(lpos); - createShadowVolume(lpos); + core::vector3df ldir(dl.Direction); + matTransp.transformVect(ldir); + createShadowVolume(ldir, true); + } + else + { + core::vector3df lpos(dl.Position); + if (dl.CastShadows && + fabs((lpos - parentpos).getLengthSQ()) <= (dl.Radius*dl.Radius*4.0f)) + { + matInv.transformVect(lpos); + createShadowVolume(lpos, false); + } } } } +void CShadowVolumeSceneNode::setOptimization(ESHADOWVOLUME_OPTIMIZATION optimization) +{ + if ( Optimization != optimization ) + { + Optimization = optimization; + AdjacencyDirtyFlag = true; + } +} //! pre render method void CShadowVolumeSceneNode::OnRegisterSceneNode() @@ -317,45 +404,55 @@ void CShadowVolumeSceneNode::render() driver->setTransform(video::ETS_WORLD, Parent->getAbsoluteTransformation()); + bool checkFarPlaneClipping = UseZFailMethod && !driver->queryFeature(video::EVDF_DEPTH_CLAMP); + + // get camera frustum converted to local coordinates when we have to check for far plane clipping + SViewFrustum frust; + if ( checkFarPlaneClipping ) + { + const irr::scene::ICameraSceneNode* camera = SceneManager->getActiveCamera(); + if ( camera ) + { + frust = *camera->getViewFrustum(); + core::matrix4 invTrans(Parent->getAbsoluteTransformation(), core::matrix4::EM4CONST_INVERSE); + frust.transform(invTrans); + } + else + checkFarPlaneClipping = false; + } + for (u32 i=0; igetActiveCamera()) + if (checkFarPlaneClipping) { // Disable shadows drawing, when back cap is behind of ZFar plane. - - SViewFrustum frust = *SceneManager->getActiveCamera()->getViewFrustum(); - - core::matrix4 invTrans(Parent->getAbsoluteTransformation(), core::matrix4::EM4CONST_INVERSE); - frust.transform(invTrans); + // TODO: Using infinite projection matrices instead is said to work better + // as then we wouldn't fail when the shadow clip the far plane. + // I couldn't get it working (and neither anyone before me it seems). + // Anyone who can figure it out is welcome to provide a patch. core::vector3df edges[8]; ShadowBBox[i].getEdges(edges); - core::vector3df largestEdge = edges[0]; - f32 maxDistance = core::vector3df(SceneManager->getActiveCamera()->getPosition() - edges[0]).getLength(); - f32 curDistance = 0.f; - - for(int j = 1; j < 8; ++j) + for(int j = 0; j < 8; ++j) { - curDistance = core::vector3df(SceneManager->getActiveCamera()->getPosition() - edges[j]).getLength(); - - if(curDistance > maxDistance) + if (frust.planes[scene::SViewFrustum::VF_FAR_PLANE].classifyPointRelation(edges[j]) == core::ISREL3D_FRONT) { - maxDistance = curDistance; - largestEdge = edges[j]; + drawShadow = false; + break; } } - - if (!(frust.planes[scene::SViewFrustum::VF_FAR_PLANE].classifyPointRelation(largestEdge) != core::ISREL3D_FRONT)) - drawShadow = false; } if(drawShadow) driver->drawStencilShadowVolume(ShadowVolumes[i], UseZFailMethod, DebugDataVisible); else { + // TODO: For some reason (not yet further investigated), Direct3D needs a call to drawStencilShadowVolume + // even if we have nothing to draw here to set the renderstate into a StencilShadowMode. + // If that's not done it has effect on further render calls. core::array triangles; driver->drawStencilShadowVolume(triangles, UseZFailMethod, DebugDataVisible); } @@ -373,47 +470,56 @@ const core::aabbox3d& CShadowVolumeSceneNode::getBoundingBox() const //! Generates adjacency information based on mesh indices. void CShadowVolumeSceneNode::calculateAdjacency() { - Adjacency.set_used(IndexCount); + AdjacencyDirtyFlag = false; - // go through all faces and fetch their three neighbours - for (u32 f=0; f store face number, else store adjacent face - if (of >= IndexCount) - Adjacency[f + edge] = f/3; - else - Adjacency[f + edge] = of/3; + // no adjacent edges -> store face number, else store adjacent face + if (of >= IndexCount) + Adjacency[f + edge] = f/3; + else + Adjacency[f + edge] = of/3; + } } } } diff --git a/source/Irrlicht/CShadowVolumeSceneNode.h b/source/Irrlicht/CShadowVolumeSceneNode.h index 92b4ac21..6501652e 100644 --- a/source/Irrlicht/CShadowVolumeSceneNode.h +++ b/source/Irrlicht/CShadowVolumeSceneNode.h @@ -33,6 +33,17 @@ namespace scene /** Called each render cycle from Animated Mesh SceneNode render method. */ virtual void updateShadowVolumes() _IRR_OVERRIDE_; + //! Set optimization used to create shadow volumes + /** Default is ESV_SILHOUETTE_BY_POS. If the shadow + looks bad then give ESV_NONE a try (which will be slower). */ + virtual void setOptimization(ESHADOWVOLUME_OPTIMIZATION optimization) _IRR_OVERRIDE_; + + //! Get currently active optimization used to create shadow volumes + virtual ESHADOWVOLUME_OPTIMIZATION getOptimization() const _IRR_OVERRIDE_ + { + return Optimization; + } + //! pre render method virtual void OnRegisterSceneNode() _IRR_OVERRIDE_; @@ -49,8 +60,8 @@ namespace scene typedef core::array SShadowVolume; - void createShadowVolume(const core::vector3df& pos, bool isDirectional=false); - u32 createEdgesAndCaps(const core::vector3df& light, SShadowVolume* svp, core::aabbox3d* bb); + void createShadowVolume(const core::vector3df& pos, bool isDirectional); + u32 createEdgesAndCaps(const core::vector3df& light, bool isDirectional, SShadowVolume* svp, core::aabbox3d* bb); //! Generates adjacency information based on mesh indices. void calculateAdjacency(); @@ -69,6 +80,7 @@ namespace scene core::array Edges; // tells if face is front facing core::array FaceData; + bool AdjacencyDirtyFlag; const scene::IMesh* ShadowMesh; @@ -77,8 +89,8 @@ namespace scene u32 ShadowVolumesUsed; f32 Infinity; - bool UseZFailMethod; + ESHADOWVOLUME_OPTIMIZATION Optimization; }; } // end namespace scene diff --git a/source/Irrlicht/CSkyBoxSceneNode.cpp b/source/Irrlicht/CSkyBoxSceneNode.cpp index ca66fcdf..de41f03d 100644 --- a/source/Irrlicht/CSkyBoxSceneNode.cpp +++ b/source/Irrlicht/CSkyBoxSceneNode.cpp @@ -221,11 +221,7 @@ void CSkyBoxSceneNode::OnRegisterSceneNode() } -//! returns the material based on the zero based index i. To get the amount -//! of materials used by this scene node, use getMaterialCount(). -//! This function is needed for inserting the node into the scene hirachy on a -//! optimal position for minimizing renderstate changes, but can also be used -//! to directly modify the material of a scene node. +//! returns the material based on the zero based index i. video::SMaterial& CSkyBoxSceneNode::getMaterial(u32 i) { return Material[i]; diff --git a/source/Irrlicht/CSkyBoxSceneNode.h b/source/Irrlicht/CSkyBoxSceneNode.h index 3acaa390..a153b50a 100644 --- a/source/Irrlicht/CSkyBoxSceneNode.h +++ b/source/Irrlicht/CSkyBoxSceneNode.h @@ -33,7 +33,7 @@ namespace scene //! returns the material based on the zero based index i. To get the amount //! of materials used by this scene node, use getMaterialCount(). - //! This function is needed for inserting the node into the scene hirachy on a + //! This function is needed for inserting the node into the scene hierarchy on a //! optimal position for minimizing renderstate changes, but can also be used //! to directly modify the material of a scene node. virtual video::SMaterial& getMaterial(u32 i) _IRR_OVERRIDE_; diff --git a/source/Irrlicht/CSkyDomeSceneNode.cpp b/source/Irrlicht/CSkyDomeSceneNode.cpp index 410a0952..7b6affe0 100644 --- a/source/Irrlicht/CSkyDomeSceneNode.cpp +++ b/source/Irrlicht/CSkyDomeSceneNode.cpp @@ -197,11 +197,7 @@ void CSkyDomeSceneNode::OnRegisterSceneNode() } -//! returns the material based on the zero based index i. To get the amount -//! of materials used by this scene node, use getMaterialCount(). -//! This function is needed for inserting the node into the scene hirachy on a -//! optimal position for minimizing renderstate changes, but can also be used -//! to directly modify the material of a scene node. +//! returns the material based on the zero based index i. video::SMaterial& CSkyDomeSceneNode::getMaterial(u32 i) { return Buffer->Material; diff --git a/source/Irrlicht/CSphereSceneNode.cpp b/source/Irrlicht/CSphereSceneNode.cpp index 7dbe814d..1693f5e2 100644 --- a/source/Irrlicht/CSphereSceneNode.cpp +++ b/source/Irrlicht/CSphereSceneNode.cpp @@ -123,11 +123,7 @@ void CSphereSceneNode::OnRegisterSceneNode() } -//! returns the material based on the zero based index i. To get the amount -//! of materials used by this scene node, use getMaterialCount(). -//! This function is needed for inserting the node into the scene hirachy on a -//! optimal position for minimizing renderstate changes, but can also be used -//! to directly modify the material of a scene node. +//! returns the material based on the zero based index i. video::SMaterial& CSphereSceneNode::getMaterial(u32 i) { if (i>0 || !Mesh) diff --git a/source/Irrlicht/CSphereSceneNode.h b/source/Irrlicht/CSphereSceneNode.h index 904cb508..480881cb 100644 --- a/source/Irrlicht/CSphereSceneNode.h +++ b/source/Irrlicht/CSphereSceneNode.h @@ -35,7 +35,7 @@ namespace scene //! returns the material based on the zero based index i. To get the amount //! of materials used by this scene node, use getMaterialCount(). - //! This function is needed for inserting the node into the scene hirachy on a + //! This function is needed for inserting the node into the scene hierarchy on a //! optimal position for minimizing renderstate changes, but can also be used //! to directly modify the material of a scene node. virtual video::SMaterial& getMaterial(u32 i) _IRR_OVERRIDE_; diff --git a/source/Irrlicht/CVolumeLightSceneNode.cpp b/source/Irrlicht/CVolumeLightSceneNode.cpp index 966e8237..720c3607 100644 --- a/source/Irrlicht/CVolumeLightSceneNode.cpp +++ b/source/Irrlicht/CVolumeLightSceneNode.cpp @@ -80,18 +80,12 @@ void CVolumeLightSceneNode::OnRegisterSceneNode() } -//! returns the material based on the zero based index i. To get the amount -//! of materials used by this scene node, use getMaterialCount(). -//! This function is needed for inserting the node into the scene hirachy on a -//! optimal position for minimizing renderstate changes, but can also be used -//! to directly modify the material of a scene node. video::SMaterial& CVolumeLightSceneNode::getMaterial(u32 i) { return Mesh->getMeshBuffer(i)->getMaterial(); } -//! returns amount of materials used by this scene node. u32 CVolumeLightSceneNode::getMaterialCount() const { return 1; diff --git a/source/Irrlicht/CWGLManager.cpp b/source/Irrlicht/CWGLManager.cpp index 28161a7a..da9fb1a3 100644 --- a/source/Irrlicht/CWGLManager.cpp +++ b/source/Irrlicht/CWGLManager.cpp @@ -233,13 +233,13 @@ bool CWGLManager::initialize(const SIrrlichtCreationParameters& params, const SE WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, #ifdef WGL_ARB_multisample WGL_SAMPLES_ARB,Params.AntiAlias, // 20,21 - WGL_SAMPLE_BUFFERS_ARB, 1, + WGL_SAMPLE_BUFFERS_ARB, (Params.AntiAlias>0) ? 1 : 0, #elif defined(WGL_EXT_multisample) WGL_SAMPLES_EXT,AntiAlias, // 20,21 - WGL_SAMPLE_BUFFERS_EXT, 1, + WGL_SAMPLE_BUFFERS_EXT, (Params.AntiAlias>0) ? 1 : 0, #elif defined(WGL_3DFX_multisample) WGL_SAMPLES_3DFX,AntiAlias, // 20,21 - WGL_SAMPLE_BUFFERS_3DFX, 1, + WGL_SAMPLE_BUFFERS_3DFX, (Params.AntiAlias>0) ? 1 : 0, #endif #ifdef WGL_ARB_framebuffer_sRGB WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, Params.HandleSRGB ? 1:0, diff --git a/source/Irrlicht/Irrlicht10.0.vcxproj b/source/Irrlicht/Irrlicht10.0.vcxproj index 4cccf741..78c279ca 100644 --- a/source/Irrlicht/Irrlicht10.0.vcxproj +++ b/source/Irrlicht/Irrlicht10.0.vcxproj @@ -844,6 +844,7 @@ + diff --git a/source/Irrlicht/Irrlicht10.0.vcxproj.filters b/source/Irrlicht/Irrlicht10.0.vcxproj.filters index ca39f218..6269a9c5 100644 --- a/source/Irrlicht/Irrlicht10.0.vcxproj.filters +++ b/source/Irrlicht/Irrlicht10.0.vcxproj.filters @@ -1387,6 +1387,9 @@ include\video + + include\scene + diff --git a/source/Irrlicht/Irrlicht11.0.vcxproj b/source/Irrlicht/Irrlicht11.0.vcxproj index ce54fce0..791a36a0 100644 --- a/source/Irrlicht/Irrlicht11.0.vcxproj +++ b/source/Irrlicht/Irrlicht11.0.vcxproj @@ -842,6 +842,7 @@ + diff --git a/source/Irrlicht/Irrlicht11.0.vcxproj.filters b/source/Irrlicht/Irrlicht11.0.vcxproj.filters index 13b5ed64..f61a3f95 100644 --- a/source/Irrlicht/Irrlicht11.0.vcxproj.filters +++ b/source/Irrlicht/Irrlicht11.0.vcxproj.filters @@ -1387,6 +1387,9 @@ include\video + + include\scene + diff --git a/source/Irrlicht/Irrlicht12.0.vcxproj b/source/Irrlicht/Irrlicht12.0.vcxproj index c72568e1..7b01c746 100644 --- a/source/Irrlicht/Irrlicht12.0.vcxproj +++ b/source/Irrlicht/Irrlicht12.0.vcxproj @@ -842,6 +842,7 @@ + diff --git a/source/Irrlicht/Irrlicht12.0.vcxproj.filters b/source/Irrlicht/Irrlicht12.0.vcxproj.filters index 1e1d5ce0..7e94d188 100644 --- a/source/Irrlicht/Irrlicht12.0.vcxproj.filters +++ b/source/Irrlicht/Irrlicht12.0.vcxproj.filters @@ -1387,6 +1387,9 @@ include\video + + include\scene + diff --git a/source/Irrlicht/Irrlicht14.0.vcxproj b/source/Irrlicht/Irrlicht14.0.vcxproj index 599145be..22385f15 100644 --- a/source/Irrlicht/Irrlicht14.0.vcxproj +++ b/source/Irrlicht/Irrlicht14.0.vcxproj @@ -853,6 +853,7 @@ + diff --git a/source/Irrlicht/Irrlicht14.0.vcxproj.filters b/source/Irrlicht/Irrlicht14.0.vcxproj.filters index 8b5c48cb..ed8c285b 100644 --- a/source/Irrlicht/Irrlicht14.0.vcxproj.filters +++ b/source/Irrlicht/Irrlicht14.0.vcxproj.filters @@ -1387,6 +1387,9 @@ include\video + + include\scene + diff --git a/tests/main.cpp b/tests/main.cpp index a0a73b9d..0f604a72 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -49,8 +49,9 @@ int main(int argumentCount, char * arguments[]) #if 0 // To interactively debug a test, move it (temporarily) in here and enable the define to only run this test // Otherwise debugging is slightly tricky as each test runs in it's own process. - TEST(textureFeatures); + TEST(stencilShadow); #else + TEST(disambiguateTextures); // Normally you should run this first, since it validates the working directory. // Now the simple tests without device TEST(testIrrArray); @@ -122,9 +123,8 @@ int main(int argumentCount, char * arguments[]) TEST(mrt); TEST(projectionMatrix); // large scenes/long rendering - // shadows are slow -// TEST(orthoCam); -// TEST(stencilShadow); + TEST(orthoCam); + TEST(stencilShadow); // q3 maps are slow TEST(planeMatrix); TEST(terrainSceneNode); diff --git a/tests/media/Burning's Video-stencilSelfShadow.png b/tests/media/Burning's Video-stencilSelfShadow.png new file mode 100644 index 00000000..dcdb6087 Binary files /dev/null and b/tests/media/Burning's Video-stencilSelfShadow.png differ diff --git a/tests/media/Burning's Video-stencilShadow.png b/tests/media/Burning's Video-stencilShadow.png new file mode 100644 index 00000000..60f31cdc Binary files /dev/null and b/tests/media/Burning's Video-stencilShadow.png differ diff --git a/tests/media/Direct3D 9.0-orthoStencil.png b/tests/media/Direct3D 9.0-orthoStencil.png index bc24e206..4e7afb8a 100644 Binary files a/tests/media/Direct3D 9.0-orthoStencil.png and b/tests/media/Direct3D 9.0-orthoStencil.png differ diff --git a/tests/media/Direct3D 9.0-stencilSelfShadow.png b/tests/media/Direct3D 9.0-stencilSelfShadow.png index 5cb17d2f..4c271de7 100644 Binary files a/tests/media/Direct3D 9.0-stencilSelfShadow.png and b/tests/media/Direct3D 9.0-stencilSelfShadow.png differ diff --git a/tests/media/Direct3D 9.0-stencilShadow.png b/tests/media/Direct3D 9.0-stencilShadow.png index 45a75531..724d5d3b 100644 Binary files a/tests/media/Direct3D 9.0-stencilShadow.png and b/tests/media/Direct3D 9.0-stencilShadow.png differ diff --git a/tests/media/OpenGL-orthoStencil.png b/tests/media/OpenGL-orthoStencil.png index 7f81c32f..913905cb 100644 Binary files a/tests/media/OpenGL-orthoStencil.png and b/tests/media/OpenGL-orthoStencil.png differ diff --git a/tests/media/OpenGL-stencilSelfShadow.png b/tests/media/OpenGL-stencilSelfShadow.png index 2b21fd86..d5a9abf3 100644 Binary files a/tests/media/OpenGL-stencilSelfShadow.png and b/tests/media/OpenGL-stencilSelfShadow.png differ diff --git a/tests/media/OpenGL-stencilShadow.png b/tests/media/OpenGL-stencilShadow.png index 96f8601c..8f1534ad 100644 Binary files a/tests/media/OpenGL-stencilShadow.png and b/tests/media/OpenGL-stencilShadow.png differ diff --git a/tests/orthoCam.cpp b/tests/orthoCam.cpp index 1e499325..deb08bcd 100644 --- a/tests/orthoCam.cpp +++ b/tests/orthoCam.cpp @@ -60,7 +60,7 @@ static bool testOrthoStencil(video::E_DRIVER_TYPE driverType) scene::ICameraSceneNode* cam = device->getSceneManager()->addCameraSceneNode(); cam->setPosition(core::vector3df(300,250,-300)); cam->setTarget(core::vector3df(0,20,0)); - cam->setProjectionMatrix(core::matrix4().buildProjectionMatrixOrthoLH(120,90,0.9f,2000.f,driverType != video::EDT_OPENGL), true); + cam->setProjectionMatrix(core::matrix4().buildProjectionMatrixOrthoLH(120,90,0.9f,5000.f,driverType != video::EDT_OPENGL), true); device->getSceneManager()->addAnimatedMeshSceneNode(device->getSceneManager()->addHillPlaneMesh("plane", core::dimension2df(32,32), core::dimension2du(16,16)));//->setMaterialFlag(video::EMF_WIREFRAME, true); @@ -97,6 +97,7 @@ bool orthoCam(void) passed &= testOrthoCam(video::EDT_BURNINGSVIDEO); passed &= testOrthoCam(video::EDT_DIRECT3D9); + // TODO: not sure if burnings could work? Currently it doesn't. passed &= testOrthoStencil(video::EDT_OPENGL); passed &= testOrthoStencil(video::EDT_DIRECT3D9); diff --git a/tests/stencilshadow.cpp b/tests/stencilshadow.cpp index eb520e6d..4e7f3e3f 100644 --- a/tests/stencilshadow.cpp +++ b/tests/stencilshadow.cpp @@ -5,7 +5,8 @@ using namespace irr; -static bool shadows(video::E_DRIVER_TYPE driverType) +// +static bool stencilShadow(video::E_DRIVER_TYPE driverType) { IrrlichtDevice *device = createDevice (driverType, core::dimension2d(160,120), 16, false, true); if (!device) @@ -14,45 +15,71 @@ static bool shadows(video::E_DRIVER_TYPE driverType) stabilizeScreenBackground(device->getVideoDriver()); scene::ICameraSceneNode* cam = device->getSceneManager()->addCameraSceneNodeFPS(); - cam->setPosition(core::vector3df(-15,55,10)); - cam->setTarget(core::vector3df(-5,-5,-15)); + cam->setPosition(core::vector3df(-15,60,40)); + cam->setTarget(core::vector3df(+25,-5,-25)); device->getSceneManager()->setAmbientLight(video::SColorf(.5f,.5f,.5f)); - scene::IMeshSceneNode* cube = device->getSceneManager()->addCubeSceneNode(100, 0, -1, core::vector3df(0,50,0)); - cube->setScale(core::vector3df(-1,-1,-1)); + device->getSceneManager()->setShadowColor( video::SColor(255, 50, 0, 50)); + device->getSceneManager()->addCubeSceneNode(100, 0, -1, core::vector3df(0,50,0), core::vector3df(), core::vector3df(-1,-1,-1)); - scene::IAnimatedMeshSceneNode* node = device->getSceneManager()->addAnimatedMeshSceneNode(device->getSceneManager()->getMesh("../media/ninja.b3d"), 0, -1, core::vector3df(0,2,0), core::vector3df(),core::vector3df(5,5,5)); + scene::IAnimatedMeshSceneNode* node = device->getSceneManager()->addAnimatedMeshSceneNode(device->getSceneManager()->getMesh("../media/ninja.b3d"), 0, -1, core::vector3df(), core::vector3df(0.f, 230.f, 0.f),core::vector3df(5,5,5)); node->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true); - node->addShadowVolumeSceneNode(); + node->addShadowVolumeSceneNode(0, -1, true, 200.f); node->setAnimationSpeed(0.f); - scene::ILightSceneNode* light = device->getSceneManager()->addLightSceneNode(0, core::vector3df(10,10,10)); + scene::IMeshSceneNode* cube2 = device->getSceneManager()->addCubeSceneNode(10, 0, -1, core::vector3df(40,0,0), core::vector3df(), core::vector3df(1,1,2.5f)); + cube2->getMaterial(0).DiffuseColor = video::SColor(220, 0, 100, 100); + cube2->addShadowVolumeSceneNode(0, -1, false, 200.f); + + scene::ILightSceneNode* light = device->getSceneManager()->addLightSceneNode(0, core::vector3df(-40,10,20)); light->setLightType(video::ELT_POINT); light->setRadius(500.f); - light->getLightData().DiffuseColor.set(0,1,1); + light->getLightData().DiffuseColor.set(1,1,1); - device->getVideoDriver()->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0,0,0,0)); + device->getVideoDriver()->beginScene(video::ECBF_ALL, video::SColor(0,0,0,0)); device->getSceneManager()->drawAll(); device->getVideoDriver()->endScene(); bool result = takeScreenshotAndCompareAgainstReference(device->getVideoDriver(), "-stencilShadow.png", 99.91f); - node->remove(); - cube->remove(); - // test self-shadowing - node = device->getSceneManager()->addAnimatedMeshSceneNode(device->getSceneManager()->getMesh("../media/dwarf.x")); + device->closeDevice(); + device->run(); + device->drop(); + + return result; +} + +// test self-shadowing +static bool selfShadowing(video::E_DRIVER_TYPE driverType) +{ + IrrlichtDevice *device = createDevice (driverType, core::dimension2d(160,120), 16, false, true); + if (!device) + return true; // No error if device does not exist + + stabilizeScreenBackground(device->getVideoDriver()); + + device->getSceneManager()->setAmbientLight(video::SColorf(.5f,.5f,.5f)); + device->getSceneManager()->setShadowColor( video::SColor(220, 50, 0, 0)); + + scene::IAnimatedMeshSceneNode* node = device->getSceneManager()->addAnimatedMeshSceneNode(device->getSceneManager()->getMesh("../media/dwarf.x")); node->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true); node->addShadowVolumeSceneNode(); node->setAnimationSpeed(0.f); + scene::ICameraSceneNode* cam = device->getSceneManager()->addCameraSceneNodeFPS(); cam->setPosition(core::vector3df(0,55,-30)); cam->setTarget(core::vector3df(60,45,150)); - device->getVideoDriver()->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0,0,0,0)); + scene::ILightSceneNode* light = device->getSceneManager()->addLightSceneNode(0, core::vector3df(100,100,-20)); + light->setLightType(video::ELT_POINT); + light->setRadius(500.f); + light->getLightData().DiffuseColor.set(0,1,1); + + device->getVideoDriver()->beginScene(video::ECBF_ALL, video::SColor(0,0,0,0)); device->getSceneManager()->drawAll(); device->getVideoDriver()->endScene(); - result = takeScreenshotAndCompareAgainstReference(device->getVideoDriver(), "-stencilSelfShadow.png", 99.41f); + bool result = takeScreenshotAndCompareAgainstReference(device->getVideoDriver(), "-stencilSelfShadow.png", 99.41f); device->closeDevice(); device->run(); @@ -65,11 +92,17 @@ bool stencilShadow(void) { bool passed = true; - passed &= shadows(video::EDT_OPENGL); - // no shadows in these renderers -// passed &= shadows(video::EDT_SOFTWARE); -// passed &= shadows(video::EDT_BURNINGSVIDEO); - passed &= shadows(video::EDT_DIRECT3D9); + passed &= stencilShadow(video::EDT_OPENGL); + passed &= stencilShadow(video::EDT_DIRECT3D9); + // no shadows in software renderer +// passed &= stencilShadow(video::EDT_SOFTWARE); + passed &= stencilShadow(video::EDT_BURNINGSVIDEO); // Note: cube has wrong color, if that gets ever changed just update the test-image. + + passed &= selfShadowing(video::EDT_OPENGL); + passed &= selfShadowing(video::EDT_DIRECT3D9); + // no shadows in software renderer +// passed &= selfShadowing(video::EDT_SOFTWARE); + passed &= selfShadowing(video::EDT_BURNINGSVIDEO); return passed; } diff --git a/tests/tests-last-passed-at.txt b/tests/tests-last-passed-at.txt index d503b194..eb9e250c 100644 --- a/tests/tests-last-passed-at.txt +++ b/tests/tests-last-passed-at.txt @@ -1,4 +1,4 @@ -Tests finished. 70 tests of 70 passed. -Compiled as DEBUG -Test suite pass at GMT Tue Nov 12 17:06:08 2019 - +Tests finished. 72 tests of 72 passed. +Compiled as DEBUG +Test suite pass at GMT Fri Nov 22 15:52:21 2019 +