From c4bc172d3b871b6773b36505f7b472b508f4d74a Mon Sep 17 00:00:00 2001 From: Murat Sari Date: Mon, 30 Mar 2015 14:25:28 +0200 Subject: [PATCH] Start migrating custom HLMS version for Ogre 1.10 (documentation / pbs shader / sample will follow) Backported a few things from 2.1 which is needed like Threading / Hashing / IdString --- .hgignore | 3 +- CMake/FeatureSummary.cmake | 3 + CMakeLists.txt | 1 + Components/CMakeLists.txt | 4 + Components/HLMS/CMakeLists.txt | 42 + Components/HLMS/include/OgreHlmsDatablock.h | 75 ++ Components/HLMS/include/OgreHlmsManager.h | 72 ++ .../HLMS/include/OgreHlmsMaterialBase.h | 65 ++ Components/HLMS/include/OgreHlmsPbsMaterial.h | 206 ++++ .../HLMS/include/OgreHlmsPrerequisites.h | 56 + .../HLMS/include/OgreHlmsPropertyHelper.h | 88 ++ Components/HLMS/include/OgreHlmsPropertyMap.h | 100 ++ .../HLMS/include/OgreHlmsShaderCommon.h | 164 +++ .../HLMS/include/OgreHlmsShaderGenerator.h | 106 ++ .../HLMS/include/OgreHlmsShaderManager.h | 61 ++ .../include/OgreHlmsShaderPiecesManager.h | 60 ++ .../HLMS/include/OgreHlmsShaderTemplate.h | 61 ++ Components/HLMS/src/OgreHlmsDatablock.cpp | 93 ++ Components/HLMS/src/OgreHlmsManager.cpp | 118 +++ Components/HLMS/src/OgreHlmsMaterialBase.cpp | 46 + Components/HLMS/src/OgreHlmsPbsMaterial.cpp | 413 ++++++++ .../HLMS/src/OgreHlmsPropertyHelper.cpp | 85 ++ Components/HLMS/src/OgreHlmsPropertyMap.cpp | 132 +++ .../HLMS/src/OgreHlmsShaderGenerator.cpp | 956 ++++++++++++++++++ Components/HLMS/src/OgreHlmsShaderManager.cpp | 452 +++++++++ .../HLMS/src/OgreHlmsShaderPiecesManager.cpp | 98 ++ .../HLMS/src/OgreHlmsShaderTemplate.cpp | 83 ++ .../include/OgreOverlayPrerequisites.h | 2 +- OgreMain/CMakeLists.txt | 19 +- OgreMain/include/Hash/MurmurHash3.h | 43 + OgreMain/include/OgreId.h | 88 ++ OgreMain/include/OgreIdString.h | 297 ++++++ OgreMain/include/OgrePlatform.h | 37 + OgreMain/include/Threading/OgreBarrier.h | 84 ++ .../include/Threading/OgreLightweightMutex.h | 103 ++ OgreMain/include/Threading/OgreThreads.h | 187 ++++ OgreMain/src/Hash/MurmurHash3.cpp | 340 +++++++ .../src/Threading/OgreBarrierPThreads.cpp | 113 +++ OgreMain/src/Threading/OgreBarrierWin.cpp | 88 ++ .../OgreLightweightMutexPThreads.cpp | 59 ++ .../src/Threading/OgreLightweightMutexWin.cpp | 85 ++ .../src/Threading/OgreThreadsPThreads.cpp | 78 ++ OgreMain/src/Threading/OgreThreadsWin.cpp | 84 ++ 43 files changed, 5346 insertions(+), 4 deletions(-) create mode 100644 Components/HLMS/CMakeLists.txt create mode 100644 Components/HLMS/include/OgreHlmsDatablock.h create mode 100644 Components/HLMS/include/OgreHlmsManager.h create mode 100644 Components/HLMS/include/OgreHlmsMaterialBase.h create mode 100644 Components/HLMS/include/OgreHlmsPbsMaterial.h create mode 100644 Components/HLMS/include/OgreHlmsPrerequisites.h create mode 100644 Components/HLMS/include/OgreHlmsPropertyHelper.h create mode 100644 Components/HLMS/include/OgreHlmsPropertyMap.h create mode 100644 Components/HLMS/include/OgreHlmsShaderCommon.h create mode 100644 Components/HLMS/include/OgreHlmsShaderGenerator.h create mode 100644 Components/HLMS/include/OgreHlmsShaderManager.h create mode 100644 Components/HLMS/include/OgreHlmsShaderPiecesManager.h create mode 100644 Components/HLMS/include/OgreHlmsShaderTemplate.h create mode 100644 Components/HLMS/src/OgreHlmsDatablock.cpp create mode 100644 Components/HLMS/src/OgreHlmsManager.cpp create mode 100644 Components/HLMS/src/OgreHlmsMaterialBase.cpp create mode 100644 Components/HLMS/src/OgreHlmsPbsMaterial.cpp create mode 100644 Components/HLMS/src/OgreHlmsPropertyHelper.cpp create mode 100644 Components/HLMS/src/OgreHlmsPropertyMap.cpp create mode 100644 Components/HLMS/src/OgreHlmsShaderGenerator.cpp create mode 100644 Components/HLMS/src/OgreHlmsShaderManager.cpp create mode 100644 Components/HLMS/src/OgreHlmsShaderPiecesManager.cpp create mode 100644 Components/HLMS/src/OgreHlmsShaderTemplate.cpp create mode 100644 OgreMain/include/Hash/MurmurHash3.h create mode 100644 OgreMain/include/OgreId.h create mode 100644 OgreMain/include/OgreIdString.h create mode 100644 OgreMain/include/Threading/OgreBarrier.h create mode 100644 OgreMain/include/Threading/OgreLightweightMutex.h create mode 100644 OgreMain/include/Threading/OgreThreads.h create mode 100644 OgreMain/src/Hash/MurmurHash3.cpp create mode 100644 OgreMain/src/Threading/OgreBarrierPThreads.cpp create mode 100644 OgreMain/src/Threading/OgreBarrierWin.cpp create mode 100644 OgreMain/src/Threading/OgreLightweightMutexPThreads.cpp create mode 100644 OgreMain/src/Threading/OgreLightweightMutexWin.cpp create mode 100644 OgreMain/src/Threading/OgreThreadsPThreads.cpp create mode 100644 OgreMain/src/Threading/OgreThreadsWin.cpp diff --git a/.hgignore b/.hgignore index ef009a0b6a7..5ad22677b47 100644 --- a/.hgignore +++ b/.hgignore @@ -27,4 +27,5 @@ AndroidBuild/ AndroidDependencies/ Build/ EmscriptenDependencies -EmscriptenBuild \ No newline at end of file +EmscriptenBuild +buildx64 diff --git a/CMake/FeatureSummary.cmake b/CMake/FeatureSummary.cmake index 5680caea7d2..8417b1fe3d6 100644 --- a/CMake/FeatureSummary.cmake +++ b/CMake/FeatureSummary.cmake @@ -45,6 +45,9 @@ endif () if (OGRE_BUILD_COMPONENT_OVERLAY) set(_components "${_components} + Overlay\n") endif () +if (OGRE_BUILD_COMPONENT_HLMS) + set(_components "${_components} + HLMS\n") +endif () if (DEFINED _components) set(_features "${_features}Building components:\n${_components}") diff --git a/CMakeLists.txt b/CMakeLists.txt index 91b44489f74..5998a378957 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -402,6 +402,7 @@ cmake_dependent_option(OGRE_BUILD_COMPONENT_VOLUME "Build Volume component" TRUE cmake_dependent_option(OGRE_BUILD_COMPONENT_PROPERTY "Build Property component" TRUE "Boost_FOUND" FALSE) cmake_dependent_option(OGRE_BUILD_PLUGIN_CG "Build Cg plugin" TRUE "Cg_FOUND;NOT OGRE_BUILD_PLATFORM_APPLE_IOS;NOT WINDOWS_STORE;NOT WINDOWS_PHONE" FALSE) cmake_dependent_option(OGRE_BUILD_COMPONENT_OVERLAY "Build Overlay component" TRUE "FREETYPE_FOUND" FALSE) +option(OGRE_BUILD_COMPONENT_HLMS "Build HLMS component" FALSE) option(OGRE_BUILD_COMPONENT_RTSHADERSYSTEM "Build RTShader System component" TRUE) cmake_dependent_option(OGRE_BUILD_RTSHADERSYSTEM_CORE_SHADERS "Build RTShader System FFP core shaders" TRUE "OGRE_BUILD_COMPONENT_RTSHADERSYSTEM" FALSE) cmake_dependent_option(OGRE_BUILD_RTSHADERSYSTEM_EXT_SHADERS "Build RTShader System extensions shaders" TRUE "OGRE_BUILD_COMPONENT_RTSHADERSYSTEM" FALSE) diff --git a/Components/CMakeLists.txt b/Components/CMakeLists.txt index a2619788cae..6647ed3b5e6 100644 --- a/Components/CMakeLists.txt +++ b/Components/CMakeLists.txt @@ -39,3 +39,7 @@ endif () if (OGRE_BUILD_COMPONENT_OVERLAY) add_subdirectory(Overlay) endif () + +if (OGRE_BUILD_COMPONENT_HLMS) + add_subdirectory(HLMS) +endif () \ No newline at end of file diff --git a/Components/HLMS/CMakeLists.txt b/Components/HLMS/CMakeLists.txt new file mode 100644 index 00000000000..0be0a0c004b --- /dev/null +++ b/Components/HLMS/CMakeLists.txt @@ -0,0 +1,42 @@ +#------------------------------------------------------------------- +# This file is part of the CMake build system for OGRE +# (Object-oriented Graphics Rendering Engine) +# For the latest info, see http://www.ogre3d.org/ +# +# The contents of this file are placed in the public domain. Feel +# free to make use of it in any way you like. +#------------------------------------------------------------------- + +############################################################ +# HLMS optional component +############################################################ + +PROJECT(OgreHLMS) + +# define header and source files for the library +file(GLOB HEADER_FILES "${CMAKE_CURRENT_SOURCE_DIR}/include/*.h") +file(GLOB SOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") + +# Add needed definitions +add_definitions(-DOGRE_HLMS_EXPORTS -D_MT -D_USRDLL) + +# include headers +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) +include_directories(${OGRE_SOURCE_DIR}/OgreMain/include) + +# setup target +ogre_add_library(OgreHLMS ${OGRE_COMP_LIB_TYPE} ${HEADER_FILES} ${SOURCE_FILES} ${PLATFORM_HEADER_FILES} ${PLATFORM_SOURCE_FILES}) +set_target_properties(OgreHLMS PROPERTIES VERSION ${OGRE_SOVERSION} SOVERSION ${OGRE_SOVERSION}) +target_link_libraries(OgreHLMS OgreMain) +if (OGRE_CONFIG_THREADS) + target_link_libraries(OgreHLMS ${OGRE_THREAD_LIBRARIES}) +endif () + +# install +ogre_config_framework(OgreHLMS) +ogre_config_component(OgreHLMS) + +install(FILES ${HEADER_FILES} + DESTINATION include/OGRE/HLMS +) + diff --git a/Components/HLMS/include/OgreHlmsDatablock.h b/Components/HLMS/include/OgreHlmsDatablock.h new file mode 100644 index 00000000000..2e2e2c0d976 --- /dev/null +++ b/Components/HLMS/include/OgreHlmsDatablock.h @@ -0,0 +1,75 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE +(Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2015 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#pragma once + +#include "Ogre.h" +#include "OgreHlmsPrerequisites.h" +#include "OgreHlmsPropertyMap.h" +#include "OgreHlmsShaderTemplate.h" + +namespace Ogre +{ + /** \addtogroup Component + * @{ + */ + /** \addtogroup Hlms + * @{ + */ + class _OgreHlmsExport HlmsDatablock + { + public: + HlmsDatablock(Ogre::GpuProgramType type, PropertyMap* propertyMap); + + PropertyMap* getPropertyMap(){ return mPropertyMap; } + + Ogre::GpuProgramType getShaderType(){ return mShaderType; } + const Ogre::String& getLanguarge(){ return mLanguarge; } + ShaderTemplate* getTemplate(); + const Ogre::StringVector& getProfileList(){ return mProfilesList; } + + void setLanguarge(const Ogre::String& languarge); + void setTemplateName(const Ogre::String& tamplateName); + void addProfile(const Ogre::String& profile); + + Ogre::uint32 getHash(); + + protected: + ShaderTemplate mTemplate; + Ogre::String mTamplateName; + Ogre::String mLanguarge; + Ogre::GpuProgramType mShaderType; + PropertyMap* mPropertyMap; + Ogre::StringVector mProfilesList; // vs_2_0, fs_3_0, ... + + Ogre::uint32 mHash; + + void reload(); + }; +} + diff --git a/Components/HLMS/include/OgreHlmsManager.h b/Components/HLMS/include/OgreHlmsManager.h new file mode 100644 index 00000000000..9985f1be9a0 --- /dev/null +++ b/Components/HLMS/include/OgreHlmsManager.h @@ -0,0 +1,72 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE +(Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2015 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#pragma once + +#include "Ogre.h" +#include "OgreHlmsPrerequisites.h" +#include "OgreHlmsShaderManager.h" +#include "Threading/OgreThreadHeaders.h" + +namespace Ogre +{ + class HlmsMaterialBase; + + /** \addtogroup Component + * @{ + */ + /** \addtogroup Hlms + * @{ + */ + class _OgreHlmsExport HlmsManager : public Ogre::RenderObjectListener, public Ogre::Camera::Listener + { + public: + HlmsManager(Ogre::Camera* camera); + virtual ~HlmsManager(); + + virtual void cameraPreRenderScene(Ogre::Camera* cam); + + virtual void notifyRenderSingleObject( + Ogre::Renderable* rend, + const Ogre::Pass* pass, + const Ogre::AutoParamDataSource* source, + const Ogre::LightList* pLightList, + bool suppressRenderStateChanges); + + void bind(Ogre::Renderable* rend, HlmsMaterialBase* material); + + protected: + Ogre::Camera* mCamera; + Ogre::SceneManager* mSceneManager; + + ShaderManager mShaderManager; + + std::unordered_map mBindedMaterials; + }; +} + diff --git a/Components/HLMS/include/OgreHlmsMaterialBase.h b/Components/HLMS/include/OgreHlmsMaterialBase.h new file mode 100644 index 00000000000..2e6ed42c080 --- /dev/null +++ b/Components/HLMS/include/OgreHlmsMaterialBase.h @@ -0,0 +1,65 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE +(Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2015 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#pragma once + +#include "Ogre.h" +#include "OgreHlmsPrerequisites.h" +#include "OgreHlmsPropertyMap.h" +#include "OgreHlmsDatablock.h" + +namespace Ogre +{ + /** \addtogroup Component + * @{ + */ + /** \addtogroup Hlms + * @{ + */ + class _OgreHlmsExport HlmsMaterialBase + { + public: + HlmsMaterialBase(); + virtual ~HlmsMaterialBase(); + + HlmsDatablock* getVertexDatablock(){ return &mVertexDatablock; } + HlmsDatablock* getFragmentDatablock(){ return &mFragmentDatablock; } + + PropertyMap& getPropertyMap(){ return mPropertyMap; } + + virtual void updatePropertyMap(Ogre::Camera* camera, const Ogre::LightList* pLightList){} + virtual void updateUniforms(Ogre::Camera* camera, Ogre::Pass* pass, const Ogre::AutoParamDataSource* source, const Ogre::LightList* pLightList, bool shaderHasChanged) {} + + protected: + HlmsDatablock mVertexDatablock; + HlmsDatablock mFragmentDatablock; + + PropertyMap mPropertyMap; + }; +} + diff --git a/Components/HLMS/include/OgreHlmsPbsMaterial.h b/Components/HLMS/include/OgreHlmsPbsMaterial.h new file mode 100644 index 00000000000..4ebd6461c11 --- /dev/null +++ b/Components/HLMS/include/OgreHlmsPbsMaterial.h @@ -0,0 +1,206 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE +(Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2015 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#pragma once + +#include "Ogre.h" +#include "OgreHlmsPrerequisites.h" +#include "OgreHlmsMaterialBase.h" + +namespace Ogre +{ + /** \addtogroup Component + * @{ + */ + /** \addtogroup Hlms + * @{ + */ + class _OgreHlmsExport PbsMaterial : public HlmsMaterialBase + { + public: + enum BlendFunction + { + BF_ALPHA = 0, + BF_ALPHA_PREMUL, + BF_ADD, + BF_SUBTRACT, + BF_MULTIPLY, + BF_MULTIPLY_2X, + BF_SCREEN, + BF_OVERLAY, + BF_LIGHTEN, + BF_DARKEN, + BF_GRAIN_EXTRACT, + BF_GRAIN_MERGE, + BF_DIFFERENCE + }; + + enum MapSlot + { + MS_MAIN, + MS_D1, + MS_D2 + }; + + class TextureAddressing + { + public: + Ogre::TextureUnitState::TextureAddressingMode u = Ogre::TextureUnitState::TAM_WRAP; + Ogre::TextureUnitState::TextureAddressingMode v = Ogre::TextureUnitState::TAM_WRAP; + bool operator ==(TextureAddressing& b){ return u == b.u && v == b.v; } + }; + + private: + enum SamplerType + { + ST_ENV_MAP = 0, + ST_MAIN_ALBEDO, + ST_MAIN_NORMAL, + ST_MAIN_F0R, + ST_D1_ALBEDO, + ST_D1_NORMAL, + ST_D1_F0R, + ST_D2_ALBEDO, + ST_D2_NORMAL, + ST_D2_F0R, + ST_COUNT + }; + + enum SamplerStatus + { + SS_NOT_ACTIVE, + SS_ACTIVE, + SS_UPDATED, + SS_ADDED, + SS_REMOVED + }; + + class SamplerContainer + { + public: + Ogre::String name; + Ogre::TextureType textureType; + Ogre::TexturePtr tex; + Ogre::TextureUnitState* textureUnitState = NULL; + + SamplerStatus status = SS_NOT_ACTIVE; + + bool hasIntensity = false; + float intensity = 0; + + bool hasMipmapCount = false; + float mipmapCount = 0; + + bool hasBlendFunc = false; + BlendFunction blendFunc = BF_ALPHA; + bool hasBlendFactor1 = false; + float blendFactor1 = 0; + bool hasBlendFactor2 = false; + float blendFactor2 = 0; + + TextureAddressing textureAddressing; + + bool needsGammaCorrection = false; + + void init(Ogre::String n, bool hasBlendFu = false, bool hasBlendFc1 = false, bool hasBlendFc2 = false, bool needsGammaCorrect = false, bool hasIntens = false, bool hasMipmapC = false, Ogre::TextureType texType = Ogre::TEX_TYPE_2D) + { + name = n; + hasBlendFunc = hasBlendFu; + hasBlendFactor1 = hasBlendFc1; + hasBlendFactor2 = hasBlendFc2; + needsGammaCorrection = needsGammaCorrect; + hasIntensity = hasIntens; + hasMipmapCount = hasMipmapC; + textureType = texType; + } + }; + + public: + PbsMaterial(); + PbsMaterial(const PbsMaterial &obj); + virtual ~PbsMaterial(); + + void setEnvironmapTexture(Ogre::TexturePtr tex, float intensityFactor = 1.0f); + + Ogre::ColourValue getAlbedo(){ return mAlbedo; } + void setAlbedo(Ogre::ColourValue val){ mAlbedo = val; } + + Ogre::ColourValue getF0(){ return mF0; } + void setF0(Ogre::ColourValue val){ mF0 = val; } + + Ogre::Real getRothness(){ return mRothness; } + void setRothness(Ogre::Real val){ mRothness = val; } + + void setAlbedoTexture(MapSlot mapSlot, Ogre::TexturePtr tex, TextureAddressing textureAddressing = TextureAddressing(), BlendFunction blendFunc = BF_ALPHA, float blendFactor = 0); + void setNormalTexture(MapSlot mapSlot, Ogre::TexturePtr tex, TextureAddressing textureAddressing = TextureAddressing(), float blendFactor = 0); + void setF0RTexture(MapSlot mapSlot, Ogre::TexturePtr tex, TextureAddressing textureAddressing = TextureAddressing(), BlendFunction blendFunc = BF_ALPHA, float f0BlendFactor = 0, float rBlendFactor = 0); + void setOffsetAndScale(MapSlot mapSlot, Ogre::Vector2 offset, Ogre::Vector2 scale); + void setUvSetIndex(MapSlot mapSlot, Ogre::uint index); + + void updatePropertyMap(Ogre::Camera* camera, const Ogre::LightList* pLightList); + void updateUniforms(Ogre::Camera* camera, Ogre::Pass* pass, const Ogre::AutoParamDataSource* source, const Ogre::LightList* pLightList, bool shaderHasChanged); + void updateTexturUnits(Ogre::TextureUnitState* textureUnitState, Ogre::GpuProgramParametersSharedPtr fragmentParams, SamplerContainer& s); + + protected: + + Ogre::ColourValue mAlbedo; + Ogre::ColourValue mF0; + Ogre::Real mRothness; + + Ogre::Vector2 mMainOffset = Ogre::Vector2::ZERO; + Ogre::Vector2 mMainScale = Ogre::Vector2::UNIT_SCALE; + Ogre::uint mMainUvSetIndex = 0; + + Ogre::Vector2 mD1Offset = Ogre::Vector2::ZERO; + Ogre::Vector2 mD1Scale = Ogre::Vector2::UNIT_SCALE; + Ogre::uint mD1UvSetIndex = 0; + + Ogre::Vector2 mD2Offset = Ogre::Vector2::ZERO; + Ogre::Vector2 mD2Scale = Ogre::Vector2::UNIT_SCALE; + Ogre::uint mD2UvSetIndex = 0; + + Ogre::uint32 mDirectionalLightCount; + Ogre::uint32 mPointLightCount; + Ogre::uint32 mSpotLightCount; + + SamplerContainer _samplers[ST_COUNT]; + bool _hasSamplerListChanged = false; + bool _hasSamplerChanged = false; + + static const Ogre::uint32 maxLightCount = 10; + + float mLightPositions_es[maxLightCount * 3]; + float mLightDirections_es[maxLightCount * 3]; + float mLightColors[maxLightCount * 3]; + float mLightParameters[maxLightCount * 3]; + + void setTexture(SamplerType samplerType, Ogre::TexturePtr tex, TextureAddressing uTextureAddr, + float blendFactor1 = 0, float blendFactor2 = 0, BlendFunction blendFunc = BF_ALPHA, float intensityFactor = 1.0); + }; +} + diff --git a/Components/HLMS/include/OgreHlmsPrerequisites.h b/Components/HLMS/include/OgreHlmsPrerequisites.h new file mode 100644 index 00000000000..c18c4db31e0 --- /dev/null +++ b/Components/HLMS/include/OgreHlmsPrerequisites.h @@ -0,0 +1,56 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE +(Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2015 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#ifndef __Ogre_Hlms_Prereq_H__ +#define __Ogre_Hlms_Prereq_H__ + +#include "OgrePrerequisites.h" + +#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 || OGRE_PLATFORM == OGRE_PLATFORM_WINRT +# if defined( OGRE_STATIC_LIB ) +# define _OgreHlmsExport +# else +# if defined( OGRE_HLMS_EXPORTS ) +# define _OgreHlmsExport __declspec( dllexport ) +# else +# if defined( __MINGW32__ ) +# define _OgreHlmsExport +# else +# define _OgreHlmsExport __declspec( dllimport ) +# endif +# endif +# endif +#elif defined ( OGRE_GCC_VISIBILITY ) +# define _OgreHlmsExport __attribute__ ((visibility("default"))) +#else +# define _OgreHlmsExport +#endif + + + +#endif diff --git a/Components/HLMS/include/OgreHlmsPropertyHelper.h b/Components/HLMS/include/OgreHlmsPropertyHelper.h new file mode 100644 index 00000000000..94676859a38 --- /dev/null +++ b/Components/HLMS/include/OgreHlmsPropertyHelper.h @@ -0,0 +1,88 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE +(Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2015 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#pragma once + +#include "OgreIdString.h" +#include "OgreHlmsPrerequisites.h" + +namespace Ogre +{ + /** \addtogroup Component + * @{ + */ + /** \addtogroup Hlms + * @{ + */ + class _OgreHlmsExport DefaultProperties + { + public: + /// These are "default" or "Base" properties common to many implementations and thus defined here. + static const IdString Skeleton; + static const IdString BonesPerVertex; + static const IdString Pose; + + static const IdString Normal; + static const IdString QTangent; + static const IdString Tangent; + + static const IdString Colour; + + static const IdString UvCount; + static const IdString UvCount0; + static const IdString UvCount1; + static const IdString UvCount2; + static const IdString UvCount3; + static const IdString UvCount4; + static const IdString UvCount5; + static const IdString UvCount6; + static const IdString UvCount7; + + //Change per frame (grouped together with scene pass) + static const IdString LightsDirectional; + static const IdString LightsPoint; + static const IdString LightsSpot; + static const IdString LightsAttenuation; + static const IdString LightsSpotParams; + + //Change per scene pass + static const IdString DualParaboloidMapping; + static const IdString NumShadowMaps; + static const IdString PssmSplits; + static const IdString ShadowCaster; + + //Change per material (hash can be cached on the renderable) + static const IdString AlphaTest; + + static const IdString GL3Plus; + static const IdString HighQuality; + + static const IdString *UvCountPtrs[8]; + }; +} + diff --git a/Components/HLMS/include/OgreHlmsPropertyMap.h b/Components/HLMS/include/OgreHlmsPropertyMap.h new file mode 100644 index 00000000000..7250d8d9d8a --- /dev/null +++ b/Components/HLMS/include/OgreHlmsPropertyMap.h @@ -0,0 +1,100 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE +(Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2015 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#pragma once + + +#include "Ogre.h" +#include "OgreHlmsPrerequisites.h" +#include "OgreIdString.h" + +namespace Ogre +{ + /** \addtogroup Component + * @{ + */ + /** \addtogroup Hlms + * @{ + */ + class _OgreHlmsExport PropertyMap + { + public: + + struct Property + { + IdString keyName; + Ogre::int32 value; + + Property(IdString _keyName, Ogre::int32 _value) : + keyName(_keyName), value(_value) {} + + bool operator == (const Property &_r) const + { + return this->keyName == _r.keyName && this->value == _r.value; + } + }; + + PropertyMap(); + virtual ~PropertyMap(); + + /** Inserts common properties about the current Renderable, + such as hlms_skeleton hlms_uv_count, etc + */ + void setCommonProperties(); + + void setProperty(IdString key, Ogre::int32 value); + bool hasProperty(IdString key); + Ogre::int32 getProperty(IdString key, Ogre::int32 defaultVal = 0) const; + void removeProperty(IdString key); + + Ogre::uint32 getHash(); + + /** Finds the parameter with key 'key' in the given 'paramVec'. If found, outputs + the value to 'inOut', otherwise leaves 'inOut' as is. + @return + True if the key was found (inOut was modified), false otherwise + @remarks + Assumes paramVec is sorted by key. + */ + //static bool findParamInVec(const std::vector ¶mVec, IdString key, String &inOut); + + /// For debugging stuff. I.e. the Command line uses it for testing manually set properties + //void _setProperty(IdString key, int32 value) { setProperty(key, value); } + + protected: + + std::vector mProperties; + Ogre::uint32 mHash; + + static bool orderPropertyByIdString(const PropertyMap::Property &_left, const PropertyMap::Property &_right) + { + return _left.keyName < _right.keyName; + } + }; +} + diff --git a/Components/HLMS/include/OgreHlmsShaderCommon.h b/Components/HLMS/include/OgreHlmsShaderCommon.h new file mode 100644 index 00000000000..25424defa2b --- /dev/null +++ b/Components/HLMS/include/OgreHlmsShaderCommon.h @@ -0,0 +1,164 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE +(Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2015 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#pragma once + + +#include "Ogre.h" +#include "OgreHlmsPrerequisites.h" +#include "OgreIdString.h" +#include "Hash/MurmurHash3.h" + +namespace Ogre +{ + /** \addtogroup Component + * @{ + */ + /** \addtogroup Hlms + * @{ + */ + class _OgreHlmsExport SubStringRef + { + Ogre::String const *mOriginal; + size_t mStart; + size_t mEnd; + + public: + SubStringRef(const Ogre::String *original, size_t start) : + mOriginal( original ), + mStart( start ), + mEnd( original->size() ) + { + assert( start <= original->size() ); + } + + SubStringRef(const Ogre::String *original, size_t _start, size_t _end) : + mOriginal( original ), + mStart( _start ), + mEnd( _end ) + { + assert( _start <= _end ); + assert( _end <= original->size() ); + } + + SubStringRef(const Ogre::String *original, Ogre::String::const_iterator _start) : + mOriginal( original ), + mStart( _start - original->begin() ), + mEnd( original->size() ) + { + } + + size_t find( const char *value, size_t pos=0 ) const + { + size_t retVal = mOriginal->find( value, mStart + pos ); + if( retVal >= mEnd ) + retVal = Ogre::String::npos; + else if (retVal != Ogre::String::npos) + retVal -= mStart; + + return retVal; + } + + size_t find(const Ogre::String &value) const + { + size_t retVal = mOriginal->find( value, mStart ); + if( retVal >= mEnd ) + retVal = Ogre::String::npos; + else if (retVal != Ogre::String::npos) + retVal -= mStart; + + return retVal; + } + + size_t findFirstOf( const char *c, size_t pos ) const + { + size_t retVal = mOriginal->find_first_of( c, mStart + pos ); + if( retVal >= mEnd ) + retVal = Ogre::String::npos; + else if (retVal != Ogre::String::npos) + retVal -= mStart; + + return retVal; + } + + bool matchEqual( const char *stringCompare ) const + { + const char *origStr = mOriginal->c_str() + mStart; + ptrdiff_t length = mEnd - mStart; + while( *origStr == *stringCompare && *origStr && --length ) + ++origStr, ++stringCompare; + + return length == 0 && *origStr == *stringCompare; + } + + void setStart( size_t newStart ) { mStart = std::min( newStart, mOriginal->size() ); } + void setEnd( size_t newEnd ) { mEnd = std::min( newEnd, mOriginal->size() ); } + size_t getStart(void) const { return mStart; } + size_t getEnd(void) const { return mEnd; } + size_t getSize(void) const { return mEnd - mStart; } + Ogre::String::const_iterator begin() const { return mOriginal->begin() + mStart; } + Ogre::String::const_iterator end() const { return mOriginal->begin() + mEnd; } + const Ogre::String& getOriginalBuffer() const { return *mOriginal; } + }; + + const Ogre::String FilePatterns[] = { "_vs", "_fs", "_gs", "_ds", "_hs" }; + + typedef Ogre::vector< std::pair >::type HlmsParamVec; + + inline bool OrderParamVecByKey(const std::pair &_left, + const std::pair &_right) + { + return _left.first < _right.first; + } + + inline Ogre::uint32 calcHash(void* data, int size) + { + Ogre::uint32 finalHash; + MurmurHash3_x86_32(data, size, IdString::Seed, &finalHash); + return finalHash; + } + + inline Ogre::uint32 calcHash(Ogre::String str) + { + auto chars = str.c_str(); + return calcHash((void*)chars, str.length() * sizeof(char)); + } + + inline Ogre::uint32 calcHash(const Ogre::StringVector& vec) + { + Ogre::StringStream stream; + for (Ogre::String str : vec) + { + stream << str; + } + + auto str = stream.str(); + auto chars = str.c_str(); + return calcHash((void*)chars, str.length() * sizeof(char)); + } +} diff --git a/Components/HLMS/include/OgreHlmsShaderGenerator.h b/Components/HLMS/include/OgreHlmsShaderGenerator.h new file mode 100644 index 00000000000..d24e843c966 --- /dev/null +++ b/Components/HLMS/include/OgreHlmsShaderGenerator.h @@ -0,0 +1,106 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE +(Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2015 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#pragma once + +#include "Ogre.h" +#include "OgreHlmsPrerequisites.h" +#include "OgreHlmsPropertyMap.h" +#include "OgreHlmsShaderCommon.h" +#include "OgreIdString.h" + +namespace Ogre +{ + /** \addtogroup Component + * @{ + */ + /** \addtogroup Hlms + * @{ + */ + class _OgreHlmsExport ShaderGenerator + { + protected: + + typedef std::map PiecesMap; + + enum ExpressionType + { + EXPR_OPERATOR_OR, //|| + EXPR_OPERATOR_AND, //&& + EXPR_OBJECT, //(...) + EXPR_VAR + }; + + struct Expression + { + bool result; + bool negated; + ExpressionType type; + std::vector children; + Ogre::String value; + + Expression() : result(false), negated(false), type(EXPR_VAR) {} + }; + + typedef std::vector ExpressionVec; + + static void copy(Ogre::String &outBuffer, const SubStringRef &inSubString, size_t length); + static void repeat(Ogre::String &outBuffer, const SubStringRef &inSubString, size_t length, + size_t passNum, const Ogre::String &counterVar); + static bool parseMath(const Ogre::String &inBuffer, Ogre::String &outBuffer, PropertyMap &properties); + static bool parseForEach(const Ogre::String &inBuffer, Ogre::String &outBuffer, PropertyMap &properties); + static bool parseProperties(Ogre::String &inBuffer, Ogre::String &outBuffer, PropertyMap &properties); + static bool collectPieces(const Ogre::String &inBuffer, Ogre::String &outBuffer, PropertyMap &properties, PiecesMap& pieces); + static bool insertPieces(Ogre::String &inBuffer, Ogre::String &outBuffer, PropertyMap &properties, PiecesMap& pieces); + static bool parseCounter(const Ogre::String &inBuffer, Ogre::String &outBuffer, PropertyMap &properties); + + /** Goes through 'buffer', starting from startPos (inclusive) looking for the given + character while skipping whitespace. If any character other than whitespace or + EOLs if found returns String::npos + @return + String::npos if not found or wasn't the next character. If found, the position + in the buffer, from start + */ + static size_t findNextCharacter(const Ogre::String &buffer, size_t startPos, char character); + + static void findBlockEnd(SubStringRef &outSubString, bool &syntaxError); + + static bool evaluateExpression(SubStringRef &outSubString, bool &outSyntaxError, PropertyMap &properties); + static bool evaluateExpressionRecursive(ExpressionVec &expression, bool &outSyntaxError, PropertyMap &properties); + static size_t evaluateExpressionEnd(const SubStringRef &outSubString); + + static void evaluateParamArgs(SubStringRef &outSubString, Ogre::StringVector &outArgs, + bool &outSyntaxError); + + static size_t calculateLineCount(const Ogre::String &buffer, size_t idx); + static size_t calculateLineCount(const SubStringRef &subString); + + public: + static Ogre::String parse(Ogre::String &inBuffer, PropertyMap &properties, Ogre::StringVector& pieceFiles); + }; +} diff --git a/Components/HLMS/include/OgreHlmsShaderManager.h b/Components/HLMS/include/OgreHlmsShaderManager.h new file mode 100644 index 00000000000..ad0ca1a0f82 --- /dev/null +++ b/Components/HLMS/include/OgreHlmsShaderManager.h @@ -0,0 +1,61 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE +(Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2015 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#pragma once + +#include "Ogre.h" +#include "OgreHlmsPrerequisites.h" + +namespace Ogre +{ + class ShaderPiecesManager; + class HlmsDatablock; + + /** \addtogroup Component + * @{ + */ + /** \addtogroup Hlms + * @{ + */ + class _OgreHlmsExport ShaderManager + { + public: + ShaderManager(); + virtual ~ShaderManager(); + + Ogre::GpuProgramPtr getGpuProgram(HlmsDatablock* dataBlock); + + void clearCache(); + + protected: + + std::unordered_map mShaderCache; + ShaderPiecesManager* mShaderPiecesManager; + }; +} + diff --git a/Components/HLMS/include/OgreHlmsShaderPiecesManager.h b/Components/HLMS/include/OgreHlmsShaderPiecesManager.h new file mode 100644 index 00000000000..c263ea60870 --- /dev/null +++ b/Components/HLMS/include/OgreHlmsShaderPiecesManager.h @@ -0,0 +1,60 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE +(Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2015 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#pragma once + +#include "Ogre.h" +#include "OgreHlmsPrerequisites.h" + +namespace Ogre +{ + /** \addtogroup Component + * @{ + */ + /** \addtogroup Hlms + * @{ + */ + class _OgreHlmsExport ShaderPiecesManager + { + public: + ShaderPiecesManager(const Ogre::String& piecesFolder); + ~ShaderPiecesManager(); + + void enumeratePieceFiles(); + + Ogre::StringVector& getPieces(Ogre::String languarge, Ogre::GpuProgramType shaderType); + + protected: + + Ogre::String mPiecesFolder; + std::map mPieceFiles; + Ogre::StringVector mDefaultStringVector; + + }; +} + diff --git a/Components/HLMS/include/OgreHlmsShaderTemplate.h b/Components/HLMS/include/OgreHlmsShaderTemplate.h new file mode 100644 index 00000000000..e5e5d3ca981 --- /dev/null +++ b/Components/HLMS/include/OgreHlmsShaderTemplate.h @@ -0,0 +1,61 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE +(Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2015 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#pragma once + +#include "Ogre.h" +#include "OgreHlmsPrerequisites.h" + +namespace Ogre +{ + /** \addtogroup Component + * @{ + */ + /** \addtogroup Hlms + * @{ + */ + class _OgreHlmsExport ShaderTemplate + { + public: + ShaderTemplate(); + ~ShaderTemplate(); + + const Ogre::String& getTemplateFileName() { return mTemplateFileName; } + void setTemplateFileName(const Ogre::String& templateFileName); + + void load(); + const Ogre::String& getTemplate(); + Ogre::uint32 getHash(); + + protected: + Ogre::String mTemplateFileName; + Ogre::String mTemplate; + Ogre::uint32 mHash; + }; +} + diff --git a/Components/HLMS/src/OgreHlmsDatablock.cpp b/Components/HLMS/src/OgreHlmsDatablock.cpp new file mode 100644 index 00000000000..06b14f67760 --- /dev/null +++ b/Components/HLMS/src/OgreHlmsDatablock.cpp @@ -0,0 +1,93 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE +(Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2015 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#include "OgreHlmsDataBlock.h" +#include "OgreHlmsPropertyMap.h" +#include "OgreHlmsShaderCommon.h" + +namespace Ogre +{ + //----------------------------------------------------------------------------------- + HlmsDatablock::HlmsDatablock(Ogre::GpuProgramType type, PropertyMap* propertyMap) : mShaderType(type), mPropertyMap(propertyMap), mHash(0) + { + + } + //----------------------------------------------------------------------------------- + ShaderTemplate* HlmsDatablock::getTemplate() + { + if (mHash == 0) + { + reload(); + } + return &mTemplate; + } + //----------------------------------------------------------------------------------- + void HlmsDatablock::setLanguarge(const Ogre::String& languarge) + { + if (mLanguarge != languarge) + { + mHash = 0; + mLanguarge = languarge; + } + } + //----------------------------------------------------------------------------------- + void HlmsDatablock::setTemplateName(const Ogre::String& tamplateName) + { + if (mTamplateName != tamplateName) + { + mHash = 0; + mTamplateName = tamplateName; + } + } + //----------------------------------------------------------------------------------- + void HlmsDatablock::addProfile(const Ogre::String& profile) + { + mHash = 0; + mProfilesList.push_back(profile); + } + //----------------------------------------------------------------------------------- + Ogre::uint32 HlmsDatablock::getHash() + { + if (mHash == 0) + { + reload(); + } + + return mHash + mPropertyMap->getHash(); + + } + //----------------------------------------------------------------------------------- + void HlmsDatablock::reload() + { + auto path = mTamplateName + FilePatterns[mShaderType] + "." + mLanguarge + "t"; + mTemplate.setTemplateFileName(path); + + mHash = mTemplate.getHash() + mShaderType + calcHash(mLanguarge) + calcHash(mProfilesList); + } + //----------------------------------------------------------------------------------- +} \ No newline at end of file diff --git a/Components/HLMS/src/OgreHlmsManager.cpp b/Components/HLMS/src/OgreHlmsManager.cpp new file mode 100644 index 00000000000..f0c51152aa3 --- /dev/null +++ b/Components/HLMS/src/OgreHlmsManager.cpp @@ -0,0 +1,118 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE +(Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2015 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#include "OgreHlmsManager.h" +#include "OgreHlmsMaterialBase.h" +#include "OgreHlmsPbsMaterial.h" + +namespace Ogre +{ + //----------------------------------------------------------------------------------- + HlmsManager::HlmsManager(Ogre::Camera* camera) : mCamera(camera) + { + mSceneManager = mCamera->getSceneManager(); + + mCamera->addListener(this); + mSceneManager->addRenderObjectListener(this); + } + //----------------------------------------------------------------------------------- + HlmsManager::~HlmsManager() + { + mSceneManager->removeRenderObjectListener(this); + mCamera->removeListener(this); + } + //----------------------------------------------------------------------------------- + void HlmsManager::cameraPreRenderScene(Ogre::Camera* cam) + { + //mViewMatrix = cam->getViewMatrix(); + } + //----------------------------------------------------------------------------------- + void HlmsManager::notifyRenderSingleObject(Ogre::Renderable* rend, const Ogre::Pass* pass, + const Ogre::AutoParamDataSource* source, const Ogre::LightList* pLightList, bool suppressRenderStateChanges) + { + if (pass->getName() == "pbs") + { + auto materialAny = rend->getUserObjectBindings().getUserAny("hlmsMat"); + if (!materialAny.isEmpty()) + { + auto material = materialAny.get(); + auto& propMap = material->getPropertyMap(); + + if (!pass->isProgrammable()) + { + // This has to be done because it is not called if the pass is not programmable + const_cast(source)->setCurrentRenderable(rend); + } + + material->updatePropertyMap(mCamera, pLightList); + + auto p = const_cast(pass); + + bool shaderHasChanged = false; + + // Vertex program + auto vertexDatablock = material->getVertexDatablock(); + if (vertexDatablock) + { + auto gpuProgram = mShaderManager.getGpuProgram(vertexDatablock); + + if (!p->hasVertexProgram() || p->getVertexProgram() != gpuProgram) + { + p->setVertexProgram(gpuProgram->getName()); + p->setVertexProgramParameters(gpuProgram->createParameters()); + shaderHasChanged = true; + } + } + + // Fragment program + auto fragmentDatablock = material->getFragmentDatablock(); + if (fragmentDatablock) + { + auto gpuProgram = mShaderManager.getGpuProgram(fragmentDatablock); + + if (!p->hasFragmentProgram() || p->getFragmentProgram() != gpuProgram) + { + p->setFragmentProgram(gpuProgram->getName()); + auto params = gpuProgram->createParameters(); + p->setFragmentProgramParameters(params); + shaderHasChanged = true; + } + } + + material->updateUniforms(mCamera, p, source, pLightList, shaderHasChanged); + } + } + } + //----------------------------------------------------------------------------------- + void HlmsManager::bind(Ogre::Renderable* rend, HlmsMaterialBase* material) + { + rend->getUserObjectBindings().setUserAny("hlmsMat", Ogre::Any(material)); + //mBindedMaterials[rend] = material; + } + //----------------------------------------------------------------------------------- +} diff --git a/Components/HLMS/src/OgreHlmsMaterialBase.cpp b/Components/HLMS/src/OgreHlmsMaterialBase.cpp new file mode 100644 index 00000000000..b663b5c6414 --- /dev/null +++ b/Components/HLMS/src/OgreHlmsMaterialBase.cpp @@ -0,0 +1,46 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE +(Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2015 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#include "OgreHlmsMaterialBase.h" + +namespace Ogre +{ + //----------------------------------------------------------------------------------- + HlmsMaterialBase::HlmsMaterialBase() : + mVertexDatablock(Ogre::GPT_VERTEX_PROGRAM, &mPropertyMap), + mFragmentDatablock(Ogre::GPT_FRAGMENT_PROGRAM, &mPropertyMap) + { + + } + //----------------------------------------------------------------------------------- + HlmsMaterialBase::~HlmsMaterialBase() + { + + } + //----------------------------------------------------------------------------------- +} diff --git a/Components/HLMS/src/OgreHlmsPbsMaterial.cpp b/Components/HLMS/src/OgreHlmsPbsMaterial.cpp new file mode 100644 index 00000000000..19b441ab00c --- /dev/null +++ b/Components/HLMS/src/OgreHlmsPbsMaterial.cpp @@ -0,0 +1,413 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE +(Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2015 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#include "OgreHlmsPbsMaterial.h" + +namespace Ogre +{ + //----------------------------------------------------------------------------------- + PbsMaterial::PbsMaterial() : mAlbedo(1, 1, 1, 0), mF0(0.1f, 0.1f, 0.1f, 1.0f), mRothness(0.1f) + { + _samplers[ST_ENV_MAP].init("environment", false, false, false, false, true, true, Ogre::TEX_TYPE_CUBE_MAP); + + _samplers[ST_MAIN_ALBEDO].init("main_albedo", true, true, false, true); + _samplers[ST_MAIN_NORMAL].init("main_normal", false, true); + _samplers[ST_MAIN_F0R].init("main_f0r", true, true, true); + + _samplers[ST_D1_ALBEDO].init("d1_albedo", true, true, false, true); + _samplers[ST_D1_NORMAL].init("d1_normal", false, true); + _samplers[ST_D1_F0R].init("d1_f0r", true, true, true); + + _samplers[ST_D2_ALBEDO].init("d2_albedo", true, true, false, true); + _samplers[ST_D2_NORMAL].init("d2_normal", false, true); + _samplers[ST_D2_F0R].init("d2_f0r", true, true, true); + + // TODO select languarge + auto languarge = "hlsl"; + mVertexDatablock.setLanguarge(languarge); + mFragmentDatablock.setLanguarge(languarge); + + if (languarge) + { + mVertexDatablock.addProfile("vs_3_0"); + mFragmentDatablock.addProfile("ps_3_0"); + } + + mVertexDatablock.setTemplateName("PBS"); + mFragmentDatablock.setTemplateName("PBS"); + } + //----------------------------------------------------------------------------------- + PbsMaterial::PbsMaterial(const PbsMaterial &obj) + { + assert(true); // this should not be copied + } + //----------------------------------------------------------------------------------- + PbsMaterial::~PbsMaterial() + { + + } + //----------------------------------------------------------------------------------- + void PbsMaterial::setEnvironmapTexture(Ogre::TexturePtr tex, float intensityFactor) + { + setTexture(ST_ENV_MAP, tex, TextureAddressing(), 0, 0, BF_ADD, intensityFactor); + } + //----------------------------------------------------------------------------------- + void PbsMaterial::setAlbedoTexture(MapSlot mapSlot, Ogre::TexturePtr tex, TextureAddressing textureAddressing, BlendFunction blendFunc, float blendFactor) + { + setTexture((SamplerType)(ST_MAIN_ALBEDO + mapSlot * 3), tex, textureAddressing, blendFactor, 0, blendFunc); + } + //----------------------------------------------------------------------------------- + void PbsMaterial::setNormalTexture(MapSlot mapSlot, Ogre::TexturePtr tex, TextureAddressing textureAddressing, float blendFactor) + { + setTexture((SamplerType)(ST_MAIN_NORMAL + mapSlot * 3), tex, textureAddressing, blendFactor); + } + //----------------------------------------------------------------------------------- + void PbsMaterial::setF0RTexture(MapSlot mapSlot, Ogre::TexturePtr tex, TextureAddressing textureAddressing, BlendFunction f0BlendFunc, float f0BlendFactor, float rBlendFactor) + { + setTexture((SamplerType)(ST_MAIN_F0R + mapSlot * 3), tex, textureAddressing, f0BlendFactor, rBlendFactor, f0BlendFunc); + } + //----------------------------------------------------------------------------------- + void PbsMaterial::setOffsetAndScale(MapSlot mapSlot, Ogre::Vector2 offset, Ogre::Vector2 scale) + { + switch (mapSlot) + { + case PbsMaterial::MS_MAIN: + mMainOffset = offset; + mMainScale = scale; + break; + case PbsMaterial::MS_D1: + mD1Offset = offset; + mD1Scale = scale; + break; + case PbsMaterial::MS_D2: + mD2Offset = offset; + mD2Scale = scale; + break; + default: + break; + } + } + //----------------------------------------------------------------------------------- + void PbsMaterial::setUvSetIndex(MapSlot mapSlot, Ogre::uint index) + { + switch (mapSlot) + { + case PbsMaterial::MS_MAIN: + mMainUvSetIndex = index; + break; + case PbsMaterial::MS_D1: + mD1UvSetIndex = index; + break; + case PbsMaterial::MS_D2: + mD2UvSetIndex = index; + break; + default: + break; + } + } + //----------------------------------------------------------------------------------- + void PbsMaterial::updatePropertyMap(Ogre::Camera* camera, const Ogre::LightList* pLightList) + { + // Update the light properties + mDirectionalLightCount = 0; + mPointLightCount = 0; + mSpotLightCount = 0; + + for (auto light : *pLightList) + { + switch (light->getType()) + { + case Ogre::Light::LT_DIRECTIONAL: + mDirectionalLightCount++; + break; + + case Ogre::Light::LT_POINT: + mPointLightCount++; + break; + + case Ogre::Light::LT_SPOTLIGHT: + mSpotLightCount++; + break; + + default: + break; + } + } + + mPropertyMap.setProperty("lights_directional_start", 0); + mPropertyMap.setProperty("lights_directional_count", mDirectionalLightCount); + + mPropertyMap.setProperty("lights_point_start", mDirectionalLightCount); + mPropertyMap.setProperty("lights_point_count", mPointLightCount); + + mPropertyMap.setProperty("lights_spot_start", mDirectionalLightCount + mPointLightCount); + mPropertyMap.setProperty("lights_spot_count", mSpotLightCount); + + mPropertyMap.setProperty("lights_count", mDirectionalLightCount + mPointLightCount + mSpotLightCount); + + // tell the shader if the hardware supports hardware gamma correction or not + // TODO check if the hardware supports gamma correction "Ogre::Root::getSingleton().getRenderSystem()->getCapabilities()" doesen't support this check + bool canHardwareGamma = true; + mPropertyMap.setProperty("hw_gamma_read", canHardwareGamma); + + // if HardwareGammaWrite is enable we don't need to bring the result from the shader to gamma space + bool isHardwareGammaWriteEnabled = camera->getViewport()->getTarget()->isHardwareGammaEnabled(); + mPropertyMap.setProperty("hw_gamma_write", canHardwareGamma && isHardwareGammaWriteEnabled); + + // UV Sets + mPropertyMap.setProperty("uvset_main_index", mMainUvSetIndex); + mPropertyMap.setProperty("uvset_d1_index", mD1UvSetIndex); + mPropertyMap.setProperty("uvset_d2_index", mD2UvSetIndex); + + // Add or remove the texture units + if (_hasSamplerListChanged) + { + int registerIndex = 0; + for (int i = 0; i < ST_COUNT; i++) + { + auto& s = _samplers[i]; + + if (s.status == SS_ACTIVE || s.status == SS_ADDED || s.status == SS_UPDATED) + { + mPropertyMap.setProperty("map_" + s.name, 1); + mPropertyMap.setProperty("map_" + s.name + "_register", registerIndex++); + } + else if (s.status == SS_REMOVED) + { + mPropertyMap.removeProperty("map_" + s.name); + mPropertyMap.removeProperty("map_" + s.name + "_register"); + } + } + } + + // Update the texture properties + if (_hasSamplerChanged) + { + for (int i = 0; i < ST_COUNT; i++) + { + auto& s = _samplers[i]; + + if (s.hasBlendFunc) + { + if (s.status == SS_ACTIVE || s.status == SS_ADDED || s.status == SS_UPDATED) + { + mPropertyMap.setProperty("blendFunc_" + s.name, s.blendFunc); + } + else if (s.status == SS_REMOVED) + { + mPropertyMap.removeProperty("blendFunc_" + s.name); + } + } + } + } + } + //----------------------------------------------------------------------------------- + void PbsMaterial::updateUniforms(Ogre::Camera* camera, Ogre::Pass* pass, const Ogre::AutoParamDataSource* source, const Ogre::LightList* pLightList, bool shaderHasChanged) + { + // Vertex program + auto vertexParams = pass->getVertexProgramParameters(); + vertexParams->setIgnoreMissingParams(true); + + vertexParams->setNamedAutoConstant("mvpMat", Ogre::GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX); + vertexParams->setNamedAutoConstant("mvMat", Ogre::GpuProgramParameters::ACT_WORLDVIEW_MATRIX); + + // Fragment program + auto fragmentParams = pass->getFragmentProgramParameters(); + fragmentParams->setIgnoreMissingParams(true); + + fragmentParams->setNamedAutoConstant("ivMat", Ogre::GpuProgramParameters::ACT_INVERSE_VIEW_MATRIX); + + fragmentParams->setNamedConstant("in_albedo", mAlbedo); + fragmentParams->setNamedConstant("in_f0", mF0); + fragmentParams->setNamedConstant("in_roughness", mRothness); + + fragmentParams->setNamedConstant("in_offset_main", mMainOffset); + fragmentParams->setNamedConstant("in_scale_main", mMainScale); + + fragmentParams->setNamedConstant("in_offset_d1", mD1Offset); + fragmentParams->setNamedConstant("in_scale_d1", mD1Scale); + + fragmentParams->setNamedConstant("in_offset_d2", mD2Offset); + fragmentParams->setNamedConstant("in_scale_d2", mD2Scale); + + // Set light uniforms + auto count = std::min(mDirectionalLightCount + mPointLightCount + mSpotLightCount, maxLightCount); + if (count) + { + auto viewMatrix = camera->getViewMatrix(); + auto viewMatrixQuat = viewMatrix.extractQuaternion(); + + for (unsigned int i = 0; i < count; i++) + { + auto light = (*pLightList)[i]; + + auto pos = viewMatrix * light->getPosition(); + mLightPositions_es[i * 3 + 0] = pos.x; + mLightPositions_es[i * 3 + 1] = pos.y; + mLightPositions_es[i * 3 + 2] = pos.z; + + auto dir = -(viewMatrixQuat * light->getDirection()).normalisedCopy(); + mLightDirections_es[i * 3 + 0] = dir.x; + mLightDirections_es[i * 3 + 1] = dir.y; + mLightDirections_es[i * 3 + 2] = dir.z; + + auto color = light->getDiffuseColour(); + mLightColors[i * 3 + 0] = color.r; + mLightColors[i * 3 + 1] = color.g; + mLightColors[i * 3 + 2] = color.b; + + mLightParameters[i * 3 + 0] = light->getAttenuationRange(); + mLightParameters[i * 3 + 1] = Ogre::Math::Cos(light->getSpotlightOuterAngle() / 2.0); + mLightParameters[i * 3 + 2] = light->getSpotlightFalloff(); + } + + fragmentParams->setNamedConstant("lightPositions_es", &(mLightPositions_es[0]), count, 3); + fragmentParams->setNamedConstant("lightDirections_es", &(mLightDirections_es[0]), count, 3); + fragmentParams->setNamedConstant("lightColors", &(mLightColors[0]), count, 3); + fragmentParams->setNamedConstant("lightParameters", &(mLightParameters[0]), count, 3); + } + + // update the textures + if (shaderHasChanged) + { + pass->removeAllTextureUnitStates(); + + for (int i = 0; i < ST_COUNT; i++) + { + auto& s = _samplers[i]; + if (s.status == SS_ACTIVE || s.status == SS_ADDED || s.status == SS_UPDATED) + { + s.textureUnitState = pass->createTextureUnitState("map_" + s.name); + updateTexturUnits(s.textureUnitState, fragmentParams, s); + s.status = SS_ACTIVE; + } + else + { + s.status = SS_NOT_ACTIVE; + } + } + } + else if (_hasSamplerChanged) + { + for (int i = 0; i < ST_COUNT; i++) + { + auto& s = _samplers[i]; + if (s.status == SS_UPDATED) + { + updateTexturUnits(s.textureUnitState, fragmentParams, s); + s.status = SS_ACTIVE; + } + } + } + + _hasSamplerListChanged = false; + _hasSamplerChanged = false; + } + //----------------------------------------------------------------------------------- + void PbsMaterial::updateTexturUnits(Ogre::TextureUnitState* textureUnitState, Ogre::GpuProgramParametersSharedPtr fragmentParams, SamplerContainer& s) + { + fragmentParams->setNamedConstant("in_map_" + s.name, 0); + + if (s.textureType == Ogre::TEX_TYPE_2D) + { + s.textureUnitState->setTexture(s.tex); + s.textureUnitState->setTextureAddressingMode(s.textureAddressing.u, s.textureAddressing.v, Ogre::TextureUnitState::TAM_WRAP); + } + else if (s.textureType == Ogre::TEX_TYPE_CUBE_MAP) + { + s.textureUnitState->setCubicTexture(&s.tex, true); + } + + s.textureUnitState->setTextureFiltering(Ogre::TFO_TRILINEAR); + + if (s.hasIntensity) + { + fragmentParams->setNamedConstant("in_map_" + s.name + "_intensity", s.intensity); + } + + if (s.hasMipmapCount) + { + fragmentParams->setNamedConstant("in_map_" + s.name + "_mipmapcount", s.mipmapCount); + } + + if (s.hasBlendFactor1) + { + fragmentParams->setNamedConstant("in_blendfactor1_" + s.name, s.blendFactor1); + } + + if (s.hasBlendFactor2) + { + fragmentParams->setNamedConstant("in_blendfactor2_" + s.name, s.blendFactor2); + } + } + //----------------------------------------------------------------------------------- + void PbsMaterial::setTexture(SamplerType samplerType, Ogre::TexturePtr tex, TextureAddressing textureAddr, + float blendFactor1, float blendFactor2, BlendFunction blendFunc, float intensityFactor) + { + auto& s = _samplers[samplerType]; + if (s.status == SS_ACTIVE && tex == s.tex && s.blendFunc == blendFunc && s.blendFactor1 == blendFactor1 && s.blendFactor2 == blendFactor2 && + s.intensity == intensityFactor && s.textureAddressing == textureAddr) + return; + if (s.status == SS_NOT_ACTIVE && tex.isNull()) + return; + + if (!tex.isNull()) + { + // Ensure that the texture in the shader is in linear space + tex->setHardwareGammaEnabled(s.needsGammaCorrection); + + if (s.status == SS_NOT_ACTIVE) s.status = SS_ADDED; + else if (s.status == SS_ACTIVE) s.status = SS_UPDATED; + else if (s.status == SS_UPDATED) s.status = SS_UPDATED; + else if (s.status == SS_ADDED) s.status = SS_ADDED; + else if (s.status == SS_REMOVED) s.status = SS_UPDATED; + } + else + { + if (s.status == SS_NOT_ACTIVE) s.status = SS_NOT_ACTIVE; + else if (s.status == SS_ACTIVE) s.status = SS_REMOVED; + else if (s.status == SS_UPDATED) s.status = SS_REMOVED; + else if (s.status == SS_ADDED) s.status = SS_NOT_ACTIVE; + else if (s.status == SS_REMOVED) s.status = SS_REMOVED; + } + + s.tex = tex; + s.textureAddressing = textureAddr; + + s.blendFunc = blendFunc; + s.blendFactor1 = blendFactor1; + s.blendFactor2 = blendFactor2; + + s.intensity = intensityFactor; + s.mipmapCount = tex.isNull() ? 0 : tex->getNumMipmaps(); + + _hasSamplerChanged = true; + _hasSamplerListChanged = s.status == SS_ADDED || s.status == SS_REMOVED; + } + //----------------------------------------------------------------------------------- +} diff --git a/Components/HLMS/src/OgreHlmsPropertyHelper.cpp b/Components/HLMS/src/OgreHlmsPropertyHelper.cpp new file mode 100644 index 00000000000..b2ddeab1763 --- /dev/null +++ b/Components/HLMS/src/OgreHlmsPropertyHelper.cpp @@ -0,0 +1,85 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE +(Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2015 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#include "OgreHlmsPropertyHelper.h" + +namespace Ogre +{ + //Change per mesh (hash can be cached on the renderable) + const IdString DefaultProperties::Skeleton = IdString("hlms_skeleton"); + const IdString DefaultProperties::BonesPerVertex = IdString("hlms_bones_per_vertex"); + const IdString DefaultProperties::Pose = IdString("hlms_pose"); + + const IdString DefaultProperties::Normal = IdString("hlms_normal"); + const IdString DefaultProperties::QTangent = IdString("hlms_qtangent"); + const IdString DefaultProperties::Tangent = IdString("hlms_tangent"); + + const IdString DefaultProperties::Colour = IdString("hlms_colour"); + + const IdString DefaultProperties::UvCount = IdString("hlms_uv_count"); + const IdString DefaultProperties::UvCount0 = IdString("hlms_uv_count0"); + const IdString DefaultProperties::UvCount1 = IdString("hlms_uv_count1"); + const IdString DefaultProperties::UvCount2 = IdString("hlms_uv_count2"); + const IdString DefaultProperties::UvCount3 = IdString("hlms_uv_count3"); + const IdString DefaultProperties::UvCount4 = IdString("hlms_uv_count4"); + const IdString DefaultProperties::UvCount5 = IdString("hlms_uv_count5"); + const IdString DefaultProperties::UvCount6 = IdString("hlms_uv_count6"); + const IdString DefaultProperties::UvCount7 = IdString("hlms_uv_count7"); + + //Change per frame (grouped together with scene pass) + const IdString DefaultProperties::LightsDirectional = IdString("hlms_lights_directional"); + const IdString DefaultProperties::LightsPoint = IdString("hlms_lights_point"); + const IdString DefaultProperties::LightsSpot = IdString("hlms_lights_spot"); + const IdString DefaultProperties::LightsAttenuation = IdString("hlms_lights_attenuation"); + const IdString DefaultProperties::LightsSpotParams = IdString("hlms_lights_spotparams"); + + //Change per scene pass + const IdString DefaultProperties::DualParaboloidMapping = IdString("hlms_dual_paraboloid_mapping"); + const IdString DefaultProperties::NumShadowMaps = IdString("hlms_num_shadow_maps"); + const IdString DefaultProperties::PssmSplits = IdString("hlms_pssm_splits"); + const IdString DefaultProperties::ShadowCaster = IdString("hlms_shadowcaster"); + + //Change per material (hash can be cached on the renderable) + const IdString DefaultProperties::AlphaTest = IdString("alpha_test"); + + const IdString DefaultProperties::GL3Plus = IdString("GL3+"); + const IdString DefaultProperties::HighQuality = IdString("hlms_high_quality"); + + const IdString *DefaultProperties::UvCountPtrs[8] = + { + &DefaultProperties::UvCount0, + &DefaultProperties::UvCount1, + &DefaultProperties::UvCount2, + &DefaultProperties::UvCount3, + &DefaultProperties::UvCount4, + &DefaultProperties::UvCount5, + &DefaultProperties::UvCount6, + &DefaultProperties::UvCount7 + }; +} + diff --git a/Components/HLMS/src/OgreHlmsPropertyMap.cpp b/Components/HLMS/src/OgreHlmsPropertyMap.cpp new file mode 100644 index 00000000000..7b273da8793 --- /dev/null +++ b/Components/HLMS/src/OgreHlmsPropertyMap.cpp @@ -0,0 +1,132 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE +(Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2015 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#include "OgreHlmsPropertyMap.h" +#include "OgreHlmsPropertyHelper.h" +#include "OgreHlmsShaderCommon.h" + +namespace Ogre +{ + //----------------------------------------------------------------------------------- + PropertyMap::PropertyMap() : mHash(0) + { + } + //----------------------------------------------------------------------------------- + PropertyMap::~PropertyMap() + { + } + //----------------------------------------------------------------------------------- + void PropertyMap::setCommonProperties(void) + { + Ogre::uint16 numWorldTransforms = 2; + + setProperty(DefaultProperties::Skeleton, numWorldTransforms > 1); + setProperty(DefaultProperties::UvCount, 2); + setProperty( "true", 1 ); + setProperty( "false", 0 ); + + setProperty(DefaultProperties::DualParaboloidMapping, 0); + + setProperty(DefaultProperties::Normal, 1); + + setProperty(DefaultProperties::UvCount0, 2); + setProperty(DefaultProperties::UvCount1, 4); + setProperty(DefaultProperties::BonesPerVertex, 4); + + setProperty(DefaultProperties::NumShadowMaps, 3); + setProperty(DefaultProperties::PssmSplits, 3); + setProperty(DefaultProperties::ShadowCaster, 0); + + setProperty(DefaultProperties::LightsDirectional, 1); + setProperty(DefaultProperties::LightsPoint, 2); + setProperty(DefaultProperties::LightsSpot, 3); + } + //----------------------------------------------------------------------------------- + void PropertyMap::setProperty(IdString key, Ogre::int32 value) + { + Property p( key, value ); + auto it = std::lower_bound(mProperties.begin(), mProperties.end(), p, orderPropertyByIdString); + if (it == mProperties.end() || it->keyName != p.keyName) + mProperties.insert(it, p); + else + *it = p; + + mHash = 0; + } + //----------------------------------------------------------------------------------- + bool PropertyMap::hasProperty(IdString key) + { + Property p(key, 0); + auto it = std::lower_bound(mProperties.begin(), mProperties.end(), p, orderPropertyByIdString); + return it != mProperties.end() && it->keyName == p.keyName; + } + //----------------------------------------------------------------------------------- + Ogre::int32 PropertyMap::getProperty(IdString key, Ogre::int32 defaultVal) const + { + Property p( key, 0 ); + auto it = std::lower_bound(mProperties.begin(), mProperties.end(), p, orderPropertyByIdString); + if (it != mProperties.end() && it->keyName == p.keyName) + defaultVal = it->value; + + return defaultVal; + } + //----------------------------------------------------------------------------------- + void PropertyMap::removeProperty(IdString key) + { + Property p(key, 0); + auto it = std::lower_bound(mProperties.begin(), mProperties.end(), p, orderPropertyByIdString); + if (it != mProperties.end() && it->keyName == p.keyName) + mProperties.erase(it); + } + //----------------------------------------------------------------------------------- + Ogre::uint32 PropertyMap::getHash() + { + if (mProperties.size() == 0) + { + mHash = 0; + } + else + { + if (mHash == 0) + { + float* buffer = new float[mProperties.size() * 2]; + int i = 0; + for (auto prop : mProperties) + { + buffer[i++] = prop.keyName.mHash; + buffer[i++] = prop.value; + } + + mHash = calcHash((void*)buffer, mProperties.size() * 2 * sizeof(float)); + } + } + + return mHash; + } + //----------------------------------------------------------------------------------- +} diff --git a/Components/HLMS/src/OgreHlmsShaderGenerator.cpp b/Components/HLMS/src/OgreHlmsShaderGenerator.cpp new file mode 100644 index 00000000000..09de1612f47 --- /dev/null +++ b/Components/HLMS/src/OgreHlmsShaderGenerator.cpp @@ -0,0 +1,956 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE +(Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2015 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#include "OgreHlmsShaderGenerator.h" + +namespace Ogre +{ + //----------------------------------------------------------------------------------- + void ShaderGenerator::findBlockEnd(SubStringRef &outSubString, bool &syntaxError) + { + const char *blockNames[] = + { + "foreach", + "property", + "piece" + }; + + Ogre::String::const_iterator it = outSubString.begin(); + Ogre::String::const_iterator en = outSubString.end(); + + int nesting = 0; + + while (it != en && nesting >= 0) + { + if (*it == '@') + { + SubStringRef subString(&outSubString.getOriginalBuffer(), it + 1); + + size_t idx = subString.find("end"); + if (idx == 0) + { + --nesting; + it += sizeof("end") - 1; + } + else + { + for (size_t i = 0; i < sizeof(blockNames) / sizeof(char*); ++i) + { + size_t idxBlock = subString.find(blockNames[i]); + if (idxBlock == 0) + { + it = subString.begin() + strlen(blockNames[i]); + ++nesting; + break; + } + } + } + } + + ++it; + } + + assert(nesting >= -1); + + if (it != en && nesting < 0) + outSubString.setEnd(it - outSubString.getOriginalBuffer().begin() - sizeof("end")); + else + { + syntaxError = false; + printf("Syntax Error at line %lu: start block (e.g. @foreach; @property) " + "without matching @end\n", calculateLineCount(outSubString)); + } + } + //----------------------------------------------------------------------------------- + bool ShaderGenerator::evaluateExpression(SubStringRef &outSubString, bool &outSyntaxError, PropertyMap &properties) + { + size_t expEnd = evaluateExpressionEnd(outSubString); + + if (expEnd == Ogre::String::npos) + { + outSyntaxError = true; + return false; + } + + SubStringRef subString(&outSubString.getOriginalBuffer(), outSubString.getStart(), + outSubString.getStart() + expEnd); + + outSubString = SubStringRef(&outSubString.getOriginalBuffer(), + outSubString.getStart() + expEnd + 1); + + bool textStarted = false; + bool syntaxError = false; + bool nextExpressionNegates = false; + + std::vector expressionParents; + ExpressionVec outExpressions; + outExpressions.clear(); + outExpressions.resize(1); + + Expression *currentExpression = &outExpressions.back(); + + Ogre::String::const_iterator it = subString.begin(); + Ogre::String::const_iterator en = subString.end(); + + while (it != en && !syntaxError) + { + char c = *it; + + if (c == '(') + { + currentExpression->children.push_back(Expression()); + expressionParents.push_back(currentExpression); + + currentExpression->children.back().negated = nextExpressionNegates; + + textStarted = false; + nextExpressionNegates = false; + + currentExpression = ¤tExpression->children.back(); + } + else if (c == ')') + { + if (expressionParents.empty()) + syntaxError = true; + else + { + currentExpression = expressionParents.back(); + expressionParents.pop_back(); + } + + textStarted = false; + } + else if (c == ' ' || c == '\t' || c == '\n' || c == '\r') + { + textStarted = false; + } + else if (c == '!') + { + nextExpressionNegates = true; + } + else + { + if (!textStarted) + { + textStarted = true; + currentExpression->children.push_back(Expression()); + currentExpression->children.back().negated = nextExpressionNegates; + } + + if (c == '&' || c == '|') + { + if (currentExpression->children.empty() || nextExpressionNegates) + { + syntaxError = true; + } + else if (!currentExpression->children.back().value.empty() && + c != *(currentExpression->children.back().value.end() - 1)) + { + currentExpression->children.push_back(Expression()); + } + } + + currentExpression->children.back().value.push_back(c); + nextExpressionNegates = false; + } + + ++it; + } + + bool retVal = false; + + if (!expressionParents.empty()) + syntaxError = true; + + if (!syntaxError) + retVal = evaluateExpressionRecursive(outExpressions, syntaxError, properties); + + if (syntaxError) + printf("Syntax Error at line %lu\n", calculateLineCount(subString)); + + outSyntaxError = syntaxError; + + return retVal; + } + //----------------------------------------------------------------------------------- + bool ShaderGenerator::evaluateExpressionRecursive(ExpressionVec &expression, bool &outSyntaxError, PropertyMap &properties) + { + ExpressionVec::iterator itor = expression.begin(); + ExpressionVec::iterator end = expression.end(); + + while (itor != end) + { + if (itor->value == "&&") + itor->type = EXPR_OPERATOR_AND; + else if (itor->value == "||") + itor->type = EXPR_OPERATOR_OR; + else if (!itor->children.empty()) + itor->type = EXPR_OBJECT; + else + itor->type = EXPR_VAR; + + ++itor; + } + + bool syntaxError = outSyntaxError; + bool lastExpWasOperator = true; + + itor = expression.begin(); + + while (itor != end && !syntaxError) + { + Expression &exp = *itor; + if (((exp.type == EXPR_OPERATOR_OR || exp.type == EXPR_OPERATOR_AND) && lastExpWasOperator) || + ((exp.type == EXPR_VAR || exp.type == EXPR_OBJECT) && !lastExpWasOperator)) + { + syntaxError = true; + printf("Unrecognized token '%s'", exp.value.c_str()); + } + else if (exp.type == EXPR_OPERATOR_OR || exp.type == EXPR_OPERATOR_AND) + { + lastExpWasOperator = true; + } + else if (exp.type == EXPR_VAR) + { + exp.result = properties.getProperty(exp.value) != 0; + lastExpWasOperator = false; + } + else + { + exp.result = evaluateExpressionRecursive(exp.children, syntaxError, properties); + lastExpWasOperator = false; + } + + ++itor; + } + + bool retVal = true; + + if (!syntaxError) + { + itor = expression.begin(); + bool andMode = true; + + while (itor != end) + { + if (itor->type == EXPR_OPERATOR_OR) + andMode = false; + else if (itor->type == EXPR_OPERATOR_AND) + andMode = true; + else + { + if (andMode) + retVal &= itor->negated ? !itor->result : itor->result; + else + retVal |= itor->negated ? !itor->result : itor->result; + } + + ++itor; + } + } + + outSyntaxError = syntaxError; + + return retVal; + } + //----------------------------------------------------------------------------------- + size_t ShaderGenerator::evaluateExpressionEnd(const SubStringRef &outSubString) + { + Ogre::String::const_iterator it = outSubString.begin(); + Ogre::String::const_iterator en = outSubString.end(); + + int nesting = 0; + + while (it != en && nesting >= 0) + { + if (*it == '(') + ++nesting; + else if (*it == ')') + --nesting; + ++it; + } + + assert(nesting >= -1); + + size_t retVal = Ogre::String::npos; + if (it != en && nesting < 0) + { + retVal = it - outSubString.begin() - 1; + } + else + { + printf("Syntax Error at line %lu: opening parenthesis without matching closure\n", + calculateLineCount(outSubString)); + } + + return retVal; + } + //----------------------------------------------------------------------------------- + void ShaderGenerator::evaluateParamArgs(SubStringRef &outSubString, Ogre::StringVector &outArgs, + bool &outSyntaxError) + { + size_t expEnd = evaluateExpressionEnd(outSubString); + + if (expEnd == Ogre::String::npos) + { + outSyntaxError = true; + return; + } + + SubStringRef subString(&outSubString.getOriginalBuffer(), outSubString.getStart(), + outSubString.getStart() + expEnd); + + outSubString = SubStringRef(&outSubString.getOriginalBuffer(), + outSubString.getStart() + expEnd + 1); + + int expressionState = 0; + bool syntaxError = false; + + outArgs.clear(); + outArgs.push_back(Ogre::String()); + + Ogre::String::const_iterator it = subString.begin(); + Ogre::String::const_iterator en = subString.end(); + + while (it != en && !syntaxError) + { + char c = *it; + + if (c == '(' || c == ')' || c == '@' || c == '&' || c == '|') + { + syntaxError = true; + } + else if (c == ' ' || c == '\t' || c == '\n' || c == '\r') + { + if (expressionState == 1) + expressionState = 2; + } + else if (c == ',') + { + expressionState = 0; + outArgs.push_back(Ogre::String()); + } + else + { + if (expressionState == 2) + { + printf("Syntax Error at line %lu: ',' or ')' expected\n", + calculateLineCount(subString)); + syntaxError = true; + } + else + { + outArgs.back().push_back(*it); + expressionState = 1; + } + } + + ++it; + } + + if (syntaxError) + printf("Syntax Error at line %lu\n", calculateLineCount(subString)); + + outSyntaxError = syntaxError; + } + //----------------------------------------------------------------------------------- + void ShaderGenerator::copy(Ogre::String &outBuffer, const SubStringRef &inSubString, size_t length) + { + Ogre::String::const_iterator itor = inSubString.begin(); + Ogre::String::const_iterator end = inSubString.begin() + length; + + while (itor != end) + outBuffer.push_back(*itor++); + } + //----------------------------------------------------------------------------------- + void ShaderGenerator::repeat(Ogre::String &outBuffer, const SubStringRef &inSubString, size_t length, + size_t passNum, const Ogre::String &counterVar) + { + Ogre::String::const_iterator itor = inSubString.begin(); + Ogre::String::const_iterator end = inSubString.begin() + length; + + while (itor != end) + { + if (*itor == '@' && !counterVar.empty()) + { + SubStringRef subString(&inSubString.getOriginalBuffer(), itor + 1); + if (subString.find(counterVar) == 0) + { + char tmp[16]; + sprintf(tmp, "%lu", passNum); + outBuffer += tmp; + itor += counterVar.size() + 1; + } + else + { + outBuffer.push_back(*itor++); + } + } + else + { + outBuffer.push_back(*itor++); + } + } + } + //----------------------------------------------------------------------------------- + int setOp(int op1, int op2) { return op2; } + int addOp(int op1, int op2) { return op1 + op2; } + int subOp(int op1, int op2) { return op1 - op2; } + int mulOp(int op1, int op2) { return op1 * op2; } + int divOp(int op1, int op2) { return op1 / op2; } + int modOp(int op1, int op2) { return op1 % op2; } + + struct Operation + { + const char *opName; + size_t length; + int(*opFunc)(int, int); + Operation(const char *_name, size_t len, int(*_opFunc)(int, int)) : + opName(_name), length(len), opFunc(_opFunc) {} + }; + + const Operation c_operations[6] = + { + Operation("pset", sizeof("@pset"), &setOp), + Operation("padd", sizeof("@padd"), &addOp), + Operation("psub", sizeof("@psub"), &subOp), + Operation("pmul", sizeof("@pmul"), &mulOp), + Operation("pdiv", sizeof("@pdiv"), &divOp), + Operation("pmod", sizeof("@pmod"), &modOp) + }; + //----------------------------------------------------------------------------------- + bool ShaderGenerator::parseMath(const Ogre::String &inBuffer, Ogre::String &outBuffer, PropertyMap &properties) + { + outBuffer.clear(); + outBuffer.reserve(inBuffer.size()); + + Ogre::StringVector argValues; + SubStringRef subString(&inBuffer, 0); + + size_t pos; + pos = subString.find("@"); + size_t keyword = ~0; + + while (pos != Ogre::String::npos && keyword == (size_t)~0) + { + size_t maxSize = subString.findFirstOf(" \t(", pos + 1); + maxSize = maxSize == Ogre::String::npos ? subString.getSize() : maxSize; + SubStringRef keywordStr(&inBuffer, subString.getStart() + pos + 1, + subString.getStart() + maxSize); + + for (size_t i = 0; i < 6 && keyword == (size_t)~0; ++i) + { + if (keywordStr.matchEqual(c_operations[i].opName)) + keyword = i; + } + + if (keyword == (size_t)~0) + pos = subString.find("@", pos + 1); + } + + bool syntaxError = false; + + while (pos != Ogre::String::npos && !syntaxError) + { + //Copy what comes before the block + copy(outBuffer, subString, pos); + + subString.setStart(subString.getStart() + pos + c_operations[keyword].length); + evaluateParamArgs(subString, argValues, syntaxError); + + syntaxError |= argValues.size() < 2 || argValues.size() > 3; + + if (!syntaxError) + { + IdString dstProperty; + IdString srcProperty; + int op1Value; + int op2Value; + + dstProperty = argValues[0]; + size_t idx = 1; + srcProperty = dstProperty; + if (argValues.size() == 3) + srcProperty = argValues[idx++]; + op1Value = properties.getProperty(srcProperty); + op2Value = Ogre::StringConverter::parseInt(argValues[idx], + -std::numeric_limits::max()); + + if (op2Value == -std::numeric_limits::max()) + { + //Not a number, interpret as property + op2Value = properties.getProperty(argValues[idx]); + } + + int result = c_operations[keyword].opFunc(op1Value, op2Value); + properties.setProperty(dstProperty, result); + } + else + { + size_t lineCount = calculateLineCount(subString); + if (keyword <= 1) + { + printf("Syntax Error at line %lu: @%s expects one parameter", + lineCount, c_operations[keyword].opName); + } + else + { + printf("Syntax Error at line %lu: @%s expects two or three parameters", + lineCount, c_operations[keyword].opName); + } + } + + pos = subString.find("@"); + keyword = ~0; + + while (pos != Ogre::String::npos && keyword == (size_t)~0) + { + size_t maxSize = subString.findFirstOf(" \t(", pos + 1); + maxSize = maxSize == Ogre::String::npos ? subString.getSize() : maxSize; + SubStringRef keywordStr(&inBuffer, subString.getStart() + pos + 1, + subString.getStart() + maxSize); + + for (size_t i = 0; i < 6 && keyword == (size_t)~0; ++i) + { + if (keywordStr.matchEqual(c_operations[i].opName)) + keyword = i; + } + + if (keyword == (size_t)~0) + pos = subString.find("@", pos + 1); + } + } + + copy(outBuffer, subString, subString.getSize()); + + return syntaxError; + } + //----------------------------------------------------------------------------------- + bool ShaderGenerator::parseForEach(const Ogre::String &inBuffer, Ogre::String &outBuffer, PropertyMap &properties) + { + outBuffer.clear(); + outBuffer.reserve(inBuffer.size()); + + Ogre::StringVector argValues; + SubStringRef subString(&inBuffer, 0); + size_t pos = subString.find("@foreach"); + + bool syntaxError = false; + + while (pos != Ogre::String::npos && !syntaxError) + { + //Copy what comes before the block + copy(outBuffer, subString, pos); + + subString.setStart(subString.getStart() + pos + sizeof("@foreach")); + evaluateParamArgs(subString, argValues, syntaxError); + + SubStringRef blockSubString = subString; + findBlockEnd(blockSubString, syntaxError); + + if (!syntaxError) + { + char *endPtr; + + // Arg 1 (var) + Ogre::String counterVar; + counterVar = argValues[0]; + + // Agr 2 (start) + int start = strtol(argValues[1].c_str(), &endPtr, 10); + if (argValues[1].c_str() == endPtr) + { + //This isn't a number. Let's try if it's a variable + start = properties.getProperty(argValues[1], 0); + } + + // Arg 3 (count) + int count = strtol(argValues[2].c_str(), &endPtr, 10); + if (argValues[2].c_str() == endPtr) + { + //This isn't a number. Let's try if it's a variable + count = properties.getProperty(argValues[2], 0); + } + + // Repead the block + for (int i = start; i < count; ++i) + repeat(outBuffer, blockSubString, blockSubString.getSize(), i, counterVar); + } + + subString.setStart(blockSubString.getEnd() + sizeof("@end")); + pos = subString.find("@foreach"); + } + + copy(outBuffer, subString, subString.getSize()); + + return syntaxError; + } + //----------------------------------------------------------------------------------- + bool ShaderGenerator::parseProperties(Ogre::String &inBuffer, Ogre::String &outBuffer, PropertyMap &properties) + { + outBuffer.clear(); + outBuffer.reserve(inBuffer.size()); + + SubStringRef subString(&inBuffer, 0); + size_t pos = subString.find("@property"); + + bool syntaxError = false; + + while (pos != Ogre::String::npos && !syntaxError) + { + //Copy what comes before the block + copy(outBuffer, subString, pos); + + subString.setStart(subString.getStart() + pos + sizeof("@property")); + bool result = evaluateExpression(subString, syntaxError, properties); + + SubStringRef blockSubString = subString; + findBlockEnd(blockSubString, syntaxError); + + if (result && !syntaxError) + copy(outBuffer, blockSubString, blockSubString.getSize()); + + subString.setStart(blockSubString.getEnd() + sizeof("@end") - 1); + pos = subString.find("@property"); + } + + copy(outBuffer, subString, subString.getSize()); + + while (!syntaxError && outBuffer.find("@property") != Ogre::String::npos) + { + inBuffer.swap(outBuffer); + syntaxError = parseProperties(inBuffer, outBuffer, properties); + } + + return syntaxError; + } + //----------------------------------------------------------------------------------- + bool ShaderGenerator::collectPieces(const Ogre::String &inBuffer, Ogre::String &outBuffer, PropertyMap &properties, PiecesMap& pieces) + { + outBuffer.clear(); + outBuffer.reserve(inBuffer.size()); + + Ogre::StringVector argValues; + SubStringRef subString(&inBuffer, 0); + size_t pos = subString.find("@piece"); + + bool syntaxError = false; + + while (pos != Ogre::String::npos && !syntaxError) + { + //Copy what comes before the block + copy(outBuffer, subString, pos); + + subString.setStart(subString.getStart() + pos + sizeof("@piece")); + evaluateParamArgs(subString, argValues, syntaxError); + + syntaxError |= argValues.size() != 1; + + if (!syntaxError) + { + const IdString pieceName(argValues[0]); + PiecesMap::const_iterator it = pieces.find(pieceName); + if (it != pieces.end()) + { + syntaxError = true; + printf("Error at line %lu: @piece '%s' already defined", + calculateLineCount(subString), argValues[0].c_str()); + } + else + { + SubStringRef blockSubString = subString; + findBlockEnd(blockSubString, syntaxError); + + Ogre::String tmpBuffer; + copy(tmpBuffer, blockSubString, blockSubString.getSize()); + pieces[pieceName] = tmpBuffer; + + subString.setStart(blockSubString.getEnd() + sizeof("@end")); + } + } + else + { + printf("Syntax Error at line %lu: @piece expects one parameter", + calculateLineCount(subString)); + } + + pos = subString.find("@piece"); + } + + copy(outBuffer, subString, subString.getSize()); + + return syntaxError; + } + //----------------------------------------------------------------------------------- + bool ShaderGenerator::insertPieces(Ogre::String &inBuffer, Ogre::String &outBuffer, PropertyMap &properties, PiecesMap& pieces) + { + outBuffer.clear(); + outBuffer.reserve(inBuffer.size()); + + Ogre::StringVector argValues; + SubStringRef subString(&inBuffer, 0); + size_t pos = subString.find("@insertpiece"); + + bool syntaxError = false; + + while (pos != Ogre::String::npos && !syntaxError) + { + //Copy what comes before the block + copy(outBuffer, subString, pos); + + subString.setStart(subString.getStart() + pos + sizeof("@insertpiece")); + evaluateParamArgs(subString, argValues, syntaxError); + + syntaxError |= argValues.size() != 1; + + if (!syntaxError) + { + const IdString pieceName(argValues[0]); + PiecesMap::const_iterator it = pieces.find(pieceName); + if (it != pieces.end()) + outBuffer += it->second; + } + else + { + printf("Syntax Error at line %lu: @insertpiece expects one parameter", + calculateLineCount(subString)); + } + + pos = subString.find("@insertpiece"); + } + + copy(outBuffer, subString, subString.getSize()); + + while (!syntaxError && outBuffer.find("@insertpiece") != Ogre::String::npos) + { + inBuffer.swap(outBuffer); + syntaxError = insertPieces(inBuffer, outBuffer, properties, pieces); + } + + return syntaxError; + } + //----------------------------------------------------------------------------------- + const Operation c_counterOperations[8] = + { + Operation("counter", sizeof("@counter"), 0), + Operation("value", sizeof("@value"), 0), + Operation("set", sizeof("@set"), &setOp), + Operation("add", sizeof("@add"), &addOp), + Operation("sub", sizeof("@sub"), &subOp), + Operation("mul", sizeof("@mul"), &mulOp), + Operation("div", sizeof("@div"), &divOp), + Operation("mod", sizeof("@mod"), &modOp) + }; + //----------------------------------------------------------------------------------- + bool ShaderGenerator::parseCounter(const Ogre::String &inBuffer, Ogre::String &outBuffer, PropertyMap &properties) + { + outBuffer.clear(); + outBuffer.reserve(inBuffer.size()); + + Ogre::StringVector argValues; + SubStringRef subString(&inBuffer, 0); + + size_t pos; + pos = subString.find("@"); + size_t keyword = ~0; + + if (pos != Ogre::String::npos) + { + size_t maxSize = subString.findFirstOf(" \t(", pos + 1); + SubStringRef keywordStr(&inBuffer, subString.getStart() + pos + 1, + subString.getStart() + maxSize); + + for (size_t i = 0; i < 8 && keyword == (size_t)~0; ++i) + { + if (keywordStr.matchEqual(c_counterOperations[i].opName)) + keyword = i; + } + + if (keyword == (size_t)~0) + pos = Ogre::String::npos; + } + + bool syntaxError = false; + + while (pos != Ogre::String::npos && !syntaxError) + { + //Copy what comes before the block + copy(outBuffer, subString, pos); + + subString.setStart(subString.getStart() + pos + c_counterOperations[keyword].length); + evaluateParamArgs(subString, argValues, syntaxError); + + if (keyword <= 1) + syntaxError |= argValues.size() != 1; + else + syntaxError |= argValues.size() < 2 || argValues.size() > 3; + + if (!syntaxError) + { + IdString dstProperty; + IdString srcProperty; + int op1Value; + int op2Value; + + if (argValues.size() == 1) + { + dstProperty = argValues[0]; + srcProperty = dstProperty; + op1Value = properties.getProperty(srcProperty); + op2Value = op1Value; + + //@value & @counter write, the others are invisible + char tmp[16]; + sprintf(tmp, "%i", op1Value); + outBuffer += tmp; + + if (keyword == 0) + { + ++op1Value; + properties.setProperty(dstProperty, op1Value); + } + } + else + { + dstProperty = argValues[0]; + size_t idx = 1; + srcProperty = dstProperty; + if (argValues.size() == 3) + srcProperty = argValues[idx++]; + op1Value = properties.getProperty(srcProperty); + op2Value = Ogre::StringConverter::parseInt(argValues[idx], + -std::numeric_limits::max()); + + if (op2Value == -std::numeric_limits::max()) + { + //Not a number, interpret as property + op2Value = properties.getProperty(argValues[idx]); + } + + int result = c_counterOperations[keyword].opFunc(op1Value, op2Value); + properties.setProperty(dstProperty, result); + } + } + else + { + size_t lineCount = calculateLineCount(subString); + if (keyword <= 1) + { + printf("Syntax Error at line %lu: @%s expects one parameter", + lineCount, c_counterOperations[keyword].opName); + } + else + { + printf("Syntax Error at line %lu: @%s expects two or three parameters", + lineCount, c_counterOperations[keyword].opName); + } + } + + pos = subString.find("@"); + keyword = ~0; + + if (pos != Ogre::String::npos) + { + size_t maxSize = subString.findFirstOf(" \t(", pos + 1); + SubStringRef keywordStr(&inBuffer, subString.getStart() + pos + 1, + subString.getStart() + maxSize); + + for (size_t i = 0; i < 8 && keyword == (size_t)~0; ++i) + { + if (keywordStr.matchEqual(c_counterOperations[i].opName)) + keyword = i; + } + + if (keyword == (size_t)~0) + pos = Ogre::String::npos; + } + } + + copy(outBuffer, subString, subString.getSize()); + + return syntaxError; + } + //----------------------------------------------------------------------------------- + Ogre::String ShaderGenerator::parse(Ogre::String &inBuffer, PropertyMap &properties, Ogre::StringVector& pieceFiles) + { + Ogre::String outBuffer; + outBuffer.reserve(inBuffer.size()); + + //Collect pieces + auto itor = pieceFiles.begin(); + auto end = pieceFiles.end(); + + Ogre::String inPiece; + Ogre::String outPiece; + + PiecesMap pieces; + + while (itor != end) + { + parseMath(*itor, inPiece, properties); + parseForEach(inPiece, outPiece, properties); + parseProperties(outPiece, inPiece, properties); + collectPieces(inPiece, outPiece, properties, pieces); + ++itor; + } + + parseMath(inBuffer, outBuffer, properties); + parseForEach(outBuffer, inBuffer, properties); + parseProperties(inBuffer, outBuffer, properties); + collectPieces(outBuffer, inBuffer, properties, pieces); + insertPieces(inBuffer, outBuffer, properties, pieces); + parseCounter(outBuffer, inBuffer, properties); + + outBuffer.swap(inBuffer); + + return outBuffer; + } + //----------------------------------------------------------------------------------- + size_t ShaderGenerator::calculateLineCount(const Ogre::String &buffer, size_t idx) + { + Ogre::String::const_iterator itor = buffer.begin(); + Ogre::String::const_iterator end = buffer.begin() + idx; + + size_t lineCount = 0; + + while (itor != end) + { + if (*itor == '\n') + ++lineCount; + ++itor; + } + + return lineCount + 1; + } + //----------------------------------------------------------------------------------- + size_t ShaderGenerator::calculateLineCount(const SubStringRef &subString) + { + return calculateLineCount(subString.getOriginalBuffer(), subString.getStart()); + } + //----------------------------------------------------------------------------------- +} diff --git a/Components/HLMS/src/OgreHlmsShaderManager.cpp b/Components/HLMS/src/OgreHlmsShaderManager.cpp new file mode 100644 index 00000000000..0846c2cfed5 --- /dev/null +++ b/Components/HLMS/src/OgreHlmsShaderManager.cpp @@ -0,0 +1,452 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE +(Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2015 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#include "OgreHlmsShaderManager.h" +#include "OgreHlmsShaderGenerator.h" +#include "OgreHlmsShaderPiecesManager.h" +#include "OgreHlmsDataBlock.h" +#include "OgreHlmsShaderCommon.h" + +namespace Ogre +{ + //----------------------------------------------------------------------------------- + ShaderManager::ShaderManager() + { + mShaderPiecesManager = new ShaderPiecesManager("c:/"); + } + //----------------------------------------------------------------------------------- + ShaderManager::~ShaderManager() + { + delete mShaderPiecesManager; + mShaderPiecesManager = NULL; + } + //----------------------------------------------------------------------------------- + Ogre::GpuProgramPtr ShaderManager::getGpuProgram(HlmsDatablock* dataBlock) + { + auto hash = dataBlock->getHash(); + + auto it = mShaderCache.find(hash); + if (it != mShaderCache.end()) + { + return (*it).second; + } + else + { + auto typeStr = FilePatterns[dataBlock->getShaderType()]; + + std::stringstream sstream; + sstream << std::hex << hash; + std::string hashString = sstream.str(); + + auto name = hashString + typeStr; + + // generate the shader code + auto code = dataBlock->getTemplate()->getTemplate(); + code = ShaderGenerator::parse(code, *(dataBlock->getPropertyMap()), mShaderPiecesManager->getPieces(dataBlock->getLanguarge(), dataBlock->getShaderType())); + + auto gpuProgram = Ogre::HighLevelGpuProgramManager::getSingleton().createProgram(name, + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, dataBlock->getLanguarge(), dataBlock->getShaderType()); + + gpuProgram->setSource(code); + gpuProgram->setParameter("entry_point", "main"); + + if (dataBlock->getLanguarge() == "hlsl") + { + // HLSL program requires specific target profile settings - we have to split the profile string. + const Ogre::StringVector& profilesList = dataBlock->getProfileList(); + Ogre::StringVector::const_iterator it = profilesList.begin(); + Ogre::StringVector::const_iterator itEnd = profilesList.end(); + + for (; it != itEnd; ++it) + { + if (Ogre::GpuProgramManager::getSingleton().isSyntaxSupported(*it)) + { + gpuProgram->setParameter("target", *it); + break; + } + } + + //gpuProgram->setParameter("enable_backwards_compatibility", "false"); + //gpuProgram->setParameter("column_major_matrices", Ogre::StringConverter::toString(shaderProgram->getUseColumnMajorMatrices())); + } + + //gpuProgram->setParameter("profiles", profiles); + gpuProgram->load(); + + // Case an error occurred. + if (gpuProgram->hasCompileError()) + { + gpuProgram.setNull(); + return Ogre::GpuProgramPtr(gpuProgram); + } + + mShaderCache[hash] = gpuProgram; + + return gpuProgram; + } + + } + //----------------------------------------------------------------------------------- + void clearCache() + { + // TODO + //mShaderCache + } + //----------------------------------------------------------------------------------- + /* + const HlmsCache* Hlms::createShaderCacheEntry( uint32 renderableHash, const HlmsCache &passCache, + uint32 finalHash, + const QueuedRenderable &queuedRenderable ) + { + //Set the properties by merging the cache from the pass, with the cache from renderable + mSetProperties.clear(); + //If retVal is null, we did something wrong earlier + //(the cache should've been generated by now) + const RenderableCache &renderableCache = getRenderableCache( renderableHash ); + mSetProperties.reserve( passCache.setProperties.size() + renderableCache.setProperties.size() ); + //Copy the properties from the renderable + mSetProperties.insert( mSetProperties.end(), renderableCache.setProperties.begin(), + renderableCache.setProperties.end() ); + { + //Now copy the properties from the pass (one by one, since be must maintain the order) + HlmsPropertyVec::const_iterator itor = passCache.setProperties.begin(); + HlmsPropertyVec::const_iterator end = passCache.setProperties.end(); + + while( itor != end ) + { + setProperty( itor->keyName, itor->value ); + ++itor; + } + } + + GpuProgramPtr shaders[NumShaderTypes]; + //Generate the shaders + for( size_t i=0; iopen( *itor ); + + String inString; + String outString; + + inString.resize( inFile->size() ); + inFile->read( &inString[0], inFile->size() ); + + this->parseMath( inString, outString ); + this->parseForEach( outString, inString ); + this->parseProperties( inString, outString ); + this->collectPieces( outString, inString ); + ++itor; + } + + //Generate the shader file. TODO: Identify the file extension at runtime + const String filename = ShaderFiles[i] + ".glsl"; + if( mDataFolder->exists( filename ) ) + { + DataStreamPtr inFile = mDataFolder->open( filename ); + + String inString; + String outString; + + inString.resize( inFile->size() ); + inFile->read( &inString[0], inFile->size() ); + + this->parseMath( inString, outString ); + this->parseForEach( outString, inString ); + this->parseProperties( inString, outString ); + this->collectPieces( outString, inString ); + this->insertPieces( inString, outString ); + this->parseCounter( outString, inString ); + + outString.swap( inString ); + + if( mDebugOutput ) + { + std::ofstream outFile( (mOutputPath + "./" + + StringConverter::toString( finalHash ) + + ShaderFiles[i]).c_str(), + std::ios::out | std::ios::binary ); + outFile.write( &outString[0], outString.size() ); + } + + HighLevelGpuProgramManager *gpuProgramManager = + HighLevelGpuProgramManager::getSingletonPtr(); + + HighLevelGpuProgramPtr gp = gpuProgramManager->createProgram( + StringConverter::toString( finalHash ) + ShaderFiles[i], + ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME, + mShaderProfile, static_cast(i) ); + gp->setSource( outString ); + + gp->setSkeletalAnimationIncluded( getProperty( HlmsBaseProp::Skeleton ) != 0 ); + gp->setMorphAnimationIncluded( false ); + gp->setPoseAnimationIncluded( getProperty( HlmsBaseProp::Pose ) ); + gp->setVertexTextureFetchRequired( false ); + + gp->load(); + + shaders[i] = gp; + } + } + + const HlmsCache* retVal = addShaderCache( finalHash, shaders[VertexShader], + shaders[GeometryShader], shaders[HullShader], + shaders[DomainShader], shaders[PixelShader] ); + return retVal; + } + //----------------------------------------------------------------------------------- + void Hlms::calculateHashFor( Renderable *renderable, uint32 &outHash, uint32 &outCasterHash ) + { + mSetProperties.clear(); + + setProperty( HlmsBaseProp::Skeleton, renderable->hasSkeletonAnimation() ); + + RenderOperation op; + renderable->getRenderOperation( op ); + VertexDeclaration *vertexDecl = op.vertexData->vertexDeclaration; + const VertexDeclaration::VertexElementList &elementList = vertexDecl->getElements(); + VertexDeclaration::VertexElementList::const_iterator itor = elementList.begin(); + VertexDeclaration::VertexElementList::const_iterator end = elementList.end(); + + uint numTexCoords = 0; + while( itor != end ) + { + const VertexElement &vertexElem = *itor; + switch( vertexElem.getSemantic() ) + { + case VES_NORMAL: + if( VertexElement::getTypeCount( vertexElem.getType() ) < 4 ) + { + setProperty( HlmsBaseProp::Normal, 1 ); + } + else + { + setProperty( HlmsBaseProp::QTangent, 1 ); + } + break; + case VES_TANGENT: + setProperty( HlmsBaseProp::Tangent, 1 ); + break; + case VES_DIFFUSE: + setProperty( HlmsBaseProp::Colour, 1 ); + break; + case VES_TEXTURE_COORDINATES: + numTexCoords = std::max( numTexCoords, vertexElem.getIndex() + 1 ); + setProperty( *HlmsBaseProp::UvCountPtrs[vertexElem.getIndex()], + VertexElement::getTypeCount( vertexElem.getType() ) ); + break; + case VES_BLEND_WEIGHTS: + setProperty( HlmsBaseProp::BonesPerVertex, + VertexElement::getTypeCount( vertexElem.getType() ) ); + break; + default: + break; + } + + vertexElem.getType(); + ++itor; + } + + setProperty( HlmsBaseProp::UvCount, numTexCoords ); + + HlmsDatablock *datablock = renderable->getDatablock(); + + setProperty( HlmsBaseProp::AlphaTest, datablock->getAlphaTest() ); + + PiecesMap pieces[NumShaderTypes]; + calculateHashForPreCreate( renderable, pieces ); + + uint32 renderableHash = this->addRenderableCache( mSetProperties, pieces ); + + //For shadow casters, turn normals off. UVs & diffuse also off unless there's alpha testing. + setProperty( HlmsBaseProp::Normal, 0 ); + setProperty( HlmsBaseProp::QTangent, 0 ); + if( !datablock->getAlphaTest() ) + { + setProperty( HlmsBaseProp::UvCount, 0 ); + } + PiecesMap piecesCaster[NumShaderTypes]; + calculateHashForPreCaster( renderable, piecesCaster ); + uint32 renderableCasterHash = this->addRenderableCache( mSetProperties, piecesCaster ); + + outHash = renderableHash; + outCasterHash = renderableCasterHash; + } + //----------------------------------------------------------------------------------- + HlmsCache Hlms::preparePassHash( const CompositorShadowNode *shadowNode, bool casterPass, + bool dualParaboloid, SceneManager *sceneManager ) + { + mSetProperties.clear(); + + if( !casterPass ) + { + if( shadowNode ) + { + int32 numPssmSplits = 0; + const vector::type *pssmSplits = shadowNode->getPssmSplits( 0 ); + if( pssmSplits ) + numPssmSplits = static_cast( pssmSplits->size() - 1 ); + setProperty( HlmsBaseProp::PssmSplits, numPssmSplits ); + + size_t numShadowMaps = shadowNode->getNumShadowCastingLights(); + if( numPssmSplits ) + numShadowMaps += numPssmSplits - 1; + setProperty( HlmsBaseProp::NumShadowMaps, numShadowMaps ); + } + + uint numLightsPerType[Light::NUM_LIGHT_TYPES]; + memset( numLightsPerType, 0, sizeof( numLightsPerType ) ); + + if( mLightGatheringMode == LightGatherForwardPlus ) + { + if( shadowNode ) + { + //Gather shadow casting lights, regardless of their type. + const LightClosestArray &lights = shadowNode->getShadowCastingLights(); + LightClosestArray::const_iterator itor = lights.begin(); + LightClosestArray::const_iterator end = lights.end(); + while( itor != end ) + { + ++numLightsPerType[itor->light->getType()]; + ++itor; + } + } + + //Always gather directional lights. + numLightsPerType[Light::LT_DIRECTIONAL] = 0; + { + const LightListInfo &globalLightList = sceneManager->getGlobalLightList(); + LightArray::const_iterator itor = globalLightList.lights.begin(); + LightArray::const_iterator end = globalLightList.lights.end(); + + while( itor != end ) + { + if( (*itor)->getType() == Light::LT_DIRECTIONAL ) + ++numLightsPerType[Light::LT_DIRECTIONAL]; + ++itor; + } + } + } + else if( mLightGatheringMode == LightGatherForward ) + { + //Gather all lights. + const LightListInfo &globalLightList = sceneManager->getGlobalLightList(); + LightArray::const_iterator itor = globalLightList.lights.begin(); + LightArray::const_iterator end = globalLightList.lights.end(); + + size_t numTotalLights = 0; + + while( itor != end && numTotalLights < mNumLightsLimit ) + { + ++numLightsPerType[(*itor)->getType()]; + ++numTotalLights; + ++itor; + } + } + + setProperty( HlmsBaseProp::LightsAttenuation, numLightsPerType[Light::LT_POINT] + + numLightsPerType[Light::LT_SPOTLIGHT] ); + setProperty( HlmsBaseProp::LightsSpotParams, numLightsPerType[Light::LT_SPOTLIGHT] ); + + + numLightsPerType[Light::LT_POINT] += numLightsPerType[Light::LT_DIRECTIONAL]; + numLightsPerType[Light::LT_SPOTLIGHT] += numLightsPerType[Light::LT_POINT]; + + //The value is cummulative for each type (order: Directional, point, spot) + setProperty( HlmsBaseProp::LightsDirectional, numLightsPerType[Light::LT_DIRECTIONAL] ); + setProperty( HlmsBaseProp::LightsPoint, numLightsPerType[Light::LT_POINT] ); + setProperty( HlmsBaseProp::LightsSpot, numLightsPerType[Light::LT_SPOTLIGHT] ); + } + else + { + setProperty( HlmsBaseProp::ShadowCaster, casterPass ); + setProperty( HlmsBaseProp::DualParaboloidMapping, dualParaboloid ); + + setProperty( HlmsBaseProp::NumShadowMaps, 0 ); + setProperty( HlmsBaseProp::PssmSplits, 0 ); + setProperty( HlmsBaseProp::LightsAttenuation, 0 ); + setProperty( HlmsBaseProp::LightsSpotParams, 0 ); + setProperty( HlmsBaseProp::LightsDirectional, 0 ); + setProperty( HlmsBaseProp::LightsPoint, 0 ); + setProperty( HlmsBaseProp::LightsSpot, 0 ); + } + + uint32 hash = getProperty( HlmsBaseProp::DualParaboloidMapping ) | + (getProperty( HlmsBaseProp::NumShadowMaps ) << 1 )| + (getProperty( HlmsBaseProp::PssmSplits ) << 5 )| + (getProperty( HlmsBaseProp::LightsDirectional ) << 8 )| + (getProperty( HlmsBaseProp::LightsPoint ) << 12)| + (getProperty( HlmsBaseProp::LightsSpot ) << 16)| + (getProperty( HlmsBaseProp::ShadowCaster ) << 20); + + HlmsCache retVal( hash, mType ); + retVal.setProperties = mSetProperties; + + return retVal; + } + //----------------------------------------------------------------------------------- + const HlmsCache* Hlms::getMaterial( HlmsCache const *lastReturnedValue, + const HlmsCache &passCache, + const QueuedRenderable &queuedRenderable, bool casterPass ) + { + uint32 finalHash; + uint32 hash[2]; + hash[0] = casterPass ? queuedRenderable.renderable->getHlmsCasterHash() : + queuedRenderable.renderable->getHlmsHash(); + hash[1] = passCache.hash & + (queuedRenderable.movableObject->getCastShadows() ? 0xffffffff : 0xffffffe1 ); + + MurmurHash3_x86_32( hash, sizeof( hash ), IdString::Seed, &finalHash ); + + if( lastReturnedValue->hash != finalHash ) + { + lastReturnedValue = this->getShaderCache( finalHash ); + + if( !lastReturnedValue ) + { + lastReturnedValue = createShaderCacheEntry( hash[0], passCache, finalHash, + queuedRenderable ); + } + } + + return lastReturnedValue; + }*/ + +} diff --git a/Components/HLMS/src/OgreHlmsShaderPiecesManager.cpp b/Components/HLMS/src/OgreHlmsShaderPiecesManager.cpp new file mode 100644 index 00000000000..3579d3e38b2 --- /dev/null +++ b/Components/HLMS/src/OgreHlmsShaderPiecesManager.cpp @@ -0,0 +1,98 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE +(Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2015 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#include "OgreHlmsShaderPiecesManager.h" +#include "OgreHlmsShaderCommon.h" + +namespace Ogre +{ + //----------------------------------------------------------------------------------- + ShaderPiecesManager::ShaderPiecesManager(const Ogre::String& piecesFolder) + { + + } + //----------------------------------------------------------------------------------- + ShaderPiecesManager::~ShaderPiecesManager() + { + + } + //----------------------------------------------------------------------------------- + void ShaderPiecesManager::enumeratePieceFiles(void) + { + // TODO + /* + auto stringVectorPtr = mDataFolder->list(false, false); + + Ogre::StringVector stringVectorLowerCase(*stringVectorPtr); + + { + Ogre::StringVector::iterator itor = stringVectorLowerCase.begin(); + Ogre::StringVector::iterator end = stringVectorLowerCase.end(); + while (itor != end) + { + std::transform(itor->begin(), itor->end(), itor->begin(), ::tolower); + ++itor; + } + } + + auto size = sizeof(FilePatterns) / sizeof(*FilePatterns); + for (size_t i = 0; i < size; ++i) + { + auto itLowerCase = stringVectorLowerCase.begin(); + auto itor = stringVectorPtr->begin(); + auto end = stringVectorPtr->end(); + + while (itor != end) + { + if (itLowerCase->find(FilePatterns[i]) != Ogre::String::npos) + mPieceFiles.push_back(*itor); + + ++itLowerCase; + ++itor; + } + } + + auto langIt = mPieceFiles.find(languarge); + if (langIt != mPieceFiles.end()) + { + return (*langIt).second[shaderType]; + }*/ + } + //----------------------------------------------------------------------------------- + Ogre::StringVector& ShaderPiecesManager::getPieces(Ogre::String languarge, Ogre::GpuProgramType shaderType) + { + auto langIt = mPieceFiles.find(languarge); + if (langIt != mPieceFiles.end()) + { + return (*langIt).second[shaderType]; + } + + return mDefaultStringVector; + } + //----------------------------------------------------------------------------------- +} \ No newline at end of file diff --git a/Components/HLMS/src/OgreHlmsShaderTemplate.cpp b/Components/HLMS/src/OgreHlmsShaderTemplate.cpp new file mode 100644 index 00000000000..ae270eb6c62 --- /dev/null +++ b/Components/HLMS/src/OgreHlmsShaderTemplate.cpp @@ -0,0 +1,83 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE +(Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2015 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#include "OgreHlmsShaderTemplate.h" +#include "OgreHlmsShaderCommon.h" + +namespace Ogre +{ + //----------------------------------------------------------------------------------- + ShaderTemplate::ShaderTemplate() : mHash(0) + { + + } + //----------------------------------------------------------------------------------- + ShaderTemplate::~ShaderTemplate() + { + + } + //----------------------------------------------------------------------------------- + void ShaderTemplate::setTemplateFileName(const Ogre::String& templateFileName) + { + mTemplateFileName = templateFileName; + mHash = 0; + } + //----------------------------------------------------------------------------------- + const Ogre::String& ShaderTemplate::getTemplate() + { + if (mHash == 0) + { + load(); + } + + return mTemplate; + } + //----------------------------------------------------------------------------------- + Ogre::uint32 ShaderTemplate::getHash() + { + if (mHash == 0) + { + load(); + } + + return mHash; + } + //----------------------------------------------------------------------------------- + void ShaderTemplate::load() + { + if (mTemplateFileName.empty()) return; + + if (Ogre::ResourceGroupManager::getSingletonPtr()->resourceExists(Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mTemplateFileName)) + { + Ogre::DataStreamPtr logoCornersFile = Ogre::ResourceGroupManager::getSingletonPtr()->openResource(mTemplateFileName); + mTemplate = logoCornersFile->getAsString(); + mHash = calcHash(mTemplate); + } + } + //----------------------------------------------------------------------------------- +} \ No newline at end of file diff --git a/Components/Overlay/include/OgreOverlayPrerequisites.h b/Components/Overlay/include/OgreOverlayPrerequisites.h index 875dd34aa44..d7ac5f603e2 100644 --- a/Components/Overlay/include/OgreOverlayPrerequisites.h +++ b/Components/Overlay/include/OgreOverlayPrerequisites.h @@ -4,7 +4,7 @@ This source file is part of OGRE (Object-oriented Graphics Rendering Engine) For the latest info, see http://www.ogre3d.org/ -Copyright (c) 2000-2014 Torus Knot Software Ltd +Copyright (c) 2000-2015 Torus Knot Software Ltd Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/OgreMain/CMakeLists.txt b/OgreMain/CMakeLists.txt index df2dbd635ca..2edd3979716 100644 --- a/OgreMain/CMakeLists.txt +++ b/OgreMain/CMakeLists.txt @@ -16,13 +16,13 @@ PROJECT(OgreMain) include(PrecompiledHeader) # define header and source files for the library -file(GLOB HEADER_FILES "${CMAKE_CURRENT_SOURCE_DIR}/include/*.h") +file(GLOB HEADER_FILES "${CMAKE_CURRENT_SOURCE_DIR}/include/*.h" "${CMAKE_CURRENT_SOURCE_DIR}/include/Hash/*.h") list(APPEND HEADER_FILES ${OGRE_BINARY_DIR}/include/OgreBuildSettings.h src/OgreImageResampler.h src/OgrePixelConversions.h src/OgreSIMDHelper.h) -file(GLOB SOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") +file(GLOB SOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/Hash/*.cpp") # Remove optional header files list(REMOVE_ITEM HEADER_FILES "${CMAKE_CURRENT_SOURCE_DIR}/include/OgreFreeImageCodec.h" @@ -45,6 +45,21 @@ list(REMOVE_ITEM SOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/OgreFreeImageCode "${CMAKE_CURRENT_SOURCE_DIR}/src/OgreSTBICodec.cpp" ) +# Add threading (backport from 2.X) +list(APPEND HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/Threading/OgreThreads.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/Threading/OgreBarrier.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/Threading/OgreLightweightMutex.h) + +if(WIN32 AND NOT ANDROID) + list(APPEND SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/Threading/OgreBarrierWin.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Threading/OgreThreadsWin.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Threading/OgreLightweightMutexWin.cpp) +else() + list(APPEND SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/Threading/OgreBarrierPThreads.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Threading/OgreLightweightMutexPThreads.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Threading/OgreThreadsPThreads.cpp) +endif() + # Add platform specific files if (OGRE_BUILD_PLATFORM_NACL) include_directories("include/NaCl") diff --git a/OgreMain/include/Hash/MurmurHash3.h b/OgreMain/include/Hash/MurmurHash3.h new file mode 100644 index 00000000000..c9e79075452 --- /dev/null +++ b/OgreMain/include/Hash/MurmurHash3.h @@ -0,0 +1,43 @@ +//----------------------------------------------------------------------------- +// MurmurHash3 was written by Austin Appleby, and is placed in the public +// domain. The author hereby disclaims copyright to this source code. + +#ifndef _MURMURHASH3_H_ +#define _MURMURHASH3_H_ + +//----------------------------------------------------------------------------- +// Platform-specific functions and macros +#include "OgrePlatform.h" + +// Microsoft Visual Studio + +#if defined( _MSC_VER ) && _MSC_VER < 1600 + +namespace Ogre +{ + typedef unsigned char uint8_t; + typedef unsigned long uint32_t; + typedef unsigned __int64 uint64_t; +} +// Other compilers + +#else // defined(_MSC_VER) + +#include + +#endif // !defined(_MSC_VER) + +//----------------------------------------------------------------------------- + +namespace Ogre +{ + void _OgreExport MurmurHash3_x86_32 ( const void * key, int len, uint32_t seed, void * out ); + + void _OgreExport MurmurHash3_x86_128 ( const void * key, int len, uint32_t seed, void * out ); + + void _OgreExport MurmurHash3_x64_128 ( const void * key, int len, uint32_t seed, void * out ); +} + +//----------------------------------------------------------------------------- + +#endif // _MURMURHASH3_H_ diff --git a/OgreMain/include/OgreId.h b/OgreMain/include/OgreId.h new file mode 100644 index 00000000000..b8de3d16c0a --- /dev/null +++ b/OgreMain/include/OgreId.h @@ -0,0 +1,88 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE + (Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2014 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#ifndef __Id_H__ +#define __Id_H__ + +namespace Ogre +{ + /// Big projects with lots, lots of units for very long periods of time (MMORPGs?) + /// may want to define this to 64-bit + typedef Ogre::uint32 IdType; + + /** + Usage: + OGRE_NEW SceneNode( Id::generateNewId< Node >() ) + */ + class _OgreExport Id + { + public: + //This function assumes creation of new objects can't be made from multiple threads!!! + template static IdType generateNewId() + { + static IdType g_currentId = 0; + return g_currentId++; + } + }; + + class _OgreExport IdObject + { + private: + friend struct IdCmp; //Avoid calling getId() + IdType mId; + + protected: + /**In the rare case our derived class wants to override our Id + (normally we don't want that, that's why it's private). + */ + void _setId( IdType newId ) { mId = newId; } + + public: + /** We don't call generateNewId() here, to prevent objects in the stack (i.e. local variables) + that don't need an Id from incrementing the count; which is very dangerous if the caller + is creating local objects from multiple threads (which should stay safe!). + Instead our creator should do that. + */ + IdObject( IdType id ) : mId( id ) {} + + /// Get the unique id of this object + IdType getId() const { return mId; } + + bool operator()( const IdObject *left, const IdObject *right ) + { + return left->mId < right->mId; + } + + bool operator()( const IdObject &left, const IdObject &right ) + { + return left.mId < right.mId; + } + }; +} + +#endif diff --git a/OgreMain/include/OgreIdString.h b/OgreMain/include/OgreIdString.h new file mode 100644 index 00000000000..c4ecda4d13b --- /dev/null +++ b/OgreMain/include/OgreIdString.h @@ -0,0 +1,297 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE +(Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2014 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#ifndef __OgreIdString__ +#define __OgreIdString__ + +#include "Hash/MurmurHash3.h" +#include // sprintf +#include // strlen +#include + +#define OGRE_HASH_FUNC MurmurHash3_x86_32 +#define OGRE_HASH_BITS 32 + +#ifdef NDEBUG + #define OGRE_COPY_DEBUG_STRING( _Expression ) ((void)0) + #define OGRE_APPEND_DEBUG_STRING( _Expression ) ((void)0) +#else + #include "assert.h" +#endif + +namespace Ogre +{ + /** Hashed string. + An IdString is meant to be passed by value rather than by reference since in Release + mode it's just an encapsulated integer. The default implementation uses a 32-bit uint. + A hash = 0 is the default initialization, and assumed by Ogre to mean an IdString is + empty or unspecified. + @par + Note that IdString("") != IdString(0) != IdString() + The latter indicates mHash == 0 (the default initialization). While the first + one will hash the empty string "", and the second will attempt to hash the + number 0, producing up to three possible outputs. + @par + IdStrings convert regular String to hashes AND ARE DESTRUCTIVE. + This means that you may no longer recover the real string it was constructed from. + When the original data is not available getFriendlyText returns [Hash 0x0a0100ef] + (in the example that mHash = 0x0a0100ef)* + In non-release modes (NDEBUG is not defined), IdStrings try to maintain a copy of + the original string for two purposes: + 1. Easy debugging: Reading "Texture/diffuse.png" is much nicer than "0x0a0100ef" + 2. Hash collision: If Ogre finds two IdStrings are identical but their original + strings are not, an assertion will trigger indicating a collision has been + found. Note that this isn't foolproof. + * Note: When IdString( uint32 ) was used to hash an integer, getFriendlyText + will return "[Value 0x1234567]" + @par + IdStrings can be concatenated: IdString( "Hello." ) + IdString( " How are you?" ) + produc a new IdString, but please note that it may not be the same as doing + IdString( "Hello. How are you?" ) depending on the hashing function used + (by default, we use MurmurHash3, @see OGRE_HASH_FUNC) + + @remarks + Hash collision detection isn't foolproof because we keep a fixed string copy of + the original string. If the original string is too long, it will be truncated + and there is an extremely low possibility that their truncation becomes + the same string, and their hashes also become equal, when the original strings + were not. i.e. + VeryLooooooong/String and UltraaaaaLoong/String could both become "/String" + and happen to also hash to the same number. + @par + In practice we truncate to 32 bytes. If your fear this is too little for you and + also fear about collisions, increase @OGRE_DEBUG_STR_SIZE + @author + Matias N. Goldberg + @version + 1.0 + */ + struct IdString + { + static const uint32_t Seed = 0x3A8EFA67; //It's a prime number :) + + uint32 mHash; +#ifndef NDEBUG + #define OGRE_DEBUG_STR_SIZE 32 + char mDebugString[OGRE_DEBUG_STR_SIZE]; +#endif + + IdString() : mHash( 0 ) + { +#ifndef NDEBUG + mDebugString[0] = '\0'; +#endif + } + + IdString( const char *string ) : mHash( 0 ) + { + OGRE_HASH_FUNC( string, static_cast(strlen( string )), Seed, &mHash ); + OGRE_COPY_DEBUG_STRING( string ); + } + + IdString( const std::string &string ) : mHash( 0 ) + { + OGRE_HASH_FUNC( string.c_str(), static_cast(string.size()), Seed, &mHash ); + OGRE_COPY_DEBUG_STRING( string ); + } + + IdString( uint32 value ) : mHash( 0 ) + { + OGRE_HASH_FUNC( &value, sizeof( value ), Seed, &mHash ); + OGRE_COPY_DEBUG_STRING( value ); + } + +#ifndef NDEBUG + #if OGRE_COMPILER == OGRE_COMPILER_MSVC + #pragma warning( push ) + #pragma warning( disable: 4996 ) //Unsecure CRT deprecation warning + #endif + + void OGRE_COPY_DEBUG_STRING( const char *string ) + { + size_t strLength = strlen( string ); + if( strLength > OGRE_DEBUG_STR_SIZE-1 ) + { + //Copy the last characters, not the first ones! + strncpy( mDebugString, string + strLength - (OGRE_DEBUG_STR_SIZE-1), + OGRE_DEBUG_STR_SIZE ); + } + else + { + strncpy( mDebugString, string, OGRE_DEBUG_STR_SIZE ); + } + mDebugString[OGRE_DEBUG_STR_SIZE-1] = '\0'; + } + + void OGRE_COPY_DEBUG_STRING( const std::string &string ) + { + size_t strLength = string.size(); + if( strLength > OGRE_DEBUG_STR_SIZE-1 ) + { + //Copy the last characters, not the first ones! + strncpy( mDebugString, string.c_str() + strLength - (OGRE_DEBUG_STR_SIZE-1), + OGRE_DEBUG_STR_SIZE ); + } + else + { + strncpy( mDebugString, string.c_str(), OGRE_DEBUG_STR_SIZE ); + } + mDebugString[OGRE_DEBUG_STR_SIZE-1] = '\0'; + } + + void OGRE_COPY_DEBUG_STRING( uint32 value ) + { + sprintf( mDebugString, "[Value 0x%.8x]", value ); + mDebugString[OGRE_DEBUG_STR_SIZE-1] = '\0'; + } + + void OGRE_APPEND_DEBUG_STRING( const char *string ) + { + size_t strLen0 = strlen( mDebugString ); + size_t strLen1 = strlen( string ); + + if( strLen0 + strLen1 < OGRE_DEBUG_STR_SIZE ) + { + strcat( mDebugString, string ); + mDebugString[OGRE_DEBUG_STR_SIZE-1] = '\0'; + } + else + { + size_t newStart0 = (strLen0 >> 1); + size_t newLen0 = strLen0 - newStart0; + memmove( mDebugString, mDebugString + newStart0, newLen0 ); + + size_t newStart1 = 0; + size_t newLen1 = strLen1; + if( newLen0 + strLen1 >= OGRE_DEBUG_STR_SIZE ) + { + newLen1 = OGRE_DEBUG_STR_SIZE - newLen0 - 1; + newStart1 = strLen1 - newLen1; + } + + memcpy( mDebugString + newLen0, string + newStart1, newLen1 ); + mDebugString[OGRE_DEBUG_STR_SIZE-1] = '\0'; + } + } + + #if OGRE_COMPILER == OGRE_COMPILER_MSVC + #pragma warning( pop ) + #endif +#endif + + void operator += ( IdString idString ) + { + uint32 doubleHash[2]; + doubleHash[0] = mHash; + doubleHash[1] = idString.mHash; + + OGRE_HASH_FUNC( &doubleHash, sizeof( doubleHash ), Seed, &mHash ); + OGRE_APPEND_DEBUG_STRING( idString.mDebugString ); + } + + IdString operator + ( IdString idString ) const + { + IdString retVal( *this ); + retVal += idString; + return retVal; + } + + bool operator < ( IdString idString ) const + { +#if OGRE_DEBUG_MODE + //On highly debug builds, check for collisions + assert( !(mHash == idString.mHash && + strcmp( mDebugString, idString.mDebugString ) != 0) && + "Collision detected!" ); +#endif + return mHash < idString.mHash; + } + + bool operator == ( IdString idString ) const + { +#ifndef NDEBUG + assert( !(mHash == idString.mHash && + strcmp( mDebugString, idString.mDebugString ) != 0) && + "Collision detected!" ); +#endif + return mHash == idString.mHash; + } + + bool operator != ( IdString idString ) const + { +#ifndef NDEBUG + assert( !(mHash == idString.mHash && + strcmp( mDebugString, idString.mDebugString ) != 0) && + "Collision detected!" ); +#endif + return mHash != idString.mHash; + } + + /// Returns "[Hash 0x0a0100ef]" strings in Release mode, readable string in debug + std::string getFriendlyText() const + { +#ifndef NDEBUG + return std::string( mDebugString ); +#else + #if OGRE_COMPILER == OGRE_COMPILER_MSVC + #pragma warning( push ) + #pragma warning( disable: 4996 ) //Unsecure CRT deprecation warning + #endif + + char tmp[(OGRE_HASH_BITS >> 2)+10]; + sprintf( tmp, "[Hash 0x%.8x]", mHash ); + tmp[(OGRE_HASH_BITS >> 2)+10-1] = '\0'; + return std::string( tmp ); + + #if OGRE_COMPILER == OGRE_COMPILER_MSVC + #pragma warning( pop ) + #endif +#endif + } + + /// Always returns "[Hash 0x0a0100ef]" strings in any mode + std::string getReleaseText() const + { + #if OGRE_COMPILER == OGRE_COMPILER_MSVC + #pragma warning( push ) + #pragma warning( disable: 4996 ) //Unsecure CRT deprecation warning + #endif + + char tmp[(OGRE_HASH_BITS >> 2)+10]; + sprintf( tmp, "[Hash 0x%.8x]", mHash ); + tmp[(OGRE_HASH_BITS >> 2)+10-1] = '\0'; + return std::string( tmp ); + + #if OGRE_COMPILER == OGRE_COMPILER_MSVC + #pragma warning( pop ) + #endif + } + }; +} + +#endif diff --git a/OgreMain/include/OgrePlatform.h b/OgreMain/include/OgrePlatform.h index ba70bf7cd6a..bc762b8df12 100644 --- a/OgreMain/include/OgrePlatform.h +++ b/OgreMain/include/OgrePlatform.h @@ -324,6 +324,43 @@ namespace Ogre { # define OGRE_BUILD_SUFFIX "" #endif +#if OGRE_COMPILER == OGRE_COMPILER_MSVC +#define DECL_MALLOC __declspec(restrict) __declspec(noalias) +#else +#define DECL_MALLOC __attribute__ ((malloc)) +#endif + +// Stack-alignment hackery. +// +// If macro __OGRE_SIMD_ALIGN_STACK defined, means there requests +// special code to ensure stack align to a 16-bytes boundary. +// +// Note: +// This macro can only guarantee callee stack pointer (esp) align +// to a 16-bytes boundary, but not that for frame pointer (ebp). +// Because most compiler might use frame pointer to access to stack +// variables, so you need to wrap those alignment required functions +// with extra function call. +// +#if defined(__INTEL_COMPILER) +// For intel's compiler, simply calling alloca seems to do the right +// thing. The size of the allocated block seems to be irrelevant. +#define _OGRE_SIMD_ALIGN_STACK() _alloca(16) +#define _OGRE_SIMD_ALIGN_ATTRIBUTE + +#elif OGRE_CPU == OGRE_CPU_X86 && (OGRE_COMPILER == OGRE_COMPILER_GNUC || OGRE_COMPILER == OGRE_COMPILER_CLANG) && (OGRE_ARCH_TYPE != OGRE_ARCHITECTURE_64) +// mark functions with GCC attribute to force stack alignment to 16 bytes +#define _OGRE_SIMD_ALIGN_ATTRIBUTE __attribute__((force_align_arg_pointer)) + +#elif defined(_MSC_VER) +// Fortunately, MSVC will align the stack automatically +#define _OGRE_SIMD_ALIGN_ATTRIBUTE + +#else +#define _OGRE_SIMD_ALIGN_ATTRIBUTE + +#endif + // Integer formats of fixed bit width typedef unsigned int uint32; typedef unsigned short uint16; diff --git a/OgreMain/include/Threading/OgreBarrier.h b/OgreMain/include/Threading/OgreBarrier.h new file mode 100644 index 00000000000..55b2e4286cb --- /dev/null +++ b/OgreMain/include/Threading/OgreBarrier.h @@ -0,0 +1,84 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE + (Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2014 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#ifndef __Barrier_H__ +#define __Barrier_H__ + +#include "OgrePlatform.h" + +#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 + //No need to include the heavy windows.h header for something like this! + typedef long LONG; + typedef void* HANDLE; +#else + #include + #if defined(ANDROID) || OGRE_PLATFORM == OGRE_PLATFORM_APPLE || OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS + typedef struct + { + pthread_mutex_t mutex; + pthread_cond_t cond; + int count; + int tripCount; + } pthread_barrier_t; + #endif +#endif + +namespace Ogre +{ + /** A barrier is a synchronization mechanism where multiple threads wait until all + of them have reached the barrier sync point before continuing. + A fixed number of threads must be provided on initialization. + @remarks + On Windows, Synchronization Barriers weren't introduced until Windows 8 (!?!?!? No comments...) + Therefore, we emulate them using two Semaphores and (for performance reasons) + @author + Matias N. Goldberg + */ + class _OgreExport Barrier + { +#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 + size_t mNumThreads; + size_t mIndex; + OGRE_ALIGNED_DECL( volatile LONG, mLockCount, 4 ); + HANDLE mSemaphores[2]; +#else + pthread_barrier_t mBarrier; +#endif + + public: + Barrier( size_t threadCount ); + ~Barrier(); + + /** When calling this function, it will block until all N threads reach this point; where + N is the thread count passed to the Barrier's constructor. + */ + void sync(void); + }; +} + +#endif diff --git a/OgreMain/include/Threading/OgreLightweightMutex.h b/OgreMain/include/Threading/OgreLightweightMutex.h new file mode 100644 index 00000000000..05727349e0b --- /dev/null +++ b/OgreMain/include/Threading/OgreLightweightMutex.h @@ -0,0 +1,103 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE + (Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2014 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#ifndef __LightweightMutex_H__ +#define __LightweightMutex_H__ + +#include "OgrePlatform.h" +#include "OgrePlatformInformation.h" + +#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 + //No need to include the heavy windows.h header for something like this! + typedef void* HANDLE; +#else + #include +#endif + +namespace Ogre +{ + /** A lightweight mutex is a synchronization mechanism, very similar to a regular mutex. + Regular mutexes are well known to be expensive because they need to enter & leave + kernel mode. + @par + Lightweight mutexes usually make use of atomic instructions (in x86 they're referred to + as instructions with the "lock" prefix) to avoid entering kernel mode when no other + thread has aquired the lock. + @par + This comes with a couple caveats that we don't care for the applications we need, + but is important to keep them in mind: + 1) LightweightMutexes can't be shared among processes + 2) Priority inversion is not a concern + 3) Recursive locks aren't supported (same thread calling lock() twice can deadlock) + Note that some LightweightMutex implementations may offer this functionality, but we don't + guarantee them in all platforms/architectures. + It is possible to write a lightweight mutex that supports recursive locks, but that requires + a call to GetCurrentThreadId (in Windows), which as much as saying just use a regular mutex. + @par + Windows users are familiar with the concept of LightweightMutexes because there is already + an implementation provided: CRITICAL_SECTION. We go further by reinventing the wheel and + writting it ourselves. If you ever wondered how a CRITICAL_SECTION works, now you know. + @par + Interesting reads: + http://preshing.com/20111124/always-use-a-lightweight-mutex + http://preshing.com/20120226/roll-your-own-lightweight-mutex + http://preshing.com/20120305/implementing-a-recursive-mutex + */ + class _OgreExport LightweightMutex + { +#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 + OGRE_ALIGNED_DECL( long, mCounter, 4 ); + HANDLE mSemaphore; +#else + //The joys of POSIX programming... PThread mutexes are already lightweight. + //MS is lighyears behind UNIX regarding thread synchronization. (I'm sorry + //if I don't like CRITICAL_SECTION; MS changed their behavior between XP & + //Vista. We need consistent behavior) + pthread_mutex_t mMutex; +#endif + + public: + LightweightMutex(); + ~LightweightMutex(); + + /** Acquires the exclusive lock. Waits if necessary until another thread releases the lock. + Recursive locking is not guaranteed (do not call this function twice from the same thread) + */ + void lock(); + + /** Tries to aquire the lock and returns immediately. + On failure returns false, true on success + */ + bool tryLock(); + + /// Releases the lock aquired through either @see lock or @see tryLock + void unlock(); + }; +} + +#endif diff --git a/OgreMain/include/Threading/OgreThreads.h b/OgreMain/include/Threading/OgreThreads.h new file mode 100644 index 00000000000..5ad3508c7c1 --- /dev/null +++ b/OgreMain/include/Threading/OgreThreads.h @@ -0,0 +1,187 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE + (Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2014 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#ifndef __Threads_H__ +#define __Threads_H__ + +#include "OgreSharedPtr.h" + +#if defined(__i386) || defined(_M_IX86) + // Calling conventions are needed for x86 (32-bit ONLY) CPUs + #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 + #define OGRE_THREAD_CALL_CONVENTION _OGRE_SIMD_ALIGN_ATTRIBUTE __stdcall + #elif OGRE_COMPILER == OGRE_COMPILER_GNUC || OGRE_COMPILER == OGRE_COMPILER_CLANG + #define __cdecl __attribute__((__cdecl__)) + #define OGRE_THREAD_CALL_CONVENTION __cdecl + #endif +#else + #define OGRE_THREAD_CALL_CONVENTION +#endif + +#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 + /// @See Threads::CreateThread for an example on how to use + #define THREAD_DECLARE( threadFunction ) \ + unsigned long OGRE_THREAD_CALL_CONVENTION threadFunction##_internal( void *argName )\ + {\ + unsigned long retVal = 0;\ + Ogre::ThreadHandle *threadHandle( reinterpret_cast( argName ) );\ + try {\ + retVal = threadFunction( threadHandle );\ + }\ + catch( ... )\ + {\ + }\ + delete threadHandle;\ + return retVal;\ + } +#else + /// @See Threads::CreateThread for an example on how to use + #define THREAD_DECLARE( threadFunction ) \ + void* OGRE_THREAD_CALL_CONVENTION threadFunction##_internal( void *argName )\ + {\ + unsigned long retVal = 0;\ + Ogre::ThreadHandle *threadHandle( reinterpret_cast( argName ) );\ + try {\ + retVal = threadFunction( threadHandle );\ + }\ + catch( ... )\ + {\ + }\ + delete threadHandle;\ + \ + return (void*)retVal;\ + } +#endif + +#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 + //No need to include the heavy windows.h header for something like this! + typedef void* HANDLE; +#else + #include +#endif + +namespace Ogre +{ + class _OgreExport ThreadHandle + { +#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 + HANDLE mThread; +#else + pthread_t mThread; +#endif + size_t mThreadIdx; + void *mUserParam; + + public: + ThreadHandle( size_t threadIdx, void *userParam ); + ~ThreadHandle(); + + size_t getThreadIdx() const { return mThreadIdx; } + void* getUserParam() const { return mUserParam; } + +#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 + /// Internal use + void _setOsHandle( HANDLE handle ) { mThread = handle; } + /// Internal use + HANDLE _getOsHandle() const { return mThread; } +#else + /// Internal use + void _setOsHandle( pthread_t &handle ) { mThread = handle; } + /// Internal use + pthread_t _getOsHandle() const { return mThread; } +#endif + }; + + typedef SharedPtr ThreadHandlePtr; + typedef vector::type ThreadHandleVec; + +#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 + typedef unsigned long (OGRE_THREAD_CALL_CONVENTION *THREAD_ENTRY_POINT)( void *lpThreadParameter ); +#else + typedef void* (OGRE_THREAD_CALL_CONVENTION *THREAD_ENTRY_POINT)( void *lpThreadParameter ); +#endif + + class _OgreExport Threads + { + public: + #define THREAD_GET( threadFunction ) threadFunction##_internal + /** Creates and executes a new thread + @remarks + The function to execute must be declared via THREAD_DECLARE, and the first argument + must be provided through THREAD_GET. The following example shows how to use: + + unsigned long myOwnThread( ThreadHandle *ownThreadHandle ) + { + //Should print "Hello from thread 50" + printf( "Hello from thread %i", ownThreadHandle.getThreadIdx() ); + return 0; + } + THREAD_DECLARE( myOwnThread ); + + int main() + { + ThreadHandle handle = CreateThread( THREAD_GET( myOwnThread ), 50, 0 ); + WaitForThreads( 1, handle ); + return 0; + } + + It is not possible to retrieve the return value of the function because it's not + portable (and trying to emulate it induces to easy-to-cause memory leaks; as + we're dealing with C functions + potential race conditions, not C++) + @param entryPoint + Function name of the entry point. VERY IMPORTANT: The entry point must be provided + by THREAD_GET. Do not use a function directly, otherwise there will be memory leaks! + @param threadIdx + Optional index for this thread (ie. when you have many worker threads to work on a + section of data. + @param param + Optional argument to be passed. + @return + Handle to created thread. + */ + static ThreadHandlePtr CreateThread( THREAD_ENTRY_POINT entryPoint, + size_t threadIdx, void *param ); + + /** Waits until all threads are finished + @param numThreadInfos + Number of ThreadHandle passed in the array as 'threadHandles' + @param threadHandles + Array of numThreadHandles or more ThreadHandle + @remarks + Don't pass more than 128 handles per call + */ + static void WaitForThreads( size_t numThreadHandles, const ThreadHandlePtr *threadHandles ); + static void WaitForThreads( const ThreadHandleVec &threadHandles ); + + /// Sleeps for a **minimum** of the specified time of milliseconds. Actual time spent + /// sleeping may vary widely depending on OS and other variables. Do not feed 0. + static void Sleep( uint32 milliseconds ); + }; +} + +#endif diff --git a/OgreMain/src/Hash/MurmurHash3.cpp b/OgreMain/src/Hash/MurmurHash3.cpp new file mode 100644 index 00000000000..7a251869035 --- /dev/null +++ b/OgreMain/src/Hash/MurmurHash3.cpp @@ -0,0 +1,340 @@ +//----------------------------------------------------------------------------- +// MurmurHash3 was written by Austin Appleby, and is placed in the public +// domain. The author hereby disclaims copyright to this source code. + +// Note - The x86 and x64 versions do _not_ produce the same results, as the +// algorithms are optimized for their respective platforms. You can still +// compile and run any of them on any platform, but your performance with the +// non-native version will be less than optimal. + +#include "OgreStableHeaders.h" + +#include "OgrePlatform.h" +#include "Hash/MurmurHash3.h" + +//----------------------------------------------------------------------------- +// Platform-specific functions and macros + +// Microsoft Visual Studio + +#if defined(_MSC_VER) + +#define FORCE_INLINE __forceinline + +#include + +#define ROTL32(x,y) _rotl(x,y) +#define ROTL64(x,y) _rotl64(x,y) + +#define BIG_CONSTANT(x) (x) + +// Other compilers + +#else // defined(_MSC_VER) + +#define FORCE_INLINE inline __attribute__((always_inline)) + +inline uint32_t rotl32 ( uint32_t x, int8_t r ) +{ + return (x << r) | (x >> (32 - r)); +} + +inline uint64_t rotl64 ( uint64_t x, int8_t r ) +{ + return (x << r) | (x >> (64 - r)); +} + +#define ROTL32(x,y) rotl32(x,y) +#define ROTL64(x,y) rotl64(x,y) + +#define BIG_CONSTANT(x) (x##LLU) + +#endif // !defined(_MSC_VER) + +namespace Ogre +{ +//----------------------------------------------------------------------------- +// Block read - if your platform needs to do endian-swapping or can only +// handle aligned reads, do the conversion here + +FORCE_INLINE uint32_t getblock32 ( const uint32_t * p, int i ) +{ + return p[i]; +} + +FORCE_INLINE uint64_t getblock64 ( const uint64_t * p, int i ) +{ + return p[i]; +} + +//----------------------------------------------------------------------------- +// Finalization mix - force all bits of a hash block to avalanche + +FORCE_INLINE uint32_t fmix32 ( uint32_t h ) +{ + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + h ^= h >> 16; + + return h; +} + +//---------- + +FORCE_INLINE uint64_t fmix64 ( uint64_t k ) +{ + k ^= k >> 33; + k *= BIG_CONSTANT(0xff51afd7ed558ccd); + k ^= k >> 33; + k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53); + k ^= k >> 33; + + return k; +} + +//----------------------------------------------------------------------------- + +void _OgreExport MurmurHash3_x86_32 ( const void * key, const int len, + uint32_t seed, void * out ) +{ + const uint8_t * data = (const uint8_t*)key; + const int nblocks = len / 4; + + uint32_t h1 = seed; + + const uint32_t c1 = 0xcc9e2d51; + const uint32_t c2 = 0x1b873593; + + //---------- + // body + + const uint32_t * blocks = (const uint32_t *)(data + nblocks*4); + + for(int i = -nblocks; i; i++) + { + uint32_t k1 = getblock32(blocks,i); + + k1 *= c1; + k1 = ROTL32(k1,15); + k1 *= c2; + + h1 ^= k1; + h1 = ROTL32(h1,13); + h1 = h1*5+0xe6546b64; + } + + //---------- + // tail + + const uint8_t * tail = (const uint8_t*)(data + nblocks*4); + + uint32_t k1 = 0; + + switch(len & 3) + { + case 3: k1 ^= tail[2] << 16; + case 2: k1 ^= tail[1] << 8; + case 1: k1 ^= tail[0]; + k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1; + }; + + //---------- + // finalization + + h1 ^= len; + + h1 = fmix32(h1); + + *(uint32_t*)out = h1; +} + +//----------------------------------------------------------------------------- + +void _OgreExport MurmurHash3_x86_128 ( const void * key, const int len, + uint32_t seed, void * out ) +{ + const uint8_t * data = (const uint8_t*)key; + const int nblocks = len / 16; + + uint32_t h1 = seed; + uint32_t h2 = seed; + uint32_t h3 = seed; + uint32_t h4 = seed; + + const uint32_t c1 = 0x239b961b; + const uint32_t c2 = 0xab0e9789; + const uint32_t c3 = 0x38b34ae5; + const uint32_t c4 = 0xa1e38b93; + + //---------- + // body + + const uint32_t * blocks = (const uint32_t *)(data + nblocks*16); + + for(int i = -nblocks; i; i++) + { + uint32_t k1 = getblock32(blocks,i*4+0); + uint32_t k2 = getblock32(blocks,i*4+1); + uint32_t k3 = getblock32(blocks,i*4+2); + uint32_t k4 = getblock32(blocks,i*4+3); + + k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1; + + h1 = ROTL32(h1,19); h1 += h2; h1 = h1*5+0x561ccd1b; + + k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2; + + h2 = ROTL32(h2,17); h2 += h3; h2 = h2*5+0x0bcaa747; + + k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3; + + h3 = ROTL32(h3,15); h3 += h4; h3 = h3*5+0x96cd1c35; + + k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4; + + h4 = ROTL32(h4,13); h4 += h1; h4 = h4*5+0x32ac3b17; + } + + //---------- + // tail + + const uint8_t * tail = (const uint8_t*)(data + nblocks*16); + + uint32_t k1 = 0; + uint32_t k2 = 0; + uint32_t k3 = 0; + uint32_t k4 = 0; + + switch(len & 15) + { + case 15: k4 ^= tail[14] << 16; + case 14: k4 ^= tail[13] << 8; + case 13: k4 ^= tail[12] << 0; + k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4; + + case 12: k3 ^= tail[11] << 24; + case 11: k3 ^= tail[10] << 16; + case 10: k3 ^= tail[ 9] << 8; + case 9: k3 ^= tail[ 8] << 0; + k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3; + + case 8: k2 ^= tail[ 7] << 24; + case 7: k2 ^= tail[ 6] << 16; + case 6: k2 ^= tail[ 5] << 8; + case 5: k2 ^= tail[ 4] << 0; + k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2; + + case 4: k1 ^= tail[ 3] << 24; + case 3: k1 ^= tail[ 2] << 16; + case 2: k1 ^= tail[ 1] << 8; + case 1: k1 ^= tail[ 0] << 0; + k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1; + }; + + //---------- + // finalization + + h1 ^= len; h2 ^= len; h3 ^= len; h4 ^= len; + + h1 += h2; h1 += h3; h1 += h4; + h2 += h1; h3 += h1; h4 += h1; + + h1 = fmix32(h1); + h2 = fmix32(h2); + h3 = fmix32(h3); + h4 = fmix32(h4); + + h1 += h2; h1 += h3; h1 += h4; + h2 += h1; h3 += h1; h4 += h1; + + ((uint32_t*)out)[0] = h1; + ((uint32_t*)out)[1] = h2; + ((uint32_t*)out)[2] = h3; + ((uint32_t*)out)[3] = h4; +} + +//----------------------------------------------------------------------------- + +void _OgreExport MurmurHash3_x64_128 ( const void * key, const int len, + const uint32_t seed, void * out ) +{ + const uint8_t * data = (const uint8_t*)key; + const int nblocks = len / 16; + + uint64_t h1 = seed; + uint64_t h2 = seed; + + const uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5); + const uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f); + + //---------- + // body + + const uint64_t * blocks = (const uint64_t *)(data); + + for(int i = 0; i < nblocks; i++) + { + uint64_t k1 = getblock64(blocks,i*2+0); + uint64_t k2 = getblock64(blocks,i*2+1); + + k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1; + + h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729; + + k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2; + + h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5; + } + + //---------- + // tail + + const uint8_t * tail = (const uint8_t*)(data + nblocks*16); + + uint64_t k1 = 0; + uint64_t k2 = 0; + + switch(len & 15) + { + case 15: k2 ^= ((uint64_t)tail[14]) << 48; + case 14: k2 ^= ((uint64_t)tail[13]) << 40; + case 13: k2 ^= ((uint64_t)tail[12]) << 32; + case 12: k2 ^= ((uint64_t)tail[11]) << 24; + case 11: k2 ^= ((uint64_t)tail[10]) << 16; + case 10: k2 ^= ((uint64_t)tail[ 9]) << 8; + case 9: k2 ^= ((uint64_t)tail[ 8]) << 0; + k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2; + + case 8: k1 ^= ((uint64_t)tail[ 7]) << 56; + case 7: k1 ^= ((uint64_t)tail[ 6]) << 48; + case 6: k1 ^= ((uint64_t)tail[ 5]) << 40; + case 5: k1 ^= ((uint64_t)tail[ 4]) << 32; + case 4: k1 ^= ((uint64_t)tail[ 3]) << 24; + case 3: k1 ^= ((uint64_t)tail[ 2]) << 16; + case 2: k1 ^= ((uint64_t)tail[ 1]) << 8; + case 1: k1 ^= ((uint64_t)tail[ 0]) << 0; + k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1; + }; + + //---------- + // finalization + + h1 ^= len; h2 ^= len; + + h1 += h2; + h2 += h1; + + h1 = fmix64(h1); + h2 = fmix64(h2); + + h1 += h2; + h2 += h1; + + ((uint64_t*)out)[0] = h1; + ((uint64_t*)out)[1] = h2; +} + +//----------------------------------------------------------------------------- +} diff --git a/OgreMain/src/Threading/OgreBarrierPThreads.cpp b/OgreMain/src/Threading/OgreBarrierPThreads.cpp new file mode 100644 index 00000000000..eb422ab20ad --- /dev/null +++ b/OgreMain/src/Threading/OgreBarrierPThreads.cpp @@ -0,0 +1,113 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE + (Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2014 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#include "OgreStableHeaders.h" +#include "Threading/OgreBarrier.h" +#include + +namespace Ogre +{ + +#if OGRE_CPU == OGRE_CPU_ARM +#define __dmb() asm volatile ( "dmb sy\n" ::: "cc" ); +#endif + +#if defined(ANDROID) || OGRE_PLATFORM == OGRE_PLATFORM_APPLE || OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS + typedef int pthread_barrierattr_t; + //----------------------------------------------------------------------------------- + int pthread_barrier_init(pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, int count) + { + if(count == 0) + { + errno = EINVAL; + return -1; + } + if(pthread_mutex_init(&barrier->mutex, 0) < 0) + { + return -1; + } + if(pthread_cond_init(&barrier->cond, 0) < 0) + { + pthread_mutex_destroy(&barrier->mutex); + return -1; + } + barrier->tripCount = count; + barrier->count = 0; + + return 0; + } + //----------------------------------------------------------------------------------- + int pthread_barrier_destroy(pthread_barrier_t *barrier) + { + pthread_cond_destroy(&barrier->cond); + pthread_mutex_destroy(&barrier->mutex); + return 0; + } + //----------------------------------------------------------------------------------- + int pthread_barrier_wait(pthread_barrier_t *barrier) + { + pthread_mutex_lock(&barrier->mutex); + ++(barrier->count); + if(barrier->count >= barrier->tripCount) + { + barrier->count = 0; + pthread_cond_broadcast(&barrier->cond); + pthread_mutex_unlock(&barrier->mutex); + return 1; + } + else + { + pthread_cond_wait(&barrier->cond, &(barrier->mutex)); + pthread_mutex_unlock(&barrier->mutex); + return 0; + } + } + //----------------------------------------------------------------------------------- +#endif + + Barrier::Barrier( size_t threadCount ) + { +#if OGRE_PLATFORM != OGRE_PLATFORM_EMSCRIPTEN + pthread_barrier_init( &mBarrier, 0, static_cast(threadCount) ); +#endif + } + //----------------------------------------------------------------------------------- + Barrier::~Barrier() + { +#if OGRE_PLATFORM != OGRE_PLATFORM_EMSCRIPTEN + pthread_barrier_destroy( &mBarrier ); +#endif + } + //----------------------------------------------------------------------------------- + void Barrier::sync(void) + { +#if OGRE_PLATFORM != OGRE_PLATFORM_EMSCRIPTEN + pthread_barrier_wait( &mBarrier ); +#endif + } +} diff --git a/OgreMain/src/Threading/OgreBarrierWin.cpp b/OgreMain/src/Threading/OgreBarrierWin.cpp new file mode 100644 index 00000000000..63dfb38d5cb --- /dev/null +++ b/OgreMain/src/Threading/OgreBarrierWin.cpp @@ -0,0 +1,88 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE + (Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2014 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#include "OgreStableHeaders.h" + +#include "Threading/OgreBarrier.h" + +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#include + +#ifndef __MINGW32__ + #include "intrin.h" +#else + // MinGW needs some extra headers and define MemoryBarrier manually + #include + #include + #include + + #define MemoryBarrier __sync_synchronize +#endif + +namespace Ogre +{ + Barrier::Barrier( size_t threadCount ) : mNumThreads( threadCount ), mIndex( 0 ), mLockCount( 0 ) + { + for( size_t i=0; i<2; ++i ) + mSemaphores[i] = CreateSemaphore( NULL, 0, mNumThreads, NULL ); + } + //----------------------------------------------------------------------------------- + Barrier::~Barrier() + { + for( size_t i=0; i<2; ++i ) + CloseHandle( mSemaphores[i] ); + } + //----------------------------------------------------------------------------------- + void Barrier::sync(void) + { + //We need to be absolutely certain we read mIndex before incrementing mLockCount + volatile size_t idx = mIndex; + MemoryBarrier(); + + #ifndef __MINGW32__ + LONG oldLockCount = _InterlockedExchangeAdd( &mLockCount, 1 ); + #else + LONG oldLockCount = InterlockedExchangeAdd( &mLockCount, 1 ); + #endif + if( oldLockCount != mNumThreads - 1 ) + { + WaitForSingleObject( mSemaphores[idx], INFINITE ); + } + else + { + //Swap the index to use the other semaphore. Otherwise a thread that runs too fast + //gets to the next sync point and enters the semaphore, causing threads from this + //one to get stuck in the current sync point (and ultimately, deadlock). + mIndex = !idx; + mLockCount = 0; + if( mNumThreads > 1 ) + ReleaseSemaphore( mSemaphores[idx], mNumThreads - 1, NULL ); + } + } +} \ No newline at end of file diff --git a/OgreMain/src/Threading/OgreLightweightMutexPThreads.cpp b/OgreMain/src/Threading/OgreLightweightMutexPThreads.cpp new file mode 100644 index 00000000000..bb1252a2530 --- /dev/null +++ b/OgreMain/src/Threading/OgreLightweightMutexPThreads.cpp @@ -0,0 +1,59 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE + (Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2014 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#include "OgreStableHeaders.h" + +#include "Threading/OgreLightweightMutex.h" + +namespace Ogre +{ + LightweightMutex::LightweightMutex() + { + pthread_mutex_init( &mMutex, 0 ); + } + //----------------------------------------------------------------------------------- + LightweightMutex::~LightweightMutex() + { + pthread_mutex_destroy( &mMutex ); + } + //----------------------------------------------------------------------------------- + void LightweightMutex::lock() + { + pthread_mutex_lock( &mMutex ); + } + //----------------------------------------------------------------------------------- + bool LightweightMutex::tryLock() + { + return pthread_mutex_trylock( &mMutex ) == 0; + } + //----------------------------------------------------------------------------------- + void LightweightMutex::unlock() + { + pthread_mutex_unlock( &mMutex ); + } +} diff --git a/OgreMain/src/Threading/OgreLightweightMutexWin.cpp b/OgreMain/src/Threading/OgreLightweightMutexWin.cpp new file mode 100644 index 00000000000..864a596e8b9 --- /dev/null +++ b/OgreMain/src/Threading/OgreLightweightMutexWin.cpp @@ -0,0 +1,85 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE + (Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2014 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#include "OgreStableHeaders.h" + +#include "Threading/OgreLightweightMutex.h" + +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#include +#ifdef __MINGW32__ + // MinGW doesn't have "_Interlocked" functions, but those without "_" and in winbase.h + #include +#endif + +namespace Ogre +{ + LightweightMutex::LightweightMutex() : + mCounter( 0 ) + { + mSemaphore = CreateSemaphore( NULL, 0, 1, NULL ); + } + //----------------------------------------------------------------------------------- + LightweightMutex::~LightweightMutex() + { + CloseHandle( mSemaphore ); + } + //----------------------------------------------------------------------------------- + void LightweightMutex::lock() + { + #ifndef __MINGW32__ + if( _InterlockedIncrement( &mCounter ) > 1 ) + WaitForSingleObject( mSemaphore, INFINITE ); + #else + if( InterlockedIncrement( &mCounter ) > 1 ) + WaitForSingleObject( mSemaphore, INFINITE ); + #endif + } + //----------------------------------------------------------------------------------- + bool LightweightMutex::tryLock() + { + #ifndef __MINGW32__ + long result = _InterlockedCompareExchange( &mCounter, 1, 0 ); + #else + long result = InterlockedCompareExchange( &mCounter, 1, 0 ); + #endif + return (result == 0); + } + //----------------------------------------------------------------------------------- + void LightweightMutex::unlock() + { + #ifndef __MINGW32__ + if( _InterlockedDecrement( &mCounter ) > 0 ) + ReleaseSemaphore( mSemaphore, 1, NULL ); + #else + if( InterlockedDecrement( &mCounter ) > 0 ) + ReleaseSemaphore( mSemaphore, 1, NULL ); + #endif + } +} diff --git a/OgreMain/src/Threading/OgreThreadsPThreads.cpp b/OgreMain/src/Threading/OgreThreadsPThreads.cpp new file mode 100644 index 00000000000..1080b4b4249 --- /dev/null +++ b/OgreMain/src/Threading/OgreThreadsPThreads.cpp @@ -0,0 +1,78 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE + (Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2014 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#include "OgreStableHeaders.h" + +#include "Threading/OgreThreads.h" + +namespace Ogre +{ + ThreadHandle::ThreadHandle( size_t threadIdx, void *userParam ) : + mThreadIdx( threadIdx ), + mUserParam( userParam ) + { + } + //----------------------------------------------------------------------------------- + ThreadHandle::~ThreadHandle() + { + } + //----------------------------------------------------------------------------------- + //----------------------------------------------------------------------------------- + + ThreadHandlePtr Threads::CreateThread( THREAD_ENTRY_POINT entryPoint, size_t threadIdx, void *param ) + { + ThreadHandle *threadArg( new ThreadHandle( threadIdx, param ) ); + ThreadHandlePtr retVal( new ThreadHandle( threadIdx, param ) ); + pthread_t threadId; + pthread_create( &threadId, NULL, entryPoint, threadArg ); + retVal->_setOsHandle( threadId ); + return retVal; + } + //----------------------------------------------------------------------------------- + void Threads::WaitForThreads( size_t numThreadHandles, const ThreadHandlePtr *threadHandles ) + { + assert( numThreadHandles < 128 ); + + for( size_t i=0; i_getOsHandle(), NULL ); + } + //----------------------------------------------------------------------------------- + void Threads::WaitForThreads( const ThreadHandleVec &threadHandles ) + { + if( !threadHandles.empty() ) + Threads::WaitForThreads( threadHandles.size(), &threadHandles[0] ); + } + //----------------------------------------------------------------------------------- + void Threads::Sleep( uint32 milliseconds ) + { + timespec timeToSleep; + timeToSleep.tv_nsec = (milliseconds % 1000) * 1000000; + timeToSleep.tv_sec = milliseconds / 1000; + nanosleep( &timeToSleep, 0 ); + } +} diff --git a/OgreMain/src/Threading/OgreThreadsWin.cpp b/OgreMain/src/Threading/OgreThreadsWin.cpp new file mode 100644 index 00000000000..006c0a975bc --- /dev/null +++ b/OgreMain/src/Threading/OgreThreadsWin.cpp @@ -0,0 +1,84 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE + (Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2014 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#include "OgreStableHeaders.h" + +#include "Threading/OgreThreads.h" + +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#include + +namespace Ogre +{ + ThreadHandle::ThreadHandle( size_t threadIdx, void *userParam ) : + mThread( 0 ), + mThreadIdx( threadIdx ), + mUserParam( userParam ) + { + } + //----------------------------------------------------------------------------------- + ThreadHandle::~ThreadHandle() + { + if( mThread ) + CloseHandle( mThread ); + mThread = 0; + } + //----------------------------------------------------------------------------------- + //----------------------------------------------------------------------------------- + + ThreadHandlePtr Threads::CreateThread( THREAD_ENTRY_POINT entryPoint, size_t threadIdx, void *param ) + { + ThreadHandle *threadArg( new ThreadHandle( threadIdx, param ) ); + ThreadHandlePtr retVal( new ThreadHandle( threadIdx, param ) ); + HANDLE handle = ::CreateThread( 0, 0, entryPoint, threadArg, 0, 0 ); + retVal->_setOsHandle( handle ); + return retVal; + } + //----------------------------------------------------------------------------------- + void Threads::WaitForThreads( size_t numThreadHandles, const ThreadHandlePtr *threadHandles ) + { + assert( numThreadHandles < 128 ); + HANDLE hThreads[128]; + for( size_t i=0; i_getOsHandle(); + + WaitForMultipleObjects( numThreadHandles, hThreads, true, INFINITE ); + } + //----------------------------------------------------------------------------------- + void Threads::WaitForThreads( const ThreadHandleVec &threadHandles ) + { + if( !threadHandles.empty() ) + Threads::WaitForThreads( threadHandles.size(), &threadHandles[0] ); + } + //----------------------------------------------------------------------------------- + void Threads::Sleep( uint32 milliseconds ) + { + ::Sleep( milliseconds ); + } +}