Delete shiny

c++11
scrawl 10 years ago
parent 4e69e7cc0f
commit af67de73a5

@ -418,7 +418,6 @@ IF(NOT WIN32 AND NOT APPLE)
# Install licenses
INSTALL(FILES "docs/license/DejaVu Font License.txt" DESTINATION "${LICDIR}" )
INSTALL(FILES "extern/shiny/License.txt" DESTINATION "${LICDIR}" RENAME "Shiny License.txt" )
# Install icon and desktop file
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "openmw")
@ -542,7 +541,6 @@ include_directories(libs)
add_subdirectory(libs/openengine)
# Extern
#add_subdirectory (extern/shiny)
#add_subdirectory (extern/ogre-ffmpeg-videoplayer)
add_subdirectory (extern/oics)
#add_subdirectory (extern/sdl4ogre)
@ -680,10 +678,6 @@ if (WIN32)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNINGS} ${MT_BUILD}")
# boost::wave has a few issues with signed / unsigned conversions, so we suppress those here
set(SHINY_WARNINGS "${WARNINGS} /wd4245")
set_target_properties(shiny PROPERTIES COMPILE_FLAGS "${SHINY_WARNINGS} ${MT_BUILD}")
# oics uses tinyxml, which has an initialized but unused variable
set(OICS_WARNINGS "${WARNINGS} /wd4189")
set_target_properties(oics PROPERTIES COMPILE_FLAGS "${OICS_WARNINGS} ${MT_BUILD}")

@ -204,7 +204,6 @@ target_link_libraries(openmw-cs
${OGRE_Overlay_LIBRARIES}
${OGRE_STATIC_PLUGINS}
${OPENSCENEGRAPH_LIBRARIES}
${SHINY_LIBRARIES}
${Boost_LIBRARIES}
${BULLET_LIBRARIES}
${QT_LIBRARIES}

@ -129,7 +129,6 @@ target_link_libraries(openmw
${OENGINE_LIBRARY}
${OGRE_LIBRARIES}
${OGRE_STATIC_PLUGINS}
${SHINY_LIBRARIES}
${Boost_LIBRARIES}
${OPENAL_LIBRARY}
${SOUND_INPUT_LIBRARY}

@ -27,8 +27,6 @@
#include <OgreMaterialManager.h>
#include <OgreStringConverter.h>
#include <extern/shiny/Main/Factory.hpp>
namespace Terrain
{

@ -1,54 +0,0 @@
cmake_minimum_required(VERSION 2.8)
# This is NOT intended as a stand-alone build system! Instead, you should include this from the main CMakeLists of your project.
# Make sure to link against Ogre and boost::filesystem.
option(SHINY_BUILD_OGRE_PLATFORM "build the Ogre platform" ON)
set(SHINY_LIBRARY "shiny")
set(SHINY_OGREPLATFORM_LIBRARY "shiny.OgrePlatform")
# Sources
set(SOURCE_FILES
Main/Factory.cpp
Main/MaterialInstance.cpp
Main/MaterialInstancePass.cpp
Main/MaterialInstanceTextureUnit.cpp
Main/Platform.cpp
Main/Preprocessor.cpp
Main/PropertyBase.cpp
Main/ScriptLoader.cpp
Main/ShaderInstance.cpp
Main/ShaderSet.cpp
)
set(OGRE_PLATFORM_SOURCE_FILES
Platforms/Ogre/OgreGpuProgram.cpp
Platforms/Ogre/OgreMaterial.cpp
Platforms/Ogre/OgreMaterialSerializer.cpp
Platforms/Ogre/OgrePass.cpp
Platforms/Ogre/OgrePlatform.cpp
Platforms/Ogre/OgreTextureUnitState.cpp
)
file(GLOB OGRE_PLATFORM_SOURCE_FILES Platforms/Ogre/*.cpp)
add_library(${SHINY_LIBRARY} STATIC ${SOURCE_FILES})
set(SHINY_LIBRARIES ${SHINY_LIBRARY})
if (SHINY_BUILD_OGRE_PLATFORM)
add_library(${SHINY_OGREPLATFORM_LIBRARY} STATIC ${OGRE_PLATFORM_SOURCE_FILES})
set(SHINY_LIBRARIES ${SHINY_LIBRARIES} ${SHINY_OGREPLATFORM_LIBRARY})
endif()
set(SHINY_LIBRARY ${SHINY_LIBRARY} PARENT_SCOPE)
if (DEFINED SHINY_BUILD_MATERIAL_EDITOR)
add_subdirectory(Editor)
set(SHINY_BUILD_EDITOR_FLAG ${SHINY_BUILD_EDITOR_FLAG} PARENT_SCOPE)
endif()
link_directories(${CMAKE_CURRENT_BINARY_DIR})
set(SHINY_LIBRARIES ${SHINY_LIBRARIES} PARENT_SCOPE)

@ -1,32 +0,0 @@
/*!
\page configurations Configurations
A common task in shader development is to provide a different set of simpler shaders for all your materials. Some examples:
- When rendering cubic or planar reflection maps in real-time, you will want to disable shadows.
- For an in-game minimap render target, you don't want to have fog.
For this task, the library provides a \a Configuration concept.
A Configuration is a set of properties that can override global settings, as long as this Configuration is active.
Here's an example. Say you have a global setting with the name 'shadows' that controls if your materials receive shadows.
Now, lets create a configuration for our reflection render targets that disables shadows for all materials. Paste the following in a new file with the extension '.configuration':
\code
configuration reflection_targets
{
shadows false
}
\endcode
\note You may also create configurations using sh::Factory::createConfiguration.
The active Configuration is controlled by the active material scheme in Ogre. So, in order to use the configuration "reflection_targets" for your reflection renders, simply call
\code
viewport->setMaterialScheme ("reflection_targets");
\endcode
on the Ogre viewport of your reflection render!
*/

File diff suppressed because it is too large Load Diff

@ -1,65 +0,0 @@
/*!
\page getting-started Getting started
\section download Download the source
\code
git clone git@github.com:scrawl/shiny.git
\endcode
\section building Build the source
The source files you want to build are:
- Main/*.cpp
- Preprocessor/*.cpp (unless you are using the system install of boost::wave, more below)
- Platforms/Ogre/*.cpp
You can either build the sources as a static library, or simply add the sources to the source tree of your project.
If you use CMake, you might find the included CMakeLists.txt useful. It builds static libraries with the names "shiny" and "shiny.OgrePlatform".
\note The CMakeLists.txt is not intended as a stand-alone build system! Instead, you should include this from the main CMakeLists of your project.
Make sure to link against OGRE and the boost filesystem library.
If your boost version is older than 1.49, you must set the SHINY_USE_WAVE_SYSTEM_INSTALL variable and additionally link against the boost wave library.
\code
set(SHINY_USE_WAVE_SYSTEM_INSTALL "TRUE")
\endcode
\section code Basic initialisation code
Add the following code to your application:
\code{cpp}
#include <shiny/Main/Factory.hpp>
#include <shiny/Platforms/OgrePlatform/OgrePlatform.hpp>
....
sh::OgrePlatform* platform = new sh::OgrePlatform(
"General", // OGRE Resource group to use for creating materials.
myApplication.getDataPath() + "/" + "materials" // Path to look for materials and shaders. NOTE: This does NOT use the Ogre resource system, so you have to specify an absolute path.
);
sh::Factory* factory = new sh::Factory(platform);
// Set a language. Valid options: CG, HLSL, GLSL
factory->setCurrentLanguage(sh::Language_GLSL);
factory->loadAllFiles();
....
your application runs here
....
// don't forget to delete on exit
delete factory;
\endcode
That's it! Now you can start defining materials. Refer to the page \ref defining-materials-shaders .
*/

@ -1,49 +0,0 @@
/*!
\page lod Material LOD
\section howitworks How it works
When Ogre requests a technique for a specific LOD index, the Factory selects the appropriate LOD configuration which then temporarily overrides the global settings in the shaders. We can use this to disable shader features one by one at a lower LOD, resulting in simpler and faster techniques for distant objects.
\section howtouseit How to use it
- Create a file with the extension '.lod'. There you can specify shader features to disable at a specific LOD level. Higher LOD index refers to a lower LOD. Example contents:
\code
lod_configuration 1
{
specular_mapping false
}
lod_configuration 2
{
specular_mapping false
normal_mapping false
}
lod_configuration 3
{
terrain_composite_map true
specular_mapping false
normal_mapping false
}
\endcode
\note You can also add LOD configurations by calling \a sh::Factory::registerLodConfiguration.
\note Do not use an index of 0. LOD 0 refers to the highest LOD, and you will never want to disable features at the highest LOD level.
- In your materials, specify the distances at which a lower LOD kicks in. Note that the actual distance might also be affected by the viewport and current entity LOD bias. In this example, the first LOD level (lod index 1) would normally be applied at a distance of 100 units, the next after 300, and the last after 1000 units.
\code
material sample_material
{
lod_values 100 300 1000
... your passes, texture units etc ...
}
\endcode
*/

@ -1,283 +0,0 @@
/*!
\page macros Shader Macros
\tableofcontents
\section Shader Language
These macros are automatically defined, depending on the shader language that has been set by the application using sh::Factory::setCurrentLanguage.
- SH_GLSL
- SH_HLSL
- SH_CG
<B>Example:</B>
\code
#if SH_GLSL == 1
// glsl porting code
#endif
#if SH_CG == 1 || SH_HLSL == 1
// cg / hlsl porting code (similiar syntax)
#endif
\endcode
\note It is encouraged to use the shipped porting header (extra/core.h) by #include-ing it in your shaders. If you do that, you should not have to use the above macros directly.
\section vertex-fragment Vertex / fragment shader
These macros are automatically defined, depending on the type of shader that is currently being compiled.
- SH_VERTEX_SHADER
- SH_FRAGMENT_SHADER
If you use the same source file for both vertex and fragment shader, then it is advised to use these macros for blending out the unused source. This will reduce your compile time.
\section passthrough Vertex -> Fragment passthrough
In shader development, a common task is to pass variables from the vertex to the fragment shader. This is no problem if you have a deterministic shader source (i.e. no #ifdefs).
However, as soon as you begin to have lots of permutations of the same shader source, a problem arises. All current GPUs have a limit of 8 vertex to fragment passthroughs (with 4 components each, for example a float4).
A common optimization is to put several individual float values together in a float4 (so-called "Packing"). But if your shader has lots of permutations and the passthrough elements you actually need are not known beforehand, it can be very tedious to pack manually. With the following macros, packing can become easier.
\subsection shAllocatePassthrough shAllocatePassthrough
<B>Usage:</B> \@shAllocatePassthrough(num_components, name)
<B>Example:</B>
\code
#if FRAGMENT_NEED_DEPTH
@shAllocatePassthrough(1, depth)
#endif
\endcode
This is the first thing you should do before using any of the macros below.
\subsection shPassthroughVertexOutputs shPassthroughVertexOutputs
<B>Usage:</B> \@shPassthroughVertexOutputs
Use this in the inputs/outputs section of your vertex shader, in order to declare all the outputs that are needed for packing the variables that you want passed to the fragment.
\subsection shPassthroughFragmentInputs shPassthroughFragmentInputs
<B>Usage:</B> \@shPassthroughFragmentInputs
Use this in the inputs/outputs section of your fragment shader, in order to declare all the inputs that are needed for receiving the variables that you want passed to the fragment.
\subsection shPassthroughAssign shPassthroughAssign
<B>Usage:</B> \@shPassthroughAssign(name, value)
Use this in the vertex shader for assigning a value to the variable you want passed to the fragment.
<B>Example:</B>
\code
#if FRAGMENT_NEED_DEPTH
@shPassthroughAssign(depth, shOutputPosition.z);
#endif
\endcode
\subsection shPassthroughReceive shPassthroughReceive
<B>Usage:</B> \@shPassthroughReceive(name)
Use this in the fragment shader to receive the passed value.
<B>Example:</B>
\code
#if FRAGMENT_NEED_DEPTH
float depth = @shPassthroughReceive(depth);
#endif
\endcode
\section texUnits Texture units
\subsection shUseSampler shUseSampler
<B>Usage:</B> \@shUseSampler(samplerName)
Requests the texture unit with name \a samplerName to be available for use in this pass.
Why is this necessary? If you have a derived material that does not use all of the texture units that its parent defines (for example, if an optional asset such as a normal map is not available), there would be no way to know which texture units are actually needed and which can be skipped in the creation process (those that are never referenced in the shader).
\section properties Property retrieval / binding
\subsection shPropertyHasValue shPropertyHasValue
<B>Usage:</B> \@shPropertyHasValue(property)
Gets replaced by 1 if the property's value is not empty, or 0 if it is empty.
Useful for checking whether an optional texture is present or not.
<B>Example:</B>
\code
#if @shPropertyHasValue(specularMap)
// specular mapping code
#endif
#if @shPropertyHasValue(normalMap)
// normal mapping code
#endif
\endcode
\subsection shUniformProperty shUniformProperty
<B>Usage:</B> \@shUniformProperty<4f|3f|2f|1f|int> (uniformName, property)
Binds the value of \a property (from the shader_properties of the pass this shader belongs to) to the uniform with name \a uniformName.
The following variants are available, depending on the type of your uniform variable:
- \@shUniformProperty4f
- \@shUniformProperty3f
- \@shUniformProperty2f
- \@shUniformProperty1f
- \@shUniformPropertyInt
<B>Example:</B> \@shUniformProperty1f (uFresnelScale, fresnelScale)
\subsection shPropertyBool shPropertyBool
Retrieve a boolean property of the pass that this shader belongs to, gets replaced with either 0 or 1.
<B>Usage:</B> \@shPropertyBool(propertyName)
<B>Example:</B>
\code
#if @shPropertyBool(has_vertex_colors)
...
#endif
\endcode
\subsection shPropertyString shPropertyString
Retrieve a string property of the pass that this shader belongs to
<B>Usage:</B> \@shPropertyString(propertyName)
\subsection shPropertyEqual shPropertyEqual
Check if the value of a property equals a specific value, gets replaced with either 0 or 1. This is useful because the preprocessor cannot compare strings, only numbers.
<B>Usage:</B> \@shPropertyEqual(propertyName, value)
<B>Example:</B>
\code
#if @shPropertyEqual(lighting_mode, phong)
...
#endif
\endcode
\section globalSettings Global settings
\subsection shGlobalSettingBool shGlobalSettingBool
Retrieves the boolean value of a specific global setting, gets replaced with either 0 or 1. The value can be set using sh::Factory::setGlobalSetting.
<B>Usage:</B> \@shGlobalSettingBool(settingName)
\subsection shGlobalSettingEqual shGlobalSettingEqual
Check if the value of a global setting equals a specific value, gets replaced with either 0 or 1. This is useful because the preprocessor cannot compare strings, only numbers.
<B>Usage:</B> \@shGlobalSettingEqual(settingName, value)
\subsection shGlobalSettingString shGlobalSettingString
Gets replaced with the current value of a given global setting. The value can be set using sh::Factory::setGlobalSetting.
<B>Usage:</B> \@shGlobalSettingString(settingName)
\section sharedParams Shared parameters
\subsection shSharedParameter shSharedParameter
Allows you to bind a custom value to a uniform parameter.
<B>Usage</B>: \@shSharedParameter(sharedParameterName)
<B>Example</B>: \@shSharedParameter(pssmSplitPoints) - now the uniform parameter 'pssmSplitPoints' can be altered in all shaders that use it by executing sh::Factory::setSharedParameter("pssmSplitPoints", value)
\note You may use the same shared parameter in as many shaders as you want. But don't forget to add the \@shSharedParameter macro to every shader that uses this shared parameter.
\section autoconstants Auto constants
\subsection shAutoConstant shAutoConstant
<B>Usage:</B> \@shAutoConstant(uniformName, autoConstantName, [extraData])
<B>Example</B>: \@shAutoConstant(uModelViewMatrix, worldviewproj_matrix)
<B>Example</B>: \@shAutoConstant(uLightPosition4, light_position, 4)
Binds auto constant with name \a autoConstantName to the uniform \a uniformName. Optionally, you may specify extra data (for example the light index), as required by some auto constants.
The auto constant names are the same as Ogre's. Read the section "3.1.9 Using Vertex/Geometry/Fragment Programs in a Pass" of the Ogre manual for a list of all auto constant names.
\section misc Misc
\subsection shForeach shForeach
<B>Usage:</B> \@shForeach(n)
Repeats the content of this foreach block \a n times. The end of the block is marked via \@shEndForeach, and the current iteration number can be retrieved via \@shIterator.
\note Nested foreach blocks are currently \a not supported.
\note For technical reasons, you can only use constant numbers, properties (\@shPropertyString) or global settings (\@shGlobalSettingString) as \a n parameter.
<B>Example:</B>
\code
@shForeach(3)
this is iteration number @shIterator
@shEndForeach
Gets replaced with:
this is iteration number 0
this is iteration number 1
this is iteration number 2
\endcode
Optionally, you can pass a constant offset to \@shIterator. Example:
\code
@shForeach(3)
this is iteration number @shIterator(7)
@shEndForeach
Gets replaced with:
this is iteration number 7
this is iteration number 8
this is iteration number 9
\endcode
\subsection shCounter shCounter
Gets replaced after the preprocessing step with the number that equals the n-th occurence of counters of the same ID.
<B>Usage:</B> \@shCounter(ID)
<B>Example</B>:
\code
@shCounter(0)
@shCounter(0)
@shCounter(1)
@shCounter(0)
\endcode
Gets replaced with:
\code
0
1
0
2
\endcode
*/

@ -1,13 +0,0 @@
/*!
\mainpage
- \ref getting-started
- \ref defining-materials-shaders
- \ref macros
- \ref configurations
- \ref lod
- sh::Factory - the main interface class
*/

@ -1,131 +0,0 @@
/*!
\page defining-materials-shaders Defining materials and shaders
\section first-material Your first material
Create a file called "myFirstMaterial.mat" and place it in the path you have used in your initialisation code (see \ref getting-started). Paste the following:
\code
material my_first_material
{
diffuse 1.0 1.0 1.0 1.0
specular 0.4 0.4 0.4 32
ambient 1.0 1.0 1.0
emissive 0.0 0.0 0.0
diffuseMap black.png
pass
{
diffuse $diffuse
specular $specular
ambient $ambient
emissive $emissive
texture_unit diffuseMap
{
texture $diffuseMap
create_in_ffp true // use this texture unit for fixed function pipeline
}
}
}
material material1
{
parent my_first_material
diffuseMap texture1.png
}
material material2
{
parent my_first_material
diffuseMap texture2.png
}
\endcode
\section first-shader The first shader
Change the 'pass' section to include some shaders:
\code
pass
{
vertex_program my_first_shader_vertex
fragment_program my_first_shader_fragment
...
}
\endcode
\note This does \a not refer to a single shader with a fixed source code, but in fact will automatically create a new \a instance of this shader (if necessary), which can have its own uniform variables, compile-time macros and much more!
Next, we're going to define our shaders. Paste this in a new file called 'myfirstshader.shaderset'
\code
shader_set my_first_shader_vertex
{
source example.shader
type vertex
profiles_cg vs_2_0 arbvp1
profiles_hlsl vs_2_0
}
shader_set my_first_shader_fragment
{
source example.shader
type fragment
profiles_cg ps_2_x ps_2_0 ps arbfp1
profiles_hlsl ps_2_0
}
\endcode
Some notes:
- There is no entry_point property because the entry point is always \a main.
- Both profiles_cg and profiles_hlsl are a list of shader profiles. The first profile that is supported is automatically picked. GLSL does not have shader profiles.
Now, let's get into writing our shader! As you can guess from above, the filename should be 'example.shader'.
Make sure to also copy the 'core.h' file to the same location. It is included in shiny's source tree under 'Extra/'.
Important: a newline at the end of the file is <b>required</b>. Many editors do this automatically or can be configured to do so. If there is no newline at the end of the file, and the last line is '#endif', you will get the rather cryptic error message " ill formed preprocessor directive: #endif" from boost::wave.
\code
#include "core.h"
#ifdef SH_VERTEX_SHADER
SH_BEGIN_PROGRAM
shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix)
shVertexInput(float2, uv0)
shOutput(float2, UV)
SH_START_PROGRAM
{
shOutputPosition = shMatrixMult(wvp, shInputPosition);
UV = uv0;
}
#else
SH_BEGIN_PROGRAM
// NOTE: It is important that the sampler name here (diffuseMap) matches
// the name of the texture unit in the material. This is necessary because the system
// skips texture units that are never "referenced" in the shader. This can be the case
// when your base material has optional assets (for example a normal map) that are not
// used by some derived materials.
shSampler2D(diffuseMap)
shInput(float2, UV)
SH_START_PROGRAM
{
shOutputColour(0) = shSample(diffuseMap, UV);
}
#endif
\endcode
There you have it! This shader will compile in several languages thanks to the porting defines in "core.h". If you need more defines, feel free to add them and don't forget to send them to me!
For a full list of macros available when writing your shaders, refer to the page \ref macros
In the future, some more in-depth shader examples might follow.
*/

@ -1,195 +0,0 @@
#include "Actions.hpp"
#include "../Main/Factory.hpp"
namespace sh
{
void ActionDeleteMaterial::execute()
{
sh::Factory::getInstance().destroyMaterialInstance(mName);
}
void ActionCloneMaterial::execute()
{
sh::MaterialInstance* sourceMaterial = sh::Factory::getInstance().getMaterialInstance(mSourceName);
std::string sourceMaterialParent = static_cast<sh::MaterialInstance*>(sourceMaterial->getParent())->getName();
sh::MaterialInstance* material = sh::Factory::getInstance().createMaterialInstance(
mDestName, sourceMaterialParent);
sourceMaterial->copyAll(material, sourceMaterial, false);
material->setSourceFile(sourceMaterial->getSourceFile());
}
void ActionSaveAll::execute()
{
sh::Factory::getInstance().saveAll();
}
void ActionChangeGlobalSetting::execute()
{
sh::Factory::getInstance().setGlobalSetting(mName, mNewValue);
}
void ActionCreateConfiguration::execute()
{
sh::Configuration newConfiguration;
sh::Factory::getInstance().createConfiguration(mName);
}
void ActionDeleteConfiguration::execute()
{
sh::Factory::getInstance().destroyConfiguration(mName);
}
void ActionChangeConfiguration::execute()
{
sh::Configuration* c = sh::Factory::getInstance().getConfiguration(mName);
c->setProperty(mKey, sh::makeProperty(new sh::StringValue(mValue)));
sh::Factory::getInstance().notifyConfigurationChanged();
}
void ActionDeleteConfigurationProperty::execute()
{
sh::Configuration* c = sh::Factory::getInstance().getConfiguration(mName);
c->deleteProperty(mKey);
sh::Factory::getInstance().notifyConfigurationChanged();
}
void ActionSetMaterialProperty::execute()
{
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
m->setProperty(mKey, sh::makeProperty(mValue));
sh::Factory::getInstance().notifyConfigurationChanged();
}
void ActionDeleteMaterialProperty::execute()
{
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
m->deleteProperty(mKey);
sh::Factory::getInstance().notifyConfigurationChanged();
}
void ActionCreatePass::execute()
{
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
m->createPass();
sh::Factory::getInstance().notifyConfigurationChanged();
}
void ActionDeletePass::execute()
{
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
m->deletePass(mPassIndex);
sh::Factory::getInstance().notifyConfigurationChanged();
}
void ActionSetPassProperty::execute()
{
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
assert (m->getPasses()->size() > mPassIndex);
m->getPasses()->at(mPassIndex).setProperty (mKey, sh::makeProperty(mValue));
sh::Factory::getInstance().notifyConfigurationChanged();
}
void ActionDeletePassProperty::execute()
{
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
assert (m->getPasses()->size() > mPassIndex);
m->getPasses()->at(mPassIndex).deleteProperty(mKey);
sh::Factory::getInstance().notifyConfigurationChanged();
}
void ActionSetShaderProperty::execute()
{
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
assert (m->getPasses()->size() > mPassIndex);
m->getPasses()->at(mPassIndex).mShaderProperties.setProperty (mKey, sh::makeProperty(mValue));
sh::Factory::getInstance().notifyConfigurationChanged();
}
void ActionDeleteShaderProperty::execute()
{
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
assert (m->getPasses()->size() > mPassIndex);
m->getPasses()->at(mPassIndex).mShaderProperties.deleteProperty (mKey);
sh::Factory::getInstance().notifyConfigurationChanged();
}
void ActionSetTextureProperty::execute()
{
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
assert (m->getPasses()->size() > mPassIndex);
assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex);
m->getPasses()->at(mPassIndex).mTexUnits.at(mTextureIndex).setProperty(mKey, sh::makeProperty(mValue));
sh::Factory::getInstance().notifyConfigurationChanged();
}
void ActionDeleteTextureProperty::execute()
{
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
assert (m->getPasses()->size() > mPassIndex);
assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex);
m->getPasses()->at(mPassIndex).mTexUnits.at(mTextureIndex).deleteProperty(mKey);
sh::Factory::getInstance().notifyConfigurationChanged();
}
void ActionCreateTextureUnit::execute()
{
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
assert (m->getPasses()->size() > mPassIndex);
m->getPasses()->at(mPassIndex).createTextureUnit(mTexUnitName);
sh::Factory::getInstance().notifyConfigurationChanged();
}
void ActionDeleteTextureUnit::execute()
{
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
assert (m->getPasses()->size() > mPassIndex);
assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex);
m->getPasses()->at(mPassIndex).mTexUnits.erase(m->getPasses()->at(mPassIndex).mTexUnits.begin() + mTextureIndex);
sh::Factory::getInstance().notifyConfigurationChanged();
}
void ActionMoveTextureUnit::execute()
{
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
assert (m->getPasses()->size() > mPassIndex);
assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex);
if (!mMoveUp)
assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex+1);
std::vector<MaterialInstanceTextureUnit> textures = m->getPasses()->at(mPassIndex).mTexUnits;
if (mMoveUp)
std::swap(textures[mTextureIndex-1], textures[mTextureIndex]);
else
std::swap(textures[mTextureIndex+1], textures[mTextureIndex]);
m->getPasses()->at(mPassIndex).mTexUnits = textures;
sh::Factory::getInstance().notifyConfigurationChanged();
}
void ActionChangeTextureUnitName::execute()
{
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
assert (m->getPasses()->size() > mPassIndex);
assert (m->getPasses()->at(mPassIndex).mTexUnits.size() > mTextureIndex);
m->getPasses()->at(mPassIndex).mTexUnits[mTextureIndex].setName(mTexUnitName);
sh::Factory::getInstance().notifyConfigurationChanged();
}
}

@ -1,307 +0,0 @@
#ifndef SH_ACTIONS_H
#define SH_ACTIONS_H
#include <string>
namespace sh
{
class Action
{
public:
virtual void execute() = 0;
virtual ~Action() {}
};
class ActionDeleteMaterial : public Action
{
public:
ActionDeleteMaterial(const std::string& name)
: mName(name) {}
virtual void execute();
private:
std::string mName;
};
class ActionCloneMaterial : public Action
{
public:
ActionCloneMaterial(const std::string& sourceName, const std::string& destName)
: mSourceName(sourceName), mDestName(destName) {}
virtual void execute();
private:
std::string mSourceName;
std::string mDestName;
};
class ActionSaveAll : public Action
{
public:
virtual void execute();
};
class ActionChangeGlobalSetting : public Action
{
public:
ActionChangeGlobalSetting(const std::string& name, const std::string& newValue)
: mName(name), mNewValue(newValue) {}
virtual void execute();
private:
std::string mName;
std::string mNewValue;
};
// configuration
class ActionCreateConfiguration : public Action
{
public:
ActionCreateConfiguration(const std::string& name)
: mName(name) {}
virtual void execute();
private:
std::string mName;
};
class ActionDeleteConfiguration : public Action
{
public:
ActionDeleteConfiguration(const std::string& name)
: mName(name) {}
virtual void execute();
private:
std::string mName;
};
class ActionChangeConfiguration : public Action
{
public:
ActionChangeConfiguration (const std::string& name, const std::string& key, const std::string& value)
: mName(name), mKey(key), mValue(value) {}
virtual void execute();
private:
std::string mName;
std::string mKey;
std::string mValue;
};
class ActionDeleteConfigurationProperty : public Action
{
public:
ActionDeleteConfigurationProperty (const std::string& name, const std::string& key)
: mName(name), mKey(key) {}
virtual void execute();
private:
std::string mName;
std::string mKey;
};
// material
class ActionSetMaterialProperty : public Action
{
public:
ActionSetMaterialProperty (const std::string& name, const std::string& key, const std::string& value)
: mName(name), mKey(key), mValue(value) {}
virtual void execute();
private:
std::string mName;
std::string mKey;
std::string mValue;
};
class ActionDeleteMaterialProperty : public Action
{
public:
ActionDeleteMaterialProperty (const std::string& name, const std::string& key)
: mName(name), mKey(key) {}
virtual void execute();
private:
std::string mName;
std::string mKey;
};
// pass
class ActionCreatePass : public Action
{
public:
ActionCreatePass (const std::string& name)
: mName(name) {}
virtual void execute();
private:
std::string mName;
};
class ActionDeletePass : public Action
{
public:
ActionDeletePass (const std::string& name, int passIndex)
: mName(name), mPassIndex(passIndex) {}
virtual void execute();
private:
std::string mName;
int mPassIndex;
};
class ActionSetPassProperty : public Action
{
public:
ActionSetPassProperty (const std::string& name, int passIndex, const std::string& key, const std::string& value)
: mName(name), mPassIndex(passIndex), mKey(key), mValue(value) {}
virtual void execute();
private:
std::string mName;
int mPassIndex;
std::string mKey;
std::string mValue;
};
class ActionDeletePassProperty : public Action
{
public:
ActionDeletePassProperty (const std::string& name, int passIndex, const std::string& key)
: mName(name), mPassIndex(passIndex), mKey(key) {}
virtual void execute();
private:
std::string mName;
int mPassIndex;
std::string mKey;
};
// shader
class ActionSetShaderProperty : public Action
{
public:
ActionSetShaderProperty (const std::string& name, int passIndex, const std::string& key, const std::string& value)
: mName(name), mPassIndex(passIndex), mKey(key), mValue(value) {}
virtual void execute();
private:
std::string mName;
int mPassIndex;
std::string mKey;
std::string mValue;
};
class ActionDeleteShaderProperty : public Action
{
public:
ActionDeleteShaderProperty (const std::string& name, int passIndex, const std::string& key)
: mName(name), mPassIndex(passIndex), mKey(key) {}
virtual void execute();
private:
std::string mName;
int mPassIndex;
std::string mKey;
};
// texture unit
class ActionChangeTextureUnitName : public Action
{
public:
ActionChangeTextureUnitName (const std::string& name, int passIndex, int textureIndex, const std::string& texUnitName)
: mName(name), mPassIndex(passIndex), mTextureIndex(textureIndex), mTexUnitName(texUnitName) {}
virtual void execute();
private:
std::string mName;
int mPassIndex;
int mTextureIndex;
std::string mTexUnitName;
};
class ActionCreateTextureUnit : public Action
{
public:
ActionCreateTextureUnit (const std::string& name, int passIndex, const std::string& texUnitName)
: mName(name), mPassIndex(passIndex), mTexUnitName(texUnitName) {}
virtual void execute();
private:
std::string mName;
int mPassIndex;
std::string mTexUnitName;
};
class ActionDeleteTextureUnit : public Action
{
public:
ActionDeleteTextureUnit (const std::string& name, int passIndex, int textureIndex)
: mName(name), mPassIndex(passIndex), mTextureIndex(textureIndex) {}
virtual void execute();
private:
std::string mName;
int mPassIndex;
int mTextureIndex;
};
class ActionMoveTextureUnit : public Action
{
public:
ActionMoveTextureUnit (const std::string& name, int passIndex, int textureIndex, bool moveUp)
: mName(name), mPassIndex(passIndex), mTextureIndex(textureIndex), mMoveUp(moveUp) {}
virtual void execute();
private:
std::string mName;
int mPassIndex;
int mTextureIndex;
bool mMoveUp;
};
class ActionSetTextureProperty : public Action
{
public:
ActionSetTextureProperty (const std::string& name, int passIndex, int textureIndex, const std::string& key, const std::string& value)
: mName(name), mPassIndex(passIndex), mTextureIndex(textureIndex), mKey(key), mValue(value) {}
virtual void execute();
private:
std::string mName;
int mPassIndex;
int mTextureIndex;
std::string mKey;
std::string mValue;
};
class ActionDeleteTextureProperty : public Action
{
public:
ActionDeleteTextureProperty (const std::string& name, int passIndex, int textureIndex, const std::string& key)
: mName(name), mPassIndex(passIndex), mTextureIndex(textureIndex), mKey(key) {}
virtual void execute();
private:
std::string mName;
int mPassIndex;
int mTextureIndex;
std::string mKey;
};
}
#endif

@ -1,31 +0,0 @@
#include "AddPropertyDialog.hpp"
#include "ui_addpropertydialog.h"
AddPropertyDialog::AddPropertyDialog(QWidget *parent)
: QDialog(parent)
, ui(new Ui::AddPropertyDialog)
, mType(0)
{
ui->setupUi(this);
connect(ui->buttonBox, SIGNAL(accepted()),
this, SLOT(accepted()));
connect(ui->buttonBox, SIGNAL(rejected()),
this, SLOT(rejected()));
}
void AddPropertyDialog::accepted()
{
mName = ui->lineEdit->text();
mType = ui->comboBox->currentIndex();
}
void AddPropertyDialog::rejected()
{
mName = "";
}
AddPropertyDialog::~AddPropertyDialog()
{
delete ui;
}

@ -1,22 +0,0 @@
#ifndef ADDPROPERTYDIALOG_H
#define ADDPROPERTYDIALOG_H
#include <QDialog>
namespace Ui {
class AddPropertyDialog;
}
class AddPropertyDialog : public QDialog
{
Q_OBJECT
public:
explicit AddPropertyDialog(QWidget *parent = 0);
~AddPropertyDialog();
private:
Ui::AddPropertyDialog *ui;
};
#endif // ADDPROPERTYDIALOG_H

@ -1,29 +0,0 @@
#ifndef ADDPROPERTYDIALOG_H
#define ADDPROPERTYDIALOG_H
#include <QDialog>
namespace Ui {
class AddPropertyDialog;
}
class AddPropertyDialog : public QDialog
{
Q_OBJECT
public:
explicit AddPropertyDialog(QWidget *parent = 0);
~AddPropertyDialog();
int mType;
QString mName;
public slots:
void accepted();
void rejected();
private:
Ui::AddPropertyDialog *ui;
};
#endif // ADDPROPERTYDIALOG_H

@ -1,61 +0,0 @@
set(SHINY_EDITOR_LIBRARY "shiny.Editor")
find_package(Qt4)
if (QT_FOUND)
add_definitions(-DSHINY_BUILD_MATERIAL_EDITOR=1)
set (SHINY_BUILD_EDITOR_FLAG -DSHINY_BUILD_MATERIAL_EDITOR=1 PARENT_SCOPE)
set(QT_USE_QTGUI 1)
# Headers that must be preprocessed
set(SHINY_EDITOR_HEADER_MOC
MainWindow.hpp
NewMaterialDialog.hpp
AddPropertyDialog.hpp
PropertySortModel.hpp
)
set(SHINY_EDITOR_UI
mainwindow.ui
newmaterialdialog.ui
addpropertydialog.ui
)
QT4_WRAP_CPP(MOC_SRCS ${SHINY_EDITOR_HEADER_MOC})
QT4_WRAP_UI(UI_HDRS ${SHINY_EDITOR_UI})
set(SOURCE_FILES
NewMaterialDialog.cpp
AddPropertyDialog.cpp
ColoredTabWidget.hpp
MainWindow.cpp
Editor.cpp
Actions.cpp
Query.cpp
PropertySortModel.cpp
${SHINY_EDITOR_UI} # Just to have them in the IDE's file explorer
)
include(${QT_USE_FILE})
set (CMAKE_INCLUDE_CURRENT_DIR "true")
include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_library(${SHINY_EDITOR_LIBRARY} STATIC ${SOURCE_FILES} ${MOC_SRCS} ${UI_HDRS})
set(SHINY_LIBRARIES ${SHINY_LIBRARIES}
${SHINY_EDITOR_LIBRARY}
${QT_LIBRARIES}
)
set(SHINY_LIBRARIES ${SHINY_LIBRARIES} PARENT_SCOPE)
else (QT_FOUND)
add_definitions(-DSHINY_BUILD_MATERIAL_EDITOR=0)
set (SHINY_BUILD_EDITOR_FLAG -DSHINY_BUILD_MATERIAL_EDITOR=0 PARENT_SCOPE)
message(STATUS "QT4 was not found. You will not be able to use the material editor.")
endif(QT_FOUND)

@ -1,24 +0,0 @@
#ifndef SHINY_EDITOR_COLOREDTABWIDGET_H
#define SHINY_EDITOR_COLOREDTABWIDGET_H
#include <QTabWidget>
namespace sh
{
/// Makes tabBar() public to allow changing tab title colors.
class ColoredTabWidget : public QTabWidget
{
public:
ColoredTabWidget(QWidget* parent = 0)
: QTabWidget(parent) {}
QTabBar* tabBar()
{
return QTabWidget::tabBar();
}
};
}
#endif

@ -1,117 +0,0 @@
#include "Editor.hpp"
#include <QApplication>
#include <QTimer>
#include <boost/thread.hpp>
#include "../Main/Factory.hpp"
#include "MainWindow.hpp"
namespace sh
{
Editor::Editor()
: mMainWindow(NULL)
, mApplication(NULL)
, mInitialized(false)
, mThread(NULL)
{
}
Editor::~Editor()
{
if (mMainWindow)
mMainWindow->mRequestExit = true;
if (mThread)
mThread->join();
delete mThread;
}
void Editor::show()
{
if (!mInitialized)
{
mInitialized = true;
mThread = new boost::thread(boost::bind(&Editor::runThread, this));
}
else
{
if (mMainWindow)
mMainWindow->mRequestShowWindow = true;
}
}
void Editor::runThread()
{
int argc = 0;
char** argv = NULL;
mApplication = new QApplication(argc, argv);
mApplication->setQuitOnLastWindowClosed(false);
mMainWindow = new MainWindow();
mMainWindow->mSync = &mSync;
mMainWindow->show();
mApplication->exec();
delete mApplication;
}
void Editor::update()
{
sh::Factory::getInstance().doMonitorShaderFiles();
if (!mMainWindow)
return;
{
boost::mutex::scoped_lock lock(mSync.mActionMutex);
// execute pending actions
while (mMainWindow->mActionQueue.size())
{
Action* action = mMainWindow->mActionQueue.front();
action->execute();
delete action;
mMainWindow->mActionQueue.pop();
}
}
{
boost::mutex::scoped_lock lock(mSync.mQueryMutex);
// execute pending queries
for (std::vector<Query*>::iterator it = mMainWindow->mQueries.begin(); it != mMainWindow->mQueries.end(); ++it)
{
Query* query = *it;
if (!query->mDone)
query->execute();
}
}
boost::mutex::scoped_lock lock2(mSync.mUpdateMutex);
// update the list of materials
mMainWindow->mState.mMaterialList.clear();
sh::Factory::getInstance().listMaterials(mMainWindow->mState.mMaterialList);
// update global settings
mMainWindow->mState.mGlobalSettingsMap.clear();
sh::Factory::getInstance().listGlobalSettings(mMainWindow->mState.mGlobalSettingsMap);
// update configuration list
mMainWindow->mState.mConfigurationList.clear();
sh::Factory::getInstance().listConfigurationNames(mMainWindow->mState.mConfigurationList);
// update shader list
mMainWindow->mState.mShaderSets.clear();
sh::Factory::getInstance().listShaderSets(mMainWindow->mState.mShaderSets);
mMainWindow->mState.mErrors += sh::Factory::getInstance().getErrorLog();
}
}

@ -1,73 +0,0 @@
#ifndef SH_EDITOR_H
#define SH_EDITOR_H
#if SHINY_BUILD_MATERIAL_EDITOR
class QApplication;
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/mutex.hpp>
namespace boost
{
class thread;
}
namespace sh
{
class MainWindow;
struct SynchronizationState
{
boost::mutex mUpdateMutex;
boost::mutex mActionMutex;
boost::mutex mQueryMutex;
};
class Editor
{
public:
Editor();
~Editor();
void show();
void update();
private:
bool mInitialized;
MainWindow* mMainWindow;
QApplication* mApplication;
SynchronizationState mSync;
boost::thread* mThread;
void runThread();
void processShowWindow();
};
}
#else
// Dummy implementation, so that the user's code does not have to be polluted with #ifdefs
namespace sh
{
class Editor
{
public:
Editor() {}
~Editor() {}
void show() {}
void update() {}
};
}
#endif
#endif

@ -1,952 +0,0 @@
#include "MainWindow.hpp"
#include "ui_mainwindow.h"
#include <iostream>
#include <QCloseEvent>
#include <QTimer>
#include <QInputDialog>
#include <QMessageBox>
#include "Editor.hpp"
#include "ColoredTabWidget.hpp"
#include "AddPropertyDialog.hpp"
sh::MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
, mRequestShowWindow(false)
, mRequestExit(false)
, mIgnoreGlobalSettingChange(false)
, mIgnoreConfigurationChange(false)
, mIgnoreMaterialChange(false)
, mIgnoreMaterialPropertyChange(false)
{
ui->setupUi(this);
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(onIdle()));
timer->start(50);
QList<int> sizes;
sizes << 250;
sizes << 550;
ui->splitter->setSizes(sizes);
mMaterialModel = new QStringListModel(this);
mMaterialProxyModel = new QSortFilterProxyModel(this);
mMaterialProxyModel->setSourceModel(mMaterialModel);
mMaterialProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
mMaterialProxyModel->setDynamicSortFilter(true);
mMaterialProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
ui->materialList->setModel(mMaterialProxyModel);
ui->materialList->setSelectionMode(QAbstractItemView::SingleSelection);
ui->materialList->setEditTriggers(QAbstractItemView::NoEditTriggers);
ui->materialList->setAlternatingRowColors(true);
connect(ui->materialList->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
this, SLOT(onMaterialSelectionChanged(QModelIndex,QModelIndex)));
mMaterialPropertyModel = new QStandardItemModel(0, 2, this);
mMaterialPropertyModel->setHorizontalHeaderItem(0, new QStandardItem(QString("Name")));
mMaterialPropertyModel->setHorizontalHeaderItem(1, new QStandardItem(QString("Value")));
connect(mMaterialPropertyModel, SIGNAL(itemChanged(QStandardItem*)),
this, SLOT(onMaterialPropertyChanged(QStandardItem*)));
mMaterialSortModel = new PropertySortModel(this);
mMaterialSortModel->setSourceModel(mMaterialPropertyModel);
mMaterialSortModel->setDynamicSortFilter(true);
mMaterialSortModel->setSortCaseSensitivity(Qt::CaseInsensitive);
ui->materialView->setModel(mMaterialSortModel);
ui->materialView->setContextMenuPolicy(Qt::CustomContextMenu);
ui->materialView->setAlternatingRowColors(true);
ui->materialView->setSortingEnabled(true);
connect(ui->materialView, SIGNAL(customContextMenuRequested(QPoint)),
this, SLOT(onContextMenuRequested(QPoint)));
mGlobalSettingsModel = new QStandardItemModel(0, 2, this);
mGlobalSettingsModel->setHorizontalHeaderItem(0, new QStandardItem(QString("Name")));
mGlobalSettingsModel->setHorizontalHeaderItem(1, new QStandardItem(QString("Value")));
connect(mGlobalSettingsModel, SIGNAL(itemChanged(QStandardItem*)),
this, SLOT(onGlobalSettingChanged(QStandardItem*)));
ui->globalSettingsView->setModel(mGlobalSettingsModel);
ui->globalSettingsView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
ui->globalSettingsView->verticalHeader()->hide();
ui->globalSettingsView->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
ui->globalSettingsView->setSelectionMode(QAbstractItemView::SingleSelection);
ui->configurationList->setSelectionMode(QAbstractItemView::SingleSelection);
ui->configurationList->setEditTriggers(QAbstractItemView::NoEditTriggers);
connect(ui->configurationList, SIGNAL(currentTextChanged(QString)),
this, SLOT(onConfigurationSelectionChanged(QString)));
mConfigurationModel = new QStandardItemModel(0, 2, this);
mConfigurationModel->setHorizontalHeaderItem(0, new QStandardItem(QString("Name")));
mConfigurationModel->setHorizontalHeaderItem(1, new QStandardItem(QString("Value")));
connect(mConfigurationModel, SIGNAL(itemChanged(QStandardItem*)),
this, SLOT(onConfigurationChanged(QStandardItem*)));
ui->configurationView->setModel(mConfigurationModel);
ui->configurationView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
ui->configurationView->verticalHeader()->hide();
ui->configurationView->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
ui->configurationView->setSelectionMode(QAbstractItemView::SingleSelection);
}
sh::MainWindow::~MainWindow()
{
delete ui;
}
void sh::MainWindow::closeEvent(QCloseEvent *event)
{
this->hide();
event->ignore();
}
void sh::MainWindow::onIdle()
{
if (mRequestShowWindow)
{
mRequestShowWindow = false;
show();
}
if (mRequestExit)
{
QApplication::exit();
return;
}
boost::mutex::scoped_lock lock(mSync->mUpdateMutex);
mIgnoreMaterialChange = true;
QString selected;
QModelIndex selectedIndex = ui->materialList->selectionModel()->currentIndex();
if (selectedIndex.isValid())
selected = mMaterialModel->data(selectedIndex, Qt::DisplayRole).toString();
QStringList list;
for (std::vector<std::string>::const_iterator it = mState.mMaterialList.begin(); it != mState.mMaterialList.end(); ++it)
{
list.push_back(QString::fromStdString(*it));
}
if (mMaterialModel->stringList() != list)
{
mMaterialModel->setStringList(list);
// quick hack to keep our selection when the model has changed
if (!selected.isEmpty())
for (int i=0; i<mMaterialModel->rowCount(); ++i)
{
const QModelIndex& index = mMaterialModel->index(i,0);
if (mMaterialModel->data(index, Qt::DisplayRole).toString() == selected)
{
ui->materialList->setCurrentIndex(index);
break;
}
}
}
mIgnoreMaterialChange = false;
mIgnoreGlobalSettingChange = true;
for (std::map<std::string, std::string>::const_iterator it = mState.mGlobalSettingsMap.begin();
it != mState.mGlobalSettingsMap.end(); ++it)
{
QList<QStandardItem *> list = mGlobalSettingsModel->findItems(QString::fromStdString(it->first));
if (!list.empty()) // item was already there
{
// if it changed, set the value column
if (mGlobalSettingsModel->data(mGlobalSettingsModel->index(list.front()->row(), 1)).toString()
!= QString::fromStdString(it->second))
{
mGlobalSettingsModel->setItem(list.front()->row(), 1, new QStandardItem(QString::fromStdString(it->second)));
}
}
else // item wasn't there; insert new row
{
QList<QStandardItem*> toAdd;
QStandardItem* name = new QStandardItem(QString::fromStdString(it->first));
name->setFlags(name->flags() &= ~Qt::ItemIsEditable);
QStandardItem* value = new QStandardItem(QString::fromStdString(it->second));
toAdd.push_back(name);
toAdd.push_back(value);
mGlobalSettingsModel->appendRow(toAdd);
}
}
mIgnoreGlobalSettingChange = false;
mIgnoreConfigurationChange = true;
QList<QListWidgetItem*> selected_ = ui->configurationList->selectedItems();
QString selectedStr;
if (selected_.size())
selectedStr = selected_.front()->text();
ui->configurationList->clear();
for (std::vector<std::string>::const_iterator it = mState.mConfigurationList.begin(); it != mState.mConfigurationList.end(); ++it)
ui->configurationList->addItem(QString::fromStdString(*it));
if (!selectedStr.isEmpty())
for (int i=0; i<ui->configurationList->count(); ++i)
{
if (ui->configurationList->item(i)->text() == selectedStr)
{
ui->configurationList->setCurrentItem(ui->configurationList->item(i), QItemSelectionModel::ClearAndSelect);
}
}
mIgnoreConfigurationChange = false;
if (!mState.mErrors.empty())
{
ui->errorLog->append(QString::fromStdString(mState.mErrors));
mState.mErrors = "";
QColor color = ui->tabWidget->palette().color(QPalette::Normal, QPalette::Link);
ui->tabWidget->tabBar()->setTabTextColor(3, color);
}
// process query results
boost::mutex::scoped_lock lock2(mSync->mQueryMutex);
for (std::vector<Query*>::iterator it = mQueries.begin(); it != mQueries.end();)
{
if ((*it)->mDone)
{
if (typeid(**it) == typeid(ConfigurationQuery))
buildConfigurationModel(static_cast<ConfigurationQuery*>(*it));
else if (typeid(**it) == typeid(MaterialQuery))
buildMaterialModel(static_cast<MaterialQuery*>(*it));
else if (typeid(**it) == typeid(MaterialPropertyQuery))
{
MaterialPropertyQuery* q = static_cast<MaterialPropertyQuery*>(*it);
mIgnoreMaterialPropertyChange = true;
if (getSelectedMaterial().toStdString() == q->mName)
{
for (int i=0; i<mMaterialPropertyModel->rowCount(); ++i)
{
if (mMaterialPropertyModel->item(i,0)->text() == QString::fromStdString(q->mPropertyName))
{
mMaterialPropertyModel->item(i,1)->setText(QString::fromStdString(q->mValue));
if (mMaterialPropertyModel->item(i,1)->isCheckable())
mMaterialPropertyModel->item(i,1)->setCheckState ((q->mValue == "true")
? Qt::Checked : Qt::Unchecked);
}
}
}
mIgnoreMaterialPropertyChange = false;
}
delete *it;
it = mQueries.erase(it);
}
else
++it;
}
}
void sh::MainWindow::onMaterialSelectionChanged (const QModelIndex & current, const QModelIndex & previous)
{
if (mIgnoreMaterialChange)
return;
QString name = getSelectedMaterial();
if (!name.isEmpty())
requestQuery(new sh::MaterialQuery(name.toStdString()));
}
QString sh::MainWindow::getSelectedMaterial()
{
QModelIndex selectedIndex = ui->materialList->selectionModel()->currentIndex();
if (!selectedIndex.isValid())
return QString("");
return mMaterialProxyModel->data(selectedIndex, Qt::DisplayRole).toString();
}
void sh::MainWindow::onConfigurationSelectionChanged (const QString& current)
{
if (mIgnoreConfigurationChange)
return;
requestQuery(new sh::ConfigurationQuery(current.toStdString()));
}
void sh::MainWindow::onGlobalSettingChanged(QStandardItem *item)
{
if (mIgnoreGlobalSettingChange)
return; // we are only interested in changes by the user, not by the backend.
std::string name = mGlobalSettingsModel->data(mGlobalSettingsModel->index(item->row(), 0)).toString().toStdString();
std::string value = mGlobalSettingsModel->data(mGlobalSettingsModel->index(item->row(), 1)).toString().toStdString();
queueAction(new sh::ActionChangeGlobalSetting(name, value));
}
void sh::MainWindow::onConfigurationChanged (QStandardItem* item)
{
QList<QListWidgetItem*> items = ui->configurationList->selectedItems();
if (items.size())
{
std::string name = items.front()->text().toStdString();
std::string key = mConfigurationModel->data(mConfigurationModel->index(item->row(), 0)).toString().toStdString();
std::string value = mConfigurationModel->data(mConfigurationModel->index(item->row(), 1)).toString().toStdString();
queueAction(new sh::ActionChangeConfiguration(name, key, value));
requestQuery(new sh::ConfigurationQuery(name));
}
}
void sh::MainWindow::on_lineEdit_textEdited(const QString &arg1)
{
mMaterialProxyModel->setFilterFixedString(arg1);
}
void sh::MainWindow::on_actionSave_triggered()
{
queueAction (new sh::ActionSaveAll());
}
void sh::MainWindow::on_actionNewMaterial_triggered()
{
}
void sh::MainWindow::on_actionDeleteMaterial_triggered()
{
QModelIndex selectedIndex = ui->materialList->selectionModel()->currentIndex();
QString name = mMaterialProxyModel->data(selectedIndex, Qt::DisplayRole).toString();
queueAction (new sh::ActionDeleteMaterial(name.toStdString()));
}
void sh::MainWindow::queueAction(Action* action)
{
boost::mutex::scoped_lock lock(mSync->mActionMutex);
mActionQueue.push(action);
}
void sh::MainWindow::requestQuery(Query *query)
{
boost::mutex::scoped_lock lock(mSync->mActionMutex);
mQueries.push_back(query);
}
void sh::MainWindow::on_actionQuit_triggered()
{
hide();
}
void sh::MainWindow::on_actionNewConfiguration_triggered()
{
QInputDialog dialog(this);
QString text = QInputDialog::getText(this, tr("New Configuration"),
tr("Configuration name:"));
if (!text.isEmpty())
{
queueAction(new ActionCreateConfiguration(text.toStdString()));
}
}
void sh::MainWindow::on_actionDeleteConfiguration_triggered()
{
QList<QListWidgetItem*> items = ui->configurationList->selectedItems();
if (items.size())
queueAction(new ActionDeleteConfiguration(items.front()->text().toStdString()));
}
void sh::MainWindow::on_actionDeleteConfigurationProperty_triggered()
{
QList<QListWidgetItem*> items = ui->configurationList->selectedItems();
if (items.empty())
return;
std::string configurationName = items.front()->text().toStdString();
QModelIndex current = ui->configurationView->currentIndex();
if (!current.isValid())
return;
std::string propertyName = mConfigurationModel->data(mConfigurationModel->index(current.row(), 0)).toString().toStdString();
queueAction(new sh::ActionDeleteConfigurationProperty(configurationName, propertyName));
requestQuery(new sh::ConfigurationQuery(configurationName));
}
void sh::MainWindow::on_actionCloneMaterial_triggered()
{
QModelIndex selectedIndex = ui->materialList->selectionModel()->currentIndex();
QString name = mMaterialProxyModel->data(selectedIndex, Qt::DisplayRole).toString();
if (name.isEmpty())
return;
QInputDialog dialog(this);
QString text = QInputDialog::getText(this, tr("Clone material"),
tr("Name:"));
if (!text.isEmpty())
{
queueAction(new ActionCloneMaterial(name.toStdString(), text.toStdString()));
}
}
void sh::MainWindow::onContextMenuRequested(const QPoint &point)
{
QPoint globalPos = ui->materialView->viewport()->mapToGlobal(point);
QMenu menu;
QList <QAction*> actions;
actions.push_back(ui->actionNewProperty);
actions.push_back(ui->actionDeleteProperty);
actions.push_back(ui->actionCreatePass);
actions.push_back(ui->actionCreateTextureUnit);
menu.addActions(actions);
menu.exec(globalPos);
}
void sh::MainWindow::getContext(QModelIndex index, int* passIndex, int* textureIndex, bool* isInPass, bool* isInTextureUnit)
{
if (passIndex)
{
*passIndex = 0;
if (isInPass)
*isInPass = false;
QModelIndex passModelIndex = index;
// go up until we find the pass item.
while (getPropertyKey(passModelIndex) != "pass" && passModelIndex.isValid())
passModelIndex = passModelIndex.parent();
if (passModelIndex.isValid())
{
if (passModelIndex.column() != 0)
passModelIndex = passModelIndex.parent().child(passModelIndex.row(), 0);
for (int i=0; i<mMaterialPropertyModel->rowCount(); ++i)
{
if (mMaterialPropertyModel->data(mMaterialPropertyModel->index(i, 0)).toString() == QString("pass"))
{
if (mMaterialPropertyModel->index(i, 0) == passModelIndex)
{
if (isInPass)
*isInPass = true;
break;
}
++(*passIndex);
}
}
}
}
if (textureIndex)
{
*textureIndex = 0;
if (isInTextureUnit)
*isInTextureUnit = false;
QModelIndex texModelIndex = index;
// go up until we find the texture_unit item.
while (getPropertyKey(texModelIndex) != "texture_unit" && texModelIndex.isValid())
texModelIndex = texModelIndex.parent();
if (texModelIndex.isValid())
{
if (texModelIndex.column() != 0)
texModelIndex = texModelIndex.parent().child(texModelIndex.row(), 0);
for (int i=0; i<mMaterialPropertyModel->rowCount(texModelIndex.parent()); ++i)
{
if (texModelIndex.parent().child(i, 0).data().toString() == QString("texture_unit"))
{
if (texModelIndex.parent().child(i, 0) == texModelIndex)
{
if (isInTextureUnit)
*isInTextureUnit = true;
break;
}
++(*textureIndex);
}
}
}
}
}
std::string sh::MainWindow::getPropertyKey(QModelIndex index)
{
if (!index.parent().isValid())
return mMaterialPropertyModel->data(mMaterialPropertyModel->index(index.row(), 0)).toString().toStdString();
else
return index.parent().child(index.row(), 0).data().toString().toStdString();
}
std::string sh::MainWindow::getPropertyValue(QModelIndex index)
{
if (!index.parent().isValid())
return mMaterialPropertyModel->data(mMaterialPropertyModel->index(index.row(), 1)).toString().toStdString();
else
return index.parent().child(index.row(), 1).data().toString().toStdString();
}
void sh::MainWindow::onMaterialPropertyChanged(QStandardItem *item)
{
if (mIgnoreMaterialPropertyChange)
return;
QString material = getSelectedMaterial();
if (material.isEmpty())
return;
// handle checkboxes being checked/unchecked
std::string value = getPropertyValue(item->index());
if (item->data(Qt::UserRole).toInt() == MaterialProperty::Boolean)
{
if (item->checkState() == Qt::Checked && value != "true")
value = "true";
else if (item->checkState() == Qt::Unchecked && value == "true")
value = "false";
item->setText(QString::fromStdString(value));
}
// handle inherited properties being changed, i.e. overridden by the current (derived) material
if (item->data(Qt::UserRole+1).toInt() == MaterialProperty::Inherited_Unchanged)
{
QColor normalColor = ui->materialView->palette().color(QPalette::Normal, QPalette::WindowText);
mIgnoreMaterialPropertyChange = true;
mMaterialPropertyModel->item(item->index().row(), 0)
->setData(QVariant(MaterialProperty::Inherited_Changed), Qt::UserRole+1);
mMaterialPropertyModel->item(item->index().row(), 0)
->setData(normalColor, Qt::ForegroundRole);
mMaterialPropertyModel->item(item->index().row(), 1)
->setData(QVariant(MaterialProperty::Inherited_Changed), Qt::UserRole+1);
mMaterialPropertyModel->item(item->index().row(), 1)
->setData(normalColor, Qt::ForegroundRole);
mIgnoreMaterialPropertyChange = false;
ui->materialView->scrollTo(mMaterialSortModel->mapFromSource(item->index()));
}
if (!item->index().parent().isValid())
{
// top level material property
queueAction(new ActionSetMaterialProperty(
material.toStdString(), getPropertyKey(item->index()), value));
}
else if (getPropertyKey(item->index()) == "texture_unit")
{
// texture unit name changed
int passIndex, textureIndex;
getContext(item->index(), &passIndex, &textureIndex);
std::cout << "passIndex " << passIndex << " " << textureIndex << std::endl;
queueAction(new ActionChangeTextureUnitName(
material.toStdString(), passIndex, textureIndex, value));
}
else if (item->index().parent().data().toString() == "pass")
{
// pass property
int passIndex;
getContext(item->index(), &passIndex, NULL);
/// \todo if shaders are changed, check that the material provides all properties needed by the shader
queueAction(new ActionSetPassProperty(
material.toStdString(), passIndex, getPropertyKey(item->index()), value));
}
else if (item->index().parent().data().toString() == "shader_properties")
{
// shader property
int passIndex;
getContext(item->index(), &passIndex, NULL);
queueAction(new ActionSetShaderProperty(
material.toStdString(), passIndex, getPropertyKey(item->index()), value));
}
else if (item->index().parent().data().toString() == "texture_unit")
{
// texture property
int passIndex, textureIndex;
getContext(item->index(), &passIndex, &textureIndex);
queueAction(new ActionSetTextureProperty(
material.toStdString(), passIndex, textureIndex, getPropertyKey(item->index()), value));
}
}
void sh::MainWindow::buildMaterialModel(MaterialQuery *data)
{
mMaterialPropertyModel->clear();
mMaterialPropertyModel->setHorizontalHeaderItem(0, new QStandardItem(QString("Name")));
mMaterialPropertyModel->setHorizontalHeaderItem(1, new QStandardItem(QString("Value")));
for (std::map<std::string, MaterialProperty>::const_iterator it = data->mProperties.begin();
it != data->mProperties.end(); ++it)
{
addProperty(mMaterialPropertyModel->invisibleRootItem(), it->first, it->second);
}
for (std::vector<PassInfo>::iterator it = data->mPasses.begin();
it != data->mPasses.end(); ++it)
{
QStandardItem* passItem = new QStandardItem (QString("pass"));
passItem->setFlags(passItem->flags() &= ~Qt::ItemIsEditable);
passItem->setData(QVariant(static_cast<int>(MaterialProperty::Object)), Qt::UserRole);
if (it->mShaderProperties.size())
{
QStandardItem* shaderPropertiesItem = new QStandardItem (QString("shader_properties"));
shaderPropertiesItem->setFlags(shaderPropertiesItem->flags() &= ~Qt::ItemIsEditable);
shaderPropertiesItem->setData(QVariant(static_cast<int>(MaterialProperty::Object)), Qt::UserRole);
for (std::map<std::string, MaterialProperty>::iterator pit = it->mShaderProperties.begin();
pit != it->mShaderProperties.end(); ++pit)
{
addProperty(shaderPropertiesItem, pit->first, pit->second);
}
passItem->appendRow(shaderPropertiesItem);
}
for (std::map<std::string, MaterialProperty>::iterator pit = it->mProperties.begin();
pit != it->mProperties.end(); ++pit)
{
addProperty(passItem, pit->first, pit->second);
}
for (std::vector<TextureUnitInfo>::iterator tIt = it->mTextureUnits.begin();
tIt != it->mTextureUnits.end(); ++tIt)
{
QStandardItem* unitItem = new QStandardItem (QString("texture_unit"));
unitItem->setFlags(unitItem->flags() &= ~Qt::ItemIsEditable);
unitItem->setData(QVariant(static_cast<int>(MaterialProperty::Object)), Qt::UserRole);
QStandardItem* nameItem = new QStandardItem (QString::fromStdString(tIt->mName));
nameItem->setData(QVariant(static_cast<int>(MaterialProperty::Object)), Qt::UserRole);
QList<QStandardItem*> texUnit;
texUnit << unitItem << nameItem;
for (std::map<std::string, MaterialProperty>::iterator pit = tIt->mProperties.begin();
pit != tIt->mProperties.end(); ++pit)
{
addProperty(unitItem, pit->first, pit->second);
}
passItem->appendRow(texUnit);
}
QList<QStandardItem*> toAdd;
toAdd << passItem;
toAdd << new QStandardItem(QString(""));
mMaterialPropertyModel->appendRow(toAdd);
}
ui->materialView->expandAll();
ui->materialView->resizeColumnToContents(0);
ui->materialView->resizeColumnToContents(1);
}
void sh::MainWindow::addProperty(QStandardItem *parent, const std::string &key, MaterialProperty value, bool scrollTo)
{
QList<QStandardItem*> toAdd;
QStandardItem* keyItem = new QStandardItem(QString::fromStdString(key));
keyItem->setFlags(keyItem->flags() &= ~Qt::ItemIsEditable);
keyItem->setData(QVariant(value.mType), Qt::UserRole);
keyItem->setData(QVariant(value.mSource), Qt::UserRole+1);
toAdd.push_back(keyItem);
QStandardItem* valueItem = NULL;
if (value.mSource != MaterialProperty::None)
{
valueItem = new QStandardItem(QString::fromStdString(value.mValue));
valueItem->setData(QVariant(value.mType), Qt::UserRole);
valueItem->setData(QVariant(value.mSource), Qt::UserRole+1);
toAdd.push_back(valueItem);
}
if (value.mSource == MaterialProperty::Inherited_Unchanged)
{
QColor color = ui->configurationView->palette().color(QPalette::Disabled, QPalette::WindowText);
keyItem->setData(color, Qt::ForegroundRole);
if (valueItem)
valueItem->setData(color, Qt::ForegroundRole);
}
if (value.mType == MaterialProperty::Boolean && valueItem)
{
valueItem->setCheckable(true);
valueItem->setCheckState((value.mValue == "true") ? Qt::Checked : Qt::Unchecked);
}
parent->appendRow(toAdd);
if (scrollTo)
ui->materialView->scrollTo(mMaterialSortModel->mapFromSource(keyItem->index()));
}
void sh::MainWindow::buildConfigurationModel(ConfigurationQuery *data)
{
while (mConfigurationModel->rowCount())
mConfigurationModel->removeRow(0);
for (std::map<std::string, std::string>::iterator it = data->mProperties.begin();
it != data->mProperties.end(); ++it)
{
QList<QStandardItem*> toAdd;
QStandardItem* name = new QStandardItem(QString::fromStdString(it->first));
name->setFlags(name->flags() &= ~Qt::ItemIsEditable);
QStandardItem* value = new QStandardItem(QString::fromStdString(it->second));
toAdd.push_back(name);
toAdd.push_back(value);
mConfigurationModel->appendRow(toAdd);
}
// add items that are in global settings, but not in this configuration (with a "inactive" color)
for (std::map<std::string, std::string>::const_iterator it = mState.mGlobalSettingsMap.begin();
it != mState.mGlobalSettingsMap.end(); ++it)
{
if (data->mProperties.find(it->first) == data->mProperties.end())
{
QColor color = ui->configurationView->palette().color(QPalette::Disabled, QPalette::WindowText);
QList<QStandardItem*> toAdd;
QStandardItem* name = new QStandardItem(QString::fromStdString(it->first));
name->setFlags(name->flags() &= ~Qt::ItemIsEditable);
name->setData(color, Qt::ForegroundRole);
QStandardItem* value = new QStandardItem(QString::fromStdString(it->second));
value->setData(color, Qt::ForegroundRole);
toAdd.push_back(name);
toAdd.push_back(value);
mConfigurationModel->appendRow(toAdd);
}
}
}
void sh::MainWindow::on_actionCreatePass_triggered()
{
QString material = getSelectedMaterial();
if (!material.isEmpty())
{
addProperty(mMaterialPropertyModel->invisibleRootItem(),
"pass", MaterialProperty("", MaterialProperty::Object, MaterialProperty::None), true);
queueAction (new ActionCreatePass(material.toStdString()));
}
}
void sh::MainWindow::on_actionDeleteProperty_triggered()
{
QModelIndex selectedIndex = mMaterialSortModel->mapToSource(ui->materialView->selectionModel()->currentIndex());
QString material = getSelectedMaterial();
if (material.isEmpty())
return;
mIgnoreMaterialPropertyChange = true;
if (getPropertyKey(selectedIndex) == "pass")
{
// delete whole pass
int passIndex;
getContext(selectedIndex, &passIndex, NULL);
if (passIndex == 0)
{
QMessageBox msgBox;
msgBox.setText("The first pass can not be deleted.");
msgBox.exec();
}
else
{
queueAction(new ActionDeletePass(material.toStdString(), passIndex));
mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent());
}
}
else if (getPropertyKey(selectedIndex) == "texture_unit")
{
// delete whole texture unit
int passIndex, textureIndex;
getContext(selectedIndex, &passIndex, &textureIndex);
queueAction(new ActionDeleteTextureUnit(material.toStdString(), passIndex, textureIndex));
mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent());
}
else if (!selectedIndex.parent().isValid())
{
// top level material property
MaterialProperty::Source source = static_cast<MaterialProperty::Source>(
mMaterialPropertyModel->itemFromIndex(selectedIndex)->data(Qt::UserRole+1).toInt());
if (source == MaterialProperty::Inherited_Unchanged)
{
QMessageBox msgBox;
msgBox.setText("Inherited properties can not be deleted.");
msgBox.exec();
}
else
{
queueAction(new ActionDeleteMaterialProperty(
material.toStdString(), getPropertyKey(selectedIndex)));
std::cout << "source is " << source << std::endl;
if (source == MaterialProperty::Inherited_Changed)
{
QColor inactiveColor = ui->materialView->palette().color(QPalette::Disabled, QPalette::WindowText);
mMaterialPropertyModel->item(selectedIndex.row(), 0)
->setData(QVariant(MaterialProperty::Inherited_Unchanged), Qt::UserRole+1);
mMaterialPropertyModel->item(selectedIndex.row(), 0)
->setData(inactiveColor, Qt::ForegroundRole);
mMaterialPropertyModel->item(selectedIndex.row(), 1)
->setData(QVariant(MaterialProperty::Inherited_Unchanged), Qt::UserRole+1);
mMaterialPropertyModel->item(selectedIndex.row(), 1)
->setData(inactiveColor, Qt::ForegroundRole);
// make sure to update the property's value
requestQuery(new sh::MaterialPropertyQuery(material.toStdString(), getPropertyKey(selectedIndex)));
}
else
mMaterialPropertyModel->removeRow(selectedIndex.row());
}
}
else if (selectedIndex.parent().data().toString() == "pass")
{
// pass property
int passIndex;
getContext(selectedIndex, &passIndex, NULL);
queueAction(new ActionDeletePassProperty(
material.toStdString(), passIndex, getPropertyKey(selectedIndex)));
mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent());
}
else if (selectedIndex.parent().data().toString() == "shader_properties")
{
// shader property
int passIndex;
getContext(selectedIndex, &passIndex, NULL);
queueAction(new ActionDeleteShaderProperty(
material.toStdString(), passIndex, getPropertyKey(selectedIndex)));
mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent());
}
else if (selectedIndex.parent().data().toString() == "texture_unit")
{
// texture property
int passIndex, textureIndex;
getContext(selectedIndex, &passIndex, &textureIndex);
queueAction(new ActionDeleteTextureProperty(
material.toStdString(), passIndex, textureIndex, getPropertyKey(selectedIndex)));
mMaterialPropertyModel->removeRow(selectedIndex.row(), selectedIndex.parent());
}
mIgnoreMaterialPropertyChange = false;
}
void sh::MainWindow::on_actionNewProperty_triggered()
{
QModelIndex selectedIndex = mMaterialSortModel->mapToSource(ui->materialView->selectionModel()->currentIndex());
QString material = getSelectedMaterial();
if (material.isEmpty())
return;
AddPropertyDialog* dialog = new AddPropertyDialog(this);
dialog->exec();
QString propertyName = dialog->mName;
QString defaultValue = "";
/// \todo check if this property name exists already
if (!propertyName.isEmpty())
{
int passIndex, textureIndex;
bool isInPass, isInTextureUnit;
getContext(selectedIndex, &passIndex, &textureIndex, &isInPass, &isInTextureUnit);
QList<QStandardItem*> items;
QStandardItem* keyItem = new QStandardItem(propertyName);
keyItem->setFlags(keyItem->flags() &= ~Qt::ItemIsEditable);
items << keyItem;
items << new QStandardItem(defaultValue);
// figure out which item the new property should be a child of
QModelIndex parentIndex = selectedIndex;
if (selectedIndex.data(Qt::UserRole) != MaterialProperty::Object)
parentIndex = selectedIndex.parent();
QStandardItem* parentItem;
if (!parentIndex.isValid())
parentItem = mMaterialPropertyModel->invisibleRootItem();
else
parentItem = mMaterialPropertyModel->itemFromIndex(parentIndex);
if (isInTextureUnit)
{
queueAction(new ActionSetTextureProperty(
material.toStdString(), passIndex, textureIndex, propertyName.toStdString(), defaultValue.toStdString()));
}
else if (isInPass)
{
if (selectedIndex.parent().child(selectedIndex.row(),0).data().toString() == "shader_properties"
|| selectedIndex.parent().data().toString() == "shader_properties")
{
queueAction(new ActionSetShaderProperty(
material.toStdString(), passIndex, propertyName.toStdString(), defaultValue.toStdString()));
}
else
{
queueAction(new ActionSetPassProperty(
material.toStdString(), passIndex, propertyName.toStdString(), defaultValue.toStdString()));
}
}
else
{
queueAction(new ActionSetMaterialProperty(
material.toStdString(), propertyName.toStdString(), defaultValue.toStdString()));
}
addProperty(parentItem, propertyName.toStdString(),
MaterialProperty (defaultValue.toStdString(), MaterialProperty::Misc, MaterialProperty::Normal), true);
/// \todo scroll to newly added property
}
}
void sh::MainWindow::on_actionCreateTextureUnit_triggered()
{
QString material = getSelectedMaterial();
if (material.isEmpty())
return;
QInputDialog dialog(this);
QString text = QInputDialog::getText(this, tr("New texture unit"),
tr("Texture unit name (for referencing in shaders):"));
if (!text.isEmpty())
{
QModelIndex selectedIndex = mMaterialSortModel->mapToSource(ui->materialView->selectionModel()->currentIndex());
int passIndex;
getContext(selectedIndex, &passIndex, NULL);
queueAction(new ActionCreateTextureUnit(material.toStdString(), passIndex, text.toStdString()));
// add to model
int index = 0;
for (int i=0; i<mMaterialPropertyModel->rowCount(); ++i)
{
if (mMaterialPropertyModel->data(mMaterialPropertyModel->index(i, 0)).toString() == QString("pass"))
{
if (index == passIndex)
{
addProperty(mMaterialPropertyModel->itemFromIndex(mMaterialPropertyModel->index(i, 0)),
"texture_unit", MaterialProperty(text.toStdString(), MaterialProperty::Object), true);
break;
}
++index;
}
}
}
}
void sh::MainWindow::on_clearButton_clicked()
{
ui->errorLog->clear();
}
void sh::MainWindow::on_tabWidget_currentChanged(int index)
{
QColor color = ui->tabWidget->palette().color(QPalette::Normal, QPalette::WindowText);
if (index == 3)
ui->tabWidget->tabBar()->setTabTextColor(3, color);
}

@ -1,139 +0,0 @@
#ifndef SHINY_EDITOR_MAINWINDOW_HPP
#define SHINY_EDITOR_MAINWINDOW_HPP
#include <QMainWindow>
#include <QSortFilterProxyModel>
#include <QStandardItemModel>
#include <QStringListModel>
#include <queue>
#include "Actions.hpp"
#include "Query.hpp"
#include "PropertySortModel.hpp"
namespace Ui {
class MainWindow;
}
namespace sh
{
struct SynchronizationState;
/**
* @brief A snapshot of the material system's state. Lock the mUpdateMutex before accessing.
*/
struct MaterialSystemState
{
std::vector<std::string> mMaterialList;
std::map<std::string, std::string> mGlobalSettingsMap;
std::vector<std::string> mConfigurationList;
std::vector<std::string> mMaterialFiles;
std::vector<std::string> mConfigurationFiles;
std::vector<std::string> mShaderSets;
std::string mErrors;
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
// really should be an std::atomic
volatile bool mRequestShowWindow;
// dito
volatile bool mRequestExit;
SynchronizationState* mSync;
/// \todo Is there a better way to ignore manual model changes?
bool mIgnoreGlobalSettingChange;
bool mIgnoreConfigurationChange;
bool mIgnoreMaterialChange;
bool mIgnoreMaterialPropertyChange;
std::queue<Action*> mActionQueue;
std::vector<Query*> mQueries;
MaterialSystemState mState;
private:
Ui::MainWindow *ui;
// material tab
QStringListModel* mMaterialModel;
QSortFilterProxyModel* mMaterialProxyModel;
QStandardItemModel* mMaterialPropertyModel;
PropertySortModel* mMaterialSortModel;
// global settings tab
QStandardItemModel* mGlobalSettingsModel;
// configuration tab
QStandardItemModel* mConfigurationModel;
void queueAction(Action* action);
void requestQuery(Query* query);
void buildMaterialModel (MaterialQuery* data);
void buildConfigurationModel (ConfigurationQuery* data);
QString getSelectedMaterial();
/// get the context of an index in the material property model
void getContext(QModelIndex index, int* passIndex, int* textureIndex, bool* isInPass=NULL, bool* isInTextureUnit=NULL);
std::string getPropertyKey(QModelIndex index);
std::string getPropertyValue(QModelIndex index);
void addProperty (QStandardItem* parent, const std::string& key, MaterialProperty value, bool scrollTo=false);
protected:
void closeEvent(QCloseEvent *event);
public slots:
void onIdle();
void onMaterialSelectionChanged (const QModelIndex & current, const QModelIndex & previous);
void onConfigurationSelectionChanged (const QString& current);
void onGlobalSettingChanged (QStandardItem* item);
void onConfigurationChanged (QStandardItem* item);
void onMaterialPropertyChanged (QStandardItem* item);
void onContextMenuRequested(const QPoint& point);
private slots:
void on_lineEdit_textEdited(const QString &arg1);
void on_actionSave_triggered();
void on_actionNewMaterial_triggered();
void on_actionDeleteMaterial_triggered();
void on_actionQuit_triggered();
void on_actionNewConfiguration_triggered();
void on_actionDeleteConfiguration_triggered();
void on_actionDeleteConfigurationProperty_triggered();
void on_actionCloneMaterial_triggered();
void on_actionCreatePass_triggered();
void on_actionDeleteProperty_triggered();
void on_actionNewProperty_triggered();
void on_actionCreateTextureUnit_triggered();
void on_clearButton_clicked();
void on_tabWidget_currentChanged(int index);
};
}
#endif // MAINWINDOW_HPP

@ -1,14 +0,0 @@
#include "NewMaterialDialog.hpp"
#include "ui_newmaterialdialog.h"
NewMaterialDialog::NewMaterialDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::NewMaterialDialog)
{
ui->setupUi(this);
}
NewMaterialDialog::~NewMaterialDialog()
{
delete ui;
}

@ -1,22 +0,0 @@
#ifndef NEWMATERIALDIALOG_HPP
#define NEWMATERIALDIALOG_HPP
#include <QDialog>
namespace Ui {
class NewMaterialDialog;
}
class NewMaterialDialog : public QDialog
{
Q_OBJECT
public:
explicit NewMaterialDialog(QWidget *parent = 0);
~NewMaterialDialog();
private:
Ui::NewMaterialDialog *ui;
};
#endif // NEWMATERIALDIALOG_HPP

@ -1,35 +0,0 @@
#include "PropertySortModel.hpp"
#include "Query.hpp"
#include <iostream>
sh::PropertySortModel::PropertySortModel(QObject *parent)
: QSortFilterProxyModel(parent)
{
}
bool sh::PropertySortModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
if (left.data(Qt::UserRole+1).toInt() != 0 && right.data(Qt::UserRole+1).toInt() != 0)
{
int sourceL = left.data(Qt::UserRole+1).toInt();
int sourceR = right.data(Qt::UserRole+1).toInt();
if (sourceL > sourceR)
return true;
else if (sourceR > sourceL)
return false;
}
int typeL = left.data(Qt::UserRole).toInt();
int typeR = right.data(Qt::UserRole).toInt();
if (typeL > typeR)
return true;
else if (typeR > typeL)
return false;
QString nameL = left.data().toString();
QString nameR = right.data().toString();
return nameL > nameR;
}

@ -1,21 +0,0 @@
#ifndef SHINY_EDITOR_PROPERTYSORTMODEL_H
#define SHINY_EDITOR_PROPERTYSORTMODEL_H
#include <QSortFilterProxyModel>
namespace sh
{
class PropertySortModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
PropertySortModel(QObject* parent);
protected:
bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
};
}
#endif

@ -1,134 +0,0 @@
#include "Query.hpp"
#include "../Main/Factory.hpp"
namespace sh
{
void Query::execute()
{
executeImpl();
mDone = true;
}
ConfigurationQuery::ConfigurationQuery(const std::string &name)
: mName(name)
{
}
void ConfigurationQuery::executeImpl()
{
sh::Factory::getInstance().listConfigurationSettings(mName, mProperties);
}
void MaterialQuery::executeImpl()
{
sh::MaterialInstance* instance = sh::Factory::getInstance().getMaterialInstance(mName);
if (instance->getParent())
mParent = static_cast<sh::MaterialInstance*>(instance->getParent())->getName();
// add the inherited properties
sh::PropertySetGet* parent = instance;
std::vector<std::string> inheritedPropertiesVector;
while (parent->getParent())
{
parent = parent->getParent();
const sh::PropertyMap& parentProperties = parent->listProperties();
for (PropertyMap::const_iterator it = parentProperties.begin(); it != parentProperties.end(); ++it)
{
MaterialProperty::Source source = MaterialProperty::Inherited_Unchanged;
MaterialProperty::Type type = getType(it->first, parent->getProperty(it->first));
mProperties[it->first] = MaterialProperty (
retrieveValue<sh::StringValue>(parent->getProperty(it->first), NULL).get(),
type, source);
inheritedPropertiesVector.push_back(it->first);
}
}
// add our properties
const sh::PropertyMap& ourProperties = instance->listProperties();
for (PropertyMap::const_iterator it = ourProperties.begin(); it != ourProperties.end(); ++it)
{
MaterialProperty::Source source =
(std::find(inheritedPropertiesVector.begin(), inheritedPropertiesVector.end(), it->first)
!= inheritedPropertiesVector.end()) ?
MaterialProperty::Inherited_Changed : MaterialProperty::Normal;
MaterialProperty::Type type = getType(it->first, instance->getProperty(it->first));
mProperties[it->first] = MaterialProperty (
retrieveValue<sh::StringValue>(instance->getProperty(it->first), NULL).get(),
type, source);
}
std::vector<MaterialInstancePass>* passes = instance->getPasses();
for (std::vector<MaterialInstancePass>::iterator it = passes->begin(); it != passes->end(); ++it)
{
mPasses.push_back(PassInfo());
const sh::PropertyMap& passProperties = it->listProperties();
for (PropertyMap::const_iterator pit = passProperties.begin(); pit != passProperties.end(); ++pit)
{
PropertyValuePtr property = it->getProperty(pit->first);
MaterialProperty::Type type = getType(pit->first, property);
if (typeid(*property).name() == typeid(sh::LinkedValue).name())
mPasses.back().mProperties[pit->first] = MaterialProperty("$" + property->_getStringValue(), type);
else
mPasses.back().mProperties[pit->first] = MaterialProperty(
retrieveValue<sh::StringValue>(property, NULL).get(), type);
}
const sh::PropertyMap& shaderProperties = it->mShaderProperties.listProperties();
for (PropertyMap::const_iterator pit = shaderProperties.begin(); pit != shaderProperties.end(); ++pit)
{
PropertyValuePtr property = it->mShaderProperties.getProperty(pit->first);
MaterialProperty::Type type = getType(pit->first, property);
if (typeid(*property).name() == typeid(sh::LinkedValue).name())
mPasses.back().mShaderProperties[pit->first] = MaterialProperty("$" + property->_getStringValue(), type);
else
mPasses.back().mShaderProperties[pit->first] = MaterialProperty(
retrieveValue<sh::StringValue>(property, NULL).get(), type);
}
std::vector<MaterialInstanceTextureUnit>* texUnits = &it->mTexUnits;
for (std::vector<MaterialInstanceTextureUnit>::iterator tIt = texUnits->begin(); tIt != texUnits->end(); ++tIt)
{
mPasses.back().mTextureUnits.push_back(TextureUnitInfo());
mPasses.back().mTextureUnits.back().mName = tIt->getName();
const sh::PropertyMap& unitProperties = tIt->listProperties();
for (PropertyMap::const_iterator pit = unitProperties.begin(); pit != unitProperties.end(); ++pit)
{
PropertyValuePtr property = tIt->getProperty(pit->first);
MaterialProperty::Type type = getType(pit->first, property);
if (typeid(*property).name() == typeid(sh::LinkedValue).name())
mPasses.back().mTextureUnits.back().mProperties[pit->first] = MaterialProperty(
"$" + property->_getStringValue(), MaterialProperty::Linked);
else
mPasses.back().mTextureUnits.back().mProperties[pit->first] = MaterialProperty(
retrieveValue<sh::StringValue>(property, NULL).get(), type);
}
}
}
}
MaterialProperty::Type MaterialQuery::getType(const std::string &key, PropertyValuePtr value)
{
if (typeid(*value).name() == typeid(sh::LinkedValue).name())
return MaterialProperty::Linked;
if (key == "vertex_program" || key == "fragment_program")
return MaterialProperty::Shader;
std::string valueStr = retrieveValue<sh::StringValue>(value, NULL).get();
if (valueStr == "false" || valueStr == "true")
return MaterialProperty::Boolean;
}
void MaterialPropertyQuery::executeImpl()
{
sh::MaterialInstance* m = sh::Factory::getInstance().getMaterialInstance(mName);
mValue = retrieveValue<sh::StringValue>(m->getProperty(mPropertyName), m).get();
}
}

@ -1,121 +0,0 @@
#ifndef SH_QUERY_H
#define SH_QUERY_H
#include <string>
#include <map>
#include <vector>
#include "../Main/PropertyBase.hpp"
namespace sh
{
class Query
{
public:
Query()
: mDone(false) {}
virtual ~Query() {}
void execute();
bool mDone;
protected:
virtual void executeImpl() = 0;
};
class ConfigurationQuery : public Query
{
public:
ConfigurationQuery(const std::string& name);
std::map<std::string, std::string> mProperties;
protected:
std::string mName;
virtual void executeImpl();
};
struct MaterialProperty
{
enum Type
{
Texture,
Color,
Boolean,
Shader,
Misc,
Linked,
Object // child object, i.e. pass, texture unit, shader properties
};
enum Source
{
Normal,
Inherited_Changed,
Inherited_Unchanged,
None // there is no property source (e.g. a pass, which does not have a name)
};
MaterialProperty() {}
MaterialProperty (const std::string& value, Type type, Source source=Normal)
: mValue(value), mType(type), mSource(source) {}
std::string mValue;
Type mType;
Source mSource;
};
struct TextureUnitInfo
{
std::string mName;
std::map<std::string, MaterialProperty> mProperties;
};
struct PassInfo
{
std::map<std::string, MaterialProperty> mShaderProperties;
std::map<std::string, MaterialProperty> mProperties;
std::vector<TextureUnitInfo> mTextureUnits;
};
class MaterialQuery : public Query
{
public:
MaterialQuery(const std::string& name)
: mName(name) {}
std::string mParent;
std::vector<PassInfo> mPasses;
std::map<std::string, MaterialProperty> mProperties;
protected:
std::string mName;
virtual void executeImpl();
MaterialProperty::Type getType (const std::string& key, PropertyValuePtr value);
};
class MaterialPropertyQuery : public Query
{
public:
MaterialPropertyQuery(const std::string& name, const std::string& propertyName)
: mName(name), mPropertyName(propertyName)
{
}
std::string mValue;
std::string mName;
std::string mPropertyName;
protected:
virtual void executeImpl();
};
}
#endif

@ -1,118 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AddPropertyDialog</class>
<widget class="QDialog" name="AddPropertyDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>257</width>
<height>133</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QLineEdit" name="lineEdit"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Property name</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Editing widget</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="comboBox">
<item>
<property name="text">
<string>Checkbox</string>
</property>
</item>
<item>
<property name="text">
<string>Shader</string>
</property>
</item>
<item>
<property name="text">
<string>Color</string>
</property>
</item>
<item>
<property name="text">
<string>Texture</string>
</property>
</item>
<item>
<property name="text">
<string>Other</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>AddPropertyDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>AddPropertyDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

@ -1,420 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>647</width>
<height>512</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QHBoxLayout" name="verticalLayout">
<item>
<widget class="sh::ColoredTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<property name="accessibleName">
<string/>
</property>
<attribute name="title">
<string>Materials</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QWidget" name="verticalLayoutWidget">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLineEdit" name="lineEdit">
<property name="text">
<string/>
</property>
<property name="placeholderText">
<string>Search</string>
</property>
</widget>
</item>
<item>
<widget class="QListView" name="materialList">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QToolBar" name="toolBar1">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<addaction name="actionNewMaterial"/>
<addaction name="actionCloneMaterial"/>
<addaction name="actionDeleteMaterial"/>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="verticalLayoutWidget2">
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QTreeView" name="materialView">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QToolBar" name="toolBar4">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonIconOnly</enum>
</property>
<addaction name="actionNewProperty"/>
<addaction name="actionDeleteProperty"/>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab2">
<attribute name="title">
<string>Global settings</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QTableView" name="globalSettingsView"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Configurations</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QSplitter" name="splitter_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QWidget" name="layoutWidget">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QListWidget" name="configurationList"/>
</item>
<item>
<widget class="QToolBar" name="toolBar2">
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<addaction name="actionNewConfiguration"/>
<addaction name="actionDeleteConfiguration"/>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="layoutWidget2">
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QTableView" name="configurationView"/>
</item>
<item>
<widget class="QToolBar" name="toolBar2_2">
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<addaction name="actionDeleteConfigurationProperty"/>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_3">
<attribute name="title">
<string>Errors</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QTextEdit" name="errorLog">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clearButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Clear</string>
</property>
<property name="icon">
<iconset theme="edit-clear"/>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox"/>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>647</width>
<height>25</height>
</rect>
</property>
<property name="defaultUp">
<bool>false</bool>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<addaction name="actionSave"/>
<addaction name="actionQuit"/>
</widget>
<widget class="QMenu" name="menuMaterial">
<property name="title">
<string>Material</string>
</property>
<addaction name="actionNewMaterial"/>
<addaction name="actionCloneMaterial"/>
<addaction name="actionDeleteMaterial"/>
<addaction name="actionChange_parent"/>
</widget>
<widget class="QMenu" name="menuHistory">
<property name="title">
<string>History</string>
</property>
</widget>
<addaction name="menuFile"/>
<addaction name="menuMaterial"/>
<addaction name="menuHistory"/>
</widget>
<action name="actionQuit">
<property name="icon">
<iconset theme="application-exit">
<normaloff/>
</iconset>
</property>
<property name="text">
<string>Quit</string>
</property>
</action>
<action name="actionSave">
<property name="icon">
<iconset theme="document-save">
<normaloff/>
</iconset>
</property>
<property name="text">
<string>Save</string>
</property>
<property name="toolTip">
<string>Save all</string>
</property>
</action>
<action name="actionDeleteMaterial">
<property name="icon">
<iconset theme="edit-delete">
<normaloff/>
</iconset>
</property>
<property name="text">
<string>Delete</string>
</property>
<property name="toolTip">
<string>Delete selected material</string>
</property>
</action>
<action name="actionChange_parent">
<property name="text">
<string>Change parent...</string>
</property>
</action>
<action name="actionNewMaterial">
<property name="icon">
<iconset theme="document-new">
<normaloff/>
</iconset>
</property>
<property name="text">
<string>New</string>
</property>
<property name="toolTip">
<string>Create a new material</string>
</property>
</action>
<action name="actionCloneMaterial">
<property name="icon">
<iconset theme="edit-copy">
<normaloff/>
</iconset>
</property>
<property name="text">
<string>Clone</string>
</property>
<property name="toolTip">
<string>Clone selected material</string>
</property>
</action>
<action name="actionDeleteConfiguration">
<property name="icon">
<iconset theme="edit-delete">
<normaloff/>
</iconset>
</property>
<property name="text">
<string>Delete</string>
</property>
<property name="toolTip">
<string>Delete selected configuration</string>
</property>
<property name="shortcut">
<string>Del</string>
</property>
</action>
<action name="actionNewConfiguration">
<property name="icon">
<iconset theme="document-new">
<normaloff/>
</iconset>
</property>
<property name="text">
<string>New</string>
</property>
<property name="toolTip">
<string>Create a new configuration</string>
</property>
</action>
<action name="actionDeleteConfigurationProperty">
<property name="icon">
<iconset theme="edit-delete">
<normaloff/>
</iconset>
</property>
<property name="text">
<string>Delete</string>
</property>
<property name="toolTip">
<string>Delete property</string>
</property>
</action>
<action name="actionDeleteProperty">
<property name="icon">
<iconset theme="remove">
<normaloff/>
</iconset>
</property>
<property name="text">
<string>Delete</string>
</property>
<property name="toolTip">
<string>Delete item</string>
</property>
</action>
<action name="actionNewProperty">
<property name="icon">
<iconset theme="add">
<normaloff/>
</iconset>
</property>
<property name="text">
<string>New property</string>
</property>
</action>
<action name="actionCreatePass">
<property name="icon">
<iconset theme="edit-add">
<normaloff/>
</iconset>
</property>
<property name="text">
<string>Create pass</string>
</property>
</action>
<action name="actionCreateTextureUnit">
<property name="icon">
<iconset theme="edit-add">
<normaloff/>
</iconset>
</property>
<property name="text">
<string>Create texture unit</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>sh::ColoredTabWidget</class>
<extends>QTabWidget</extends>
<header>ColoredTabWidget.hpp</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

@ -1,98 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NewMaterialDialog</class>
<widget class="QDialog" name="NewMaterialDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>385</width>
<height>198</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Parent material</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineEdit_2"/>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEdit"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>File</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="comboBox"/>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>NewMaterialDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>NewMaterialDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

@ -1,174 +0,0 @@
#if SH_HLSL == 1 || SH_CG == 1
#define shTexture2D sampler2D
#define shTexture3D sampler3D
#define shSample(tex, coord) tex2D(tex, coord)
#define shCubicSample(tex, coord) texCUBE(tex, coord)
#define shLerp(a, b, t) lerp(a, b, t)
#define shSaturate(a) saturate(a)
#define shSampler2D(name) , uniform sampler2D name : register(s@shCounter(0)) @shUseSampler(name)
#define shSampler3D(name) , uniform sampler3D name : register(s@shCounter(0)) @shUseSampler(name)
#define shSamplerCube(name) , uniform samplerCUBE name : register(s@shCounter(0)) @shUseSampler(name)
#define shMatrixMult(m, v) mul(m, v)
#define shUniform(type, name) , uniform type name
#define shTangentInput(type) , in type tangent : TANGENT
#define shVertexInput(type, name) , in type name : TEXCOORD@shCounter(1)
#define shInput(type, name) , in type name : TEXCOORD@shCounter(1)
#define shOutput(type, name) , out type name : TEXCOORD@shCounter(2)
#define shNormalInput(type) , in type normal : NORMAL
#define shColourInput(type) , in type colour : COLOR
#ifdef SH_VERTEX_SHADER
#define shOutputPosition oPosition
#define shInputPosition iPosition
#define SH_BEGIN_PROGRAM \
void main( \
float4 iPosition : POSITION \
, out float4 oPosition : POSITION
#define SH_START_PROGRAM \
) \
#endif
#ifdef SH_FRAGMENT_SHADER
#define shOutputColour(num) oColor##num
#define shDeclareMrtOutput(num) , out float4 oColor##num : COLOR##num
#define SH_BEGIN_PROGRAM \
void main( \
out float4 oColor0 : COLOR
#define SH_START_PROGRAM \
) \
#endif
#endif
#if SH_GLSL == 1
@version 120
#define float2 vec2
#define float3 vec3
#define float4 vec4
#define int2 ivec2
#define int3 ivec3
#define int4 ivec4
#define shTexture2D sampler2D
#define shTexture3D sampler3D
#define shSample(tex, coord) texture2D(tex, coord)
#define shCubicSample(tex, coord) textureCube(tex, coord)
#define shLerp(a, b, t) mix(a, b, t)
#define shSaturate(a) clamp(a, 0.0, 1.0)
#define shUniform(type, name) uniform type name;
#define shSampler2D(name) uniform sampler2D name; @shUseSampler(name)
#define shSampler3D(name) uniform sampler3D name; @shUseSampler(name)
#define shSamplerCube(name) uniform samplerCube name; @shUseSampler(name)
#define shMatrixMult(m, v) (m * v)
#define shOutputPosition gl_Position
#define float4x4 mat4
#define float3x3 mat3
// GLSL 1.3
#if 0
// automatically recognized by ogre when the input name equals this
#define shInputPosition vertex
#define shOutputColour(num) oColor##num
#define shTangentInput(type) in type tangent;
#define shVertexInput(type, name) in type name;
#define shInput(type, name) in type name;
#define shOutput(type, name) out type name;
// automatically recognized by ogre when the input name equals this
#define shNormalInput(type) in type normal;
#define shColourInput(type) in type colour;
#ifdef SH_VERTEX_SHADER
#define SH_BEGIN_PROGRAM \
in float4 vertex;
#define SH_START_PROGRAM \
void main(void)
#endif
#ifdef SH_FRAGMENT_SHADER
#define shDeclareMrtOutput(num) out vec4 oColor##num;
#define SH_BEGIN_PROGRAM \
out float4 oColor0;
#define SH_START_PROGRAM \
void main(void)
#endif
#endif
// GLSL 1.2
#if 1
// automatically recognized by ogre when the input name equals this
#define shInputPosition vertex
#define shOutputColour(num) gl_FragData[num]
#define shTangentInput(type) attribute type tangent;
#define shVertexInput(type, name) attribute type name;
#define shInput(type, name) varying type name;
#define shOutput(type, name) varying type name;
// automatically recognized by ogre when the input name equals this
#define shNormalInput(type) attribute type normal;
#define shColourInput(type) attribute type colour;
#ifdef SH_VERTEX_SHADER
#define SH_BEGIN_PROGRAM \
attribute vec4 vertex;
#define SH_START_PROGRAM \
void main(void)
#endif
#ifdef SH_FRAGMENT_SHADER
#define shDeclareMrtOutput(num)
#define SH_BEGIN_PROGRAM
#define SH_START_PROGRAM \
void main(void)
#endif
#endif
#endif

@ -1,9 +0,0 @@
Copyright (c) 2012 <scrawl@baseoftrash.de>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

@ -1,817 +0,0 @@
#include "Factory.hpp"
#include <stdexcept>
#include <iostream>
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include <boost/lexical_cast.hpp>
#include "Platform.hpp"
#include "ScriptLoader.hpp"
#include "ShaderSet.hpp"
#include "MaterialInstanceTextureUnit.hpp"
namespace sh
{
Factory* Factory::sThis = 0;
const std::string Factory::mBinaryCacheName = "binaryCache";
Factory& Factory::getInstance()
{
assert (sThis);
return *sThis;
}
Factory* Factory::getInstancePtr()
{
return sThis;
}
Factory::Factory (Platform* platform)
: mPlatform(platform)
, mShadersEnabled(true)
, mShaderDebugOutputEnabled(false)
, mCurrentLanguage(Language_None)
, mListener(NULL)
, mCurrentConfiguration(NULL)
, mCurrentLodConfiguration(NULL)
, mReadMicrocodeCache(false)
, mWriteMicrocodeCache(false)
, mReadSourceCache(false)
, mWriteSourceCache(false)
{
assert (!sThis);
sThis = this;
mPlatform->setFactory(this);
}
void Factory::loadAllFiles()
{
assert(mCurrentLanguage != Language_None);
try
{
if (boost::filesystem::exists (mPlatform->getCacheFolder () + "/lastModified.txt"))
{
std::ifstream file;
file.open(std::string(mPlatform->getCacheFolder () + "/lastModified.txt").c_str());
std::string line;
while (getline(file, line))
{
std::string sourceFile = line;
if (!getline(file, line))
assert(0);
int modified = boost::lexical_cast<int>(line);
mShadersLastModified[sourceFile] = modified;
}
}
}
catch (std::exception& e)
{
std::cerr << "Failed to load shader modification index: " << e.what() << std::endl;
mShadersLastModified.clear();
}
// load configurations
{
ScriptLoader shaderSetLoader(".configuration");
ScriptLoader::loadAllFiles (&shaderSetLoader, mPlatform->getBasePath());
std::map <std::string, ScriptNode*> nodes = shaderSetLoader.getAllConfigScripts();
for (std::map <std::string, ScriptNode*>::const_iterator it = nodes.begin();
it != nodes.end(); ++it)
{
if (!(it->second->getName() == "configuration"))
{
std::cerr << "sh::Factory: Warning: Unsupported root node type \"" << it->second->getName() << "\" for file type .configuration" << std::endl;
break;
}
Configuration newConfiguration;
newConfiguration.setParent(&mGlobalSettings);
newConfiguration.setSourceFile (it->second->mFileName);
std::vector<ScriptNode*> props = it->second->getChildren();
for (std::vector<ScriptNode*>::const_iterator propIt = props.begin(); propIt != props.end(); ++propIt)
{
std::string name = (*propIt)->getName();
std::string val = (*propIt)->getValue();
newConfiguration.setProperty (name, makeProperty(val));
}
mConfigurations[it->first] = newConfiguration;
}
}
// load lod configurations
{
ScriptLoader lodLoader(".lod");
ScriptLoader::loadAllFiles (&lodLoader, mPlatform->getBasePath());
std::map <std::string, ScriptNode*> nodes = lodLoader.getAllConfigScripts();
for (std::map <std::string, ScriptNode*>::const_iterator it = nodes.begin();
it != nodes.end(); ++it)
{
if (!(it->second->getName() == "lod_configuration"))
{
std::cerr << "sh::Factory: Warning: Unsupported root node type \"" << it->second->getName() << "\" for file type .lod" << std::endl;
break;
}
if (it->first == "0")
{
throw std::runtime_error("lod level 0 (max lod) can't have a configuration");
}
PropertySetGet newLod;
std::vector<ScriptNode*> props = it->second->getChildren();
for (std::vector<ScriptNode*>::const_iterator propIt = props.begin(); propIt != props.end(); ++propIt)
{
std::string name = (*propIt)->getName();
std::string val = (*propIt)->getValue();
newLod.setProperty (name, makeProperty(val));
}
mLodConfigurations[boost::lexical_cast<int>(it->first)] = newLod;
}
}
// load shader sets
bool removeBinaryCache = reloadShaders();
// load materials
{
ScriptLoader materialLoader(".mat");
ScriptLoader::loadAllFiles (&materialLoader, mPlatform->getBasePath());
std::map <std::string, ScriptNode*> nodes = materialLoader.getAllConfigScripts();
for (std::map <std::string, ScriptNode*>::const_iterator it = nodes.begin();
it != nodes.end(); ++it)
{
if (!(it->second->getName() == "material"))
{
std::cerr << "sh::Factory: Warning: Unsupported root node type \"" << it->second->getName() << "\" for file type .mat" << std::endl;
break;
}
MaterialInstance newInstance(it->first, this);
newInstance.create(mPlatform);
if (!mShadersEnabled)
newInstance.setShadersEnabled (false);
newInstance.setSourceFile (it->second->mFileName);
std::vector<ScriptNode*> props = it->second->getChildren();
for (std::vector<ScriptNode*>::const_iterator propIt = props.begin(); propIt != props.end(); ++propIt)
{
std::string name = (*propIt)->getName();
std::string val = (*propIt)->getValue();
if (name == "pass")
{
MaterialInstancePass* newPass = newInstance.createPass();
std::vector<ScriptNode*> props2 = (*propIt)->getChildren();
for (std::vector<ScriptNode*>::const_iterator propIt2 = props2.begin(); propIt2 != props2.end(); ++propIt2)
{
std::string name2 = (*propIt2)->getName();
std::string val2 = (*propIt2)->getValue();
if (name2 == "shader_properties")
{
std::vector<ScriptNode*> shaderProps = (*propIt2)->getChildren();
for (std::vector<ScriptNode*>::const_iterator shaderPropIt = shaderProps.begin(); shaderPropIt != shaderProps.end(); ++shaderPropIt)
{
std::string val = (*shaderPropIt)->getValue();
newPass->mShaderProperties.setProperty((*shaderPropIt)->getName(), makeProperty(val));
}
}
else if (name2 == "texture_unit")
{
MaterialInstanceTextureUnit* newTex = newPass->createTextureUnit(val2);
std::vector<ScriptNode*> texProps = (*propIt2)->getChildren();
for (std::vector<ScriptNode*>::const_iterator texPropIt = texProps.begin(); texPropIt != texProps.end(); ++texPropIt)
{
std::string val = (*texPropIt)->getValue();
newTex->setProperty((*texPropIt)->getName(), makeProperty(val));
}
}
else
newPass->setProperty((*propIt2)->getName(), makeProperty(val2));
}
}
else if (name == "parent")
newInstance.setParentInstance(val);
else
newInstance.setProperty((*propIt)->getName(), makeProperty(val));
}
if (newInstance.hasProperty("create_configuration"))
{
std::string config = retrieveValue<StringValue>(newInstance.getProperty("create_configuration"), NULL).get();
newInstance.createForConfiguration (config, 0);
}
mMaterials.insert (std::make_pair(it->first, newInstance));
}
// now that all materials are loaded, replace the parent names with the actual pointers to parent
for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it)
{
std::string parent = it->second.getParentInstance();
if (parent != "")
{
if (mMaterials.find (it->second.getParentInstance()) == mMaterials.end())
throw std::runtime_error ("Unable to find parent for material instance \"" + it->first + "\"");
it->second.setParent(&mMaterials.find(parent)->second);
}
}
}
if (mPlatform->supportsShaderSerialization () && mReadMicrocodeCache && !removeBinaryCache)
{
std::string file = mPlatform->getCacheFolder () + "/" + mBinaryCacheName;
if (boost::filesystem::exists(file))
{
mPlatform->deserializeShaders (file);
}
}
}
Factory::~Factory ()
{
mShaderSets.clear();
if (mPlatform->supportsShaderSerialization () && mWriteMicrocodeCache)
{
std::string file = mPlatform->getCacheFolder () + "/" + mBinaryCacheName;
mPlatform->serializeShaders (file);
}
if (mReadSourceCache)
{
// save the last modified time of shader sources (as of when they were loaded)
std::ofstream file;
file.open(std::string(mPlatform->getCacheFolder () + "/lastModified.txt").c_str());
for (LastModifiedMap::const_iterator it = mShadersLastModifiedNew.begin(); it != mShadersLastModifiedNew.end(); ++it)
{
file << it->first << "\n" << it->second << std::endl;
}
file.close();
}
delete mPlatform;
sThis = 0;
}
MaterialInstance* Factory::searchInstance (const std::string& name)
{
MaterialMap::iterator it = mMaterials.find(name);
if (it != mMaterials.end())
return &(it->second);
else
return NULL;
}
MaterialInstance* Factory::findInstance (const std::string& name)
{
MaterialInstance* m = searchInstance(name);
assert (m);
return m;
}
MaterialInstance* Factory::requestMaterial (const std::string& name, const std::string& configuration, unsigned short lodIndex)
{
MaterialInstance* m = searchInstance (name);
if (configuration != "Default" && mConfigurations.find(configuration) == mConfigurations.end())
return NULL;
if (m)
{
if (m->createForConfiguration (configuration, 0))
{
if (mListener)
mListener->materialCreated (m, configuration, 0);
}
else
return NULL;
for (LodConfigurationMap::iterator it = mLodConfigurations.begin(); it != mLodConfigurations.end(); ++it)
{
if (m->createForConfiguration (configuration, it->first))
{
if (mListener)
mListener->materialCreated (m, configuration, it->first);
}
else
return NULL;
}
}
return m;
}
MaterialInstance* Factory::createMaterialInstance (const std::string& name, const std::string& parentInstance)
{
if (parentInstance != "" && mMaterials.find(parentInstance) == mMaterials.end())
throw std::runtime_error ("trying to clone material that does not exist");
MaterialInstance newInstance(name, this);
if (!mShadersEnabled)
newInstance.setShadersEnabled(false);
if (parentInstance != "")
newInstance.setParent (&mMaterials.find(parentInstance)->second);
newInstance.create(mPlatform);
mMaterials.insert (std::make_pair(name, newInstance));
return &mMaterials.find(name)->second;
}
void Factory::destroyMaterialInstance (const std::string& name)
{
if (mMaterials.find(name) != mMaterials.end())
mMaterials.erase(name);
}
void Factory::setShadersEnabled (bool enabled)
{
mShadersEnabled = enabled;
for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it)
{
it->second.setShadersEnabled(enabled);
}
}
void Factory::setGlobalSetting (const std::string& name, const std::string& value)
{
bool changed = true;
if (mGlobalSettings.hasProperty(name))
changed = (retrieveValue<StringValue>(mGlobalSettings.getProperty(name), NULL).get() != value);
mGlobalSettings.setProperty (name, makeProperty<StringValue>(new StringValue(value)));
if (changed)
{
for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it)
{
it->second.destroyAll();
}
}
}
void Factory::setSharedParameter (const std::string& name, PropertyValuePtr value)
{
mPlatform->setSharedParameter(name, value);
}
ShaderSet* Factory::getShaderSet (const std::string& name)
{
if (mShaderSets.find(name) == mShaderSets.end())
{
std::stringstream msg;
msg << "Shader '" << name << "' not found";
throw std::runtime_error(msg.str());
}
return &mShaderSets.find(name)->second;
}
Platform* Factory::getPlatform ()
{
return mPlatform;
}
Language Factory::getCurrentLanguage ()
{
return mCurrentLanguage;
}
void Factory::setCurrentLanguage (Language lang)
{
bool changed = (mCurrentLanguage != lang);
mCurrentLanguage = lang;
if (changed)
{
for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it)
{
it->second.destroyAll();
}
}
}
void Factory::notifyConfigurationChanged()
{
for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it)
{
it->second.destroyAll();
}
}
MaterialInstance* Factory::getMaterialInstance (const std::string& name)
{
return findInstance(name);
}
void Factory::setTextureAlias (const std::string& alias, const std::string& realName)
{
mTextureAliases[alias] = realName;
// update the already existing texture units
for (std::map<TextureUnitState*, std::string>::iterator it = mTextureAliasInstances.begin(); it != mTextureAliasInstances.end(); ++it)
{
if (it->second == alias)
{
it->first->setTextureName(realName);
}
}
}
std::string Factory::retrieveTextureAlias (const std::string& name)
{
TextureAliasMap::iterator it = mTextureAliases.find(name);
if (it != mTextureAliases.end())
return it->second;
else
return "";
}
Configuration* Factory::getConfiguration (const std::string& name)
{
return &mConfigurations[name];
}
void Factory::createConfiguration (const std::string& name)
{
mConfigurations[name].setParent (&mGlobalSettings);
}
void Factory::destroyConfiguration(const std::string &name)
{
mConfigurations.erase(name);
}
void Factory::registerLodConfiguration (int index, PropertySetGet configuration)
{
mLodConfigurations[index] = configuration;
}
void Factory::setMaterialListener (MaterialListener* listener)
{
mListener = listener;
}
void Factory::addTextureAliasInstance (const std::string& name, TextureUnitState* t)
{
mTextureAliasInstances[t] = name;
}
void Factory::removeTextureAliasInstances (TextureUnitState* t)
{
mTextureAliasInstances.erase(t);
}
void Factory::setActiveConfiguration (const std::string& configuration)
{
if (configuration == "Default")
mCurrentConfiguration = 0;
else
{
assert (mConfigurations.find(configuration) != mConfigurations.end());
mCurrentConfiguration = &mConfigurations[configuration];
}
}
void Factory::setActiveLodLevel (int level)
{
if (level == 0)
mCurrentLodConfiguration = 0;
else
{
assert (mLodConfigurations.find(level) != mLodConfigurations.end());
mCurrentLodConfiguration = &mLodConfigurations[level];
}
}
void Factory::setShaderDebugOutputEnabled (bool enabled)
{
mShaderDebugOutputEnabled = enabled;
}
PropertySetGet* Factory::getCurrentGlobalSettings()
{
PropertySetGet* p = &mGlobalSettings;
// current global settings are affected by active configuration & active lod configuration
if (mCurrentConfiguration)
{
p = mCurrentConfiguration;
}
if (mCurrentLodConfiguration)
{
mCurrentLodConfiguration->setParent(p);
p = mCurrentLodConfiguration;
}
return p;
}
void Factory::saveAll ()
{
std::map<std::string, std::ofstream*> files;
for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it)
{
if (it->second.getSourceFile().empty())
continue;
if (files.find(it->second.getSourceFile()) == files.end())
{
/// \todo check if this is actually the same file, since there can be different paths to the same file
std::ofstream* stream = new std::ofstream();
stream->open (it->second.getSourceFile().c_str());
files[it->second.getSourceFile()] = stream;
}
it->second.save (*files[it->second.getSourceFile()]);
}
for (std::map<std::string, std::ofstream*>::iterator it = files.begin(); it != files.end(); ++it)
{
delete it->second;
}
files.clear();
for (ConfigurationMap::iterator it = mConfigurations.begin(); it != mConfigurations.end(); ++it)
{
if (it->second.getSourceFile().empty())
continue;
if (files.find(it->second.getSourceFile()) == files.end())
{
/// \todo check if this is actually the same file, since there can be different paths to the same file
std::ofstream* stream = new std::ofstream();
stream->open (it->second.getSourceFile().c_str());
files[it->second.getSourceFile()] = stream;
}
it->second.save (it->first, *files[it->second.getSourceFile()]);
}
for (std::map<std::string, std::ofstream*>::iterator it = files.begin(); it != files.end(); ++it)
{
delete it->second;
}
}
void Factory::listMaterials(std::vector<std::string> &out)
{
for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it)
{
out.push_back(it->first);
}
}
void Factory::listGlobalSettings(std::map<std::string, std::string> &out)
{
const PropertyMap& properties = mGlobalSettings.listProperties();
for (PropertyMap::const_iterator it = properties.begin(); it != properties.end(); ++it)
{
out[it->first] = retrieveValue<StringValue>(mGlobalSettings.getProperty(it->first), NULL).get();
}
}
void Factory::listConfigurationSettings(const std::string& name, std::map<std::string, std::string> &out)
{
const PropertyMap& properties = mConfigurations[name].listProperties();
for (PropertyMap::const_iterator it = properties.begin(); it != properties.end(); ++it)
{
out[it->first] = retrieveValue<StringValue>(mConfigurations[name].getProperty(it->first), NULL).get();
}
}
void Factory::listConfigurationNames(std::vector<std::string> &out)
{
for (ConfigurationMap::const_iterator it = mConfigurations.begin(); it != mConfigurations.end(); ++it)
{
out.push_back(it->first);
}
}
void Factory::listShaderSets(std::vector<std::string> &out)
{
for (ShaderSetMap::const_iterator it = mShaderSets.begin(); it != mShaderSets.end(); ++it)
{
out.push_back(it->first);
}
}
void Factory::_ensureMaterial(const std::string& name, const std::string& configuration)
{
MaterialInstance* m = searchInstance (name);
assert(m);
m->createForConfiguration (configuration, 0);
for (LodConfigurationMap::iterator it = mLodConfigurations.begin(); it != mLodConfigurations.end(); ++it)
{
m->createForConfiguration (configuration, it->first);
}
}
bool Factory::removeCache(const std::string& pattern)
{
bool ret = false;
if ( boost::filesystem::exists(mPlatform->getCacheFolder())
&& boost::filesystem::is_directory(mPlatform->getCacheFolder()))
{
boost::filesystem::directory_iterator end_iter;
for( boost::filesystem::directory_iterator dir_iter(mPlatform->getCacheFolder()) ; dir_iter != end_iter ; ++dir_iter)
{
if (boost::filesystem::is_regular_file(dir_iter->status()) )
{
boost::filesystem::path file = dir_iter->path();
std::string pathname = file.filename().string();
// get first part of filename, e.g. main_fragment_546457654 -> main_fragment
// there is probably a better method for this...
std::vector<std::string> tokens;
boost::split(tokens, pathname, boost::is_any_of("_"));
tokens.erase(--tokens.end());
std::string shaderName;
for (std::vector<std::string>::const_iterator vector_iter = tokens.begin(); vector_iter != tokens.end();)
{
shaderName += *(vector_iter++);
if (vector_iter != tokens.end())
shaderName += "_";
}
if (shaderName == pattern)
{
boost::filesystem::remove(file);
ret = true;
std::cout << "Removing outdated shader: " << file << std::endl;
}
}
}
}
return ret;
}
bool Factory::reloadShaders()
{
mShaderSets.clear();
notifyConfigurationChanged();
bool removeBinaryCache = false;
ScriptLoader shaderSetLoader(".shaderset");
ScriptLoader::loadAllFiles (&shaderSetLoader, mPlatform->getBasePath());
std::map <std::string, ScriptNode*> nodes = shaderSetLoader.getAllConfigScripts();
for (std::map <std::string, ScriptNode*>::const_iterator it = nodes.begin();
it != nodes.end(); ++it)
{
if (!(it->second->getName() == "shader_set"))
{
std::cerr << "sh::Factory: Warning: Unsupported root node type \"" << it->second->getName() << "\" for file type .shaderset" << std::endl;
break;
}
if (!it->second->findChild("profiles_cg"))
throw std::runtime_error ("missing \"profiles_cg\" field for \"" + it->first + "\"");
if (!it->second->findChild("profiles_hlsl"))
throw std::runtime_error ("missing \"profiles_hlsl\" field for \"" + it->first + "\"");
if (!it->second->findChild("source"))
throw std::runtime_error ("missing \"source\" field for \"" + it->first + "\"");
if (!it->second->findChild("type"))
throw std::runtime_error ("missing \"type\" field for \"" + it->first + "\"");
std::vector<std::string> profiles_cg;
boost::split (profiles_cg, it->second->findChild("profiles_cg")->getValue(), boost::is_any_of(" "));
std::string cg_profile;
for (std::vector<std::string>::iterator it2 = profiles_cg.begin(); it2 != profiles_cg.end(); ++it2)
{
if (mPlatform->isProfileSupported(*it2))
{
cg_profile = *it2;
break;
}
}
std::vector<std::string> profiles_hlsl;
boost::split (profiles_hlsl, it->second->findChild("profiles_hlsl")->getValue(), boost::is_any_of(" "));
std::string hlsl_profile;
for (std::vector<std::string>::iterator it2 = profiles_hlsl.begin(); it2 != profiles_hlsl.end(); ++it2)
{
if (mPlatform->isProfileSupported(*it2))
{
hlsl_profile = *it2;
break;
}
}
std::string sourceAbsolute = mPlatform->getBasePath() + "/" + it->second->findChild("source")->getValue();
std::string sourceRelative = it->second->findChild("source")->getValue();
ShaderSet newSet (it->second->findChild("type")->getValue(), cg_profile, hlsl_profile,
sourceAbsolute,
mPlatform->getBasePath(),
it->first,
&mGlobalSettings);
int lastModified = boost::filesystem::last_write_time (boost::filesystem::path(sourceAbsolute));
mShadersLastModifiedNew[sourceRelative] = lastModified;
if (mShadersLastModified.find(sourceRelative) != mShadersLastModified.end())
{
if (mShadersLastModified[sourceRelative] != lastModified)
{
// delete any outdated shaders based on this shader set
if (removeCache (it->first))
removeBinaryCache = true;
}
}
else
{
// if we get here, this is either the first run or a new shader file was added
// in both cases we can safely delete
if (removeCache (it->first))
removeBinaryCache = true;
}
mShaderSets.insert(std::make_pair(it->first, newSet));
}
// new is now current
mShadersLastModified = mShadersLastModifiedNew;
return removeBinaryCache;
}
void Factory::doMonitorShaderFiles()
{
bool reload=false;
ScriptLoader shaderSetLoader(".shaderset");
ScriptLoader::loadAllFiles (&shaderSetLoader, mPlatform->getBasePath());
std::map <std::string, ScriptNode*> nodes = shaderSetLoader.getAllConfigScripts();
for (std::map <std::string, ScriptNode*>::const_iterator it = nodes.begin();
it != nodes.end(); ++it)
{
std::string sourceAbsolute = mPlatform->getBasePath() + "/" + it->second->findChild("source")->getValue();
std::string sourceRelative = it->second->findChild("source")->getValue();
int lastModified = boost::filesystem::last_write_time (boost::filesystem::path(sourceAbsolute));
if (mShadersLastModified.find(sourceRelative) != mShadersLastModified.end())
{
if (mShadersLastModified[sourceRelative] != lastModified)
{
reload=true;
break;
}
}
}
if (reload)
reloadShaders();
}
void Factory::logError(const std::string &msg)
{
mErrorLog << msg << '\n';
}
std::string Factory::getErrorLog()
{
std::string errors = mErrorLog.str();
mErrorLog.str("");
return errors;
}
void Factory::unloadUnreferencedMaterials()
{
for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it)
{
if (it->second.getMaterial()->isUnreferenced())
it->second.getMaterial()->unreferenceTextures();
}
}
void Configuration::save(const std::string& name, std::ofstream &stream)
{
stream << "configuration " << name << '\n';
stream << "{\n";
PropertySetGet::save(stream, "\t");
stream << "}\n";
}
}

@ -1,271 +0,0 @@
#ifndef SH_FACTORY_H
#define SH_FACTORY_H
#include <map>
#include <string>
#include <sstream>
#include "MaterialInstance.hpp"
#include "ShaderSet.hpp"
#include "Language.hpp"
namespace sh
{
class Platform;
class Configuration : public PropertySetGet
{
public:
void setSourceFile (const std::string& file) { mSourceFile = file ; }
std::string getSourceFile () { return mSourceFile; }
void save(const std::string& name, std::ofstream &stream);
private:
std::string mSourceFile;
};
typedef std::map<std::string, MaterialInstance> MaterialMap;
typedef std::map<std::string, ShaderSet> ShaderSetMap;
typedef std::map<std::string, Configuration> ConfigurationMap;
typedef std::map<int, PropertySetGet> LodConfigurationMap;
typedef std::map<std::string, int> LastModifiedMap;
typedef std::map<std::string, std::string> TextureAliasMap;
/**
* @brief
* Allows you to be notified when a certain material was just created. Useful for changing material properties that you can't
* do in a .mat script (for example a series of animated textures) \n
* When receiving the event, you can get the platform material by calling m->getMaterial()
* and casting that to the platform specific material (e.g. for Ogre, sh::OgreMaterial)
*/
class MaterialListener
{
public:
virtual void materialCreated (MaterialInstance* m, const std::string& configuration, unsigned short lodIndex) = 0;
};
/**
* @brief
* The main interface class
*/
class Factory
{
public:
Factory(Platform* platform);
///< @note Ownership of \a platform is transferred to this class, so you don't have to delete it.
~Factory();
/**
* Create a MaterialInstance, optionally copying all properties from \a parentInstance
* @param name name of the new instance
* @param name of the parent (optional)
* @return newly created instance
*/
MaterialInstance* createMaterialInstance (const std::string& name, const std::string& parentInstance = "");
/// @note It is safe to call this if the instance does not exist
void destroyMaterialInstance (const std::string& name);
/// Use this to enable or disable shaders on-the-fly
void setShadersEnabled (bool enabled);
/// write generated shaders to current directory, useful for debugging
void setShaderDebugOutputEnabled (bool enabled);
/// Use this to manage user settings. \n
/// Global settings can be retrieved in shaders through a macro. \n
/// When a global setting is changed, the shaders that depend on them are recompiled automatically.
void setGlobalSetting (const std::string& name, const std::string& value);
/// Adjusts the given shared parameter. \n
/// Internally, this will change all uniform parameters of this name marked with the macro \@shSharedParameter \n
/// @param name of the shared parameter
/// @param value of the parameter, use sh::makeProperty to construct this value
void setSharedParameter (const std::string& name, PropertyValuePtr value);
Language getCurrentLanguage ();
/// Switch between different shader languages (cg, glsl, hlsl)
void setCurrentLanguage (Language lang);
/// Get a MaterialInstance by name
MaterialInstance* getMaterialInstance (const std::string& name);
/// Create a configuration, which can then be altered by using Factory::getConfiguration
void createConfiguration (const std::string& name);
/// Register a lod configuration, which can then be used by setting up lod distance values for the material \n
/// 0 refers to highest lod, so use 1 or higher as index parameter
void registerLodConfiguration (int index, PropertySetGet configuration);
/// Set an alias name for a texture, the real name can then be retrieved with the "texture_alias"
/// property in a texture unit - this is useful if you don't know the name of your texture beforehand. \n
/// Example: \n
/// - In the material definition: texture_alias ReflectionMap \n
/// - At runtime: factory->setTextureAlias("ReflectionMap", "rtt_654654"); \n
/// You can call factory->setTextureAlias as many times as you want, and if the material was already created, its texture will be updated!
void setTextureAlias (const std::string& alias, const std::string& realName);
/// Retrieve the real texture name for a texture alias (the real name is set by the user)
std::string retrieveTextureAlias (const std::string& name);
/// Attach a listener for material created events
void setMaterialListener (MaterialListener* listener);
/// Call this after you have set up basic stuff, like the shader language.
void loadAllFiles ();
/// Controls writing of generated shader source code to the cache folder, so that the
/// (rather expensive) preprocessing step can be skipped on the next run. See Factory::setReadSourceCache \n
/// \note The default is off (no cache writing)
void setWriteSourceCache(bool write) { mWriteSourceCache = write; }
/// Controls reading of generated shader sources from the cache folder
/// \note The default is off (no cache reading)
/// \note Even if microcode caching is enabled, generating (or caching) the source is still required due to the macros.
void setReadSourceCache(bool read) { mReadSourceCache = read; }
/// Controls writing the microcode of the generated shaders to the cache folder. Microcode is machine independent
/// and loads very fast compared to regular compilation. Note that the availability of this feature depends on the \a Platform.
/// \note The default is off (no cache writing)
void setWriteMicrocodeCache(bool write) { mWriteMicrocodeCache = write; }
/// Controls reading of shader microcode from the cache folder. Microcode is machine independent
/// and loads very fast compared to regular compilation. Note that the availability of this feature depends on the \a Platform.
/// \note The default is off (no cache reading)
void setReadMicrocodeCache(bool read) { mReadMicrocodeCache = read; }
/// Lists all materials currently registered with the factory. Whether they are
/// loaded or not does not matter.
void listMaterials (std::vector<std::string>& out);
/// Lists current name & value of all global settings.
void listGlobalSettings (std::map<std::string, std::string>& out);
/// Lists configuration names.
void listConfigurationNames (std::vector<std::string>& out);
/// Lists current name & value of settings for a given configuration.
void listConfigurationSettings (const std::string& name, std::map<std::string, std::string>& out);
/// Lists shader sets.
void listShaderSets (std::vector<std::string>& out);
/// \note This only works if microcode caching is disabled, as there is currently no way to remove the cache
/// through the Ogre API. Luckily, this is already fixed in Ogre 1.9.
bool reloadShaders();
/// Calls reloadShaders() if shader files have been modified since the last reload.
/// \note This only works if microcode caching is disabled, as there is currently no way to remove the cache
/// through the Ogre API. Luckily, this is already fixed in Ogre 1.9.
void doMonitorShaderFiles();
/// Unloads all materials that are currently not referenced. This will not unload the textures themselves,
/// but it will let go of the SharedPtr's to the textures, so that you may unload them if you so desire. \n
/// A good time to call this would be after a new level has been loaded, but just calling it occasionally after a period
/// of time should work just fine too.
void unloadUnreferencedMaterials();
void destroyConfiguration (const std::string& name);
void notifyConfigurationChanged();
/// Saves all materials and configurations, by default to the file they were loaded from.
/// If you wish to save them elsewhere, use setSourceFile first.
void saveAll ();
/// Returns the error log as a string, then clears it.
/// Note: Errors are also written to the standard error output, or thrown if they are fatal.
std::string getErrorLog ();
static Factory& getInstance();
///< Return instance of this class.
static Factory* getInstancePtr();
/// Make sure a material technique is loaded.\n
/// You will probably never have to use this.
void _ensureMaterial(const std::string& name, const std::string& configuration);
Configuration* getConfiguration (const std::string& name);
private:
MaterialInstance* requestMaterial (const std::string& name, const std::string& configuration, unsigned short lodIndex);
ShaderSet* getShaderSet (const std::string& name);
Platform* getPlatform ();
PropertySetGet* getCurrentGlobalSettings();
void addTextureAliasInstance (const std::string& name, TextureUnitState* t);
void removeTextureAliasInstances (TextureUnitState* t);
std::string getCacheFolder () { return mPlatform->getCacheFolder (); }
bool getReadSourceCache() { return mReadSourceCache; }
bool getWriteSourceCache() { return mWriteSourceCache; }
public:
bool getWriteMicrocodeCache() { return mWriteMicrocodeCache; } // Fixme
private:
void setActiveConfiguration (const std::string& configuration);
void setActiveLodLevel (int level);
bool getShaderDebugOutputEnabled() { return mShaderDebugOutputEnabled; }
std::map<TextureUnitState*, std::string> mTextureAliasInstances;
void logError (const std::string& msg);
friend class Platform;
friend class MaterialInstance;
friend class ShaderInstance;
friend class ShaderSet;
friend class TextureUnitState;
private:
static Factory* sThis;
bool mShadersEnabled;
bool mShaderDebugOutputEnabled;
bool mReadMicrocodeCache;
bool mWriteMicrocodeCache;
bool mReadSourceCache;
bool mWriteSourceCache;
std::stringstream mErrorLog;
MaterialMap mMaterials;
ShaderSetMap mShaderSets;
ConfigurationMap mConfigurations;
LodConfigurationMap mLodConfigurations;
LastModifiedMap mShadersLastModified;
LastModifiedMap mShadersLastModifiedNew;
PropertySetGet mGlobalSettings;
PropertySetGet* mCurrentConfiguration;
PropertySetGet* mCurrentLodConfiguration;
TextureAliasMap mTextureAliases;
Language mCurrentLanguage;
MaterialListener* mListener;
Platform* mPlatform;
MaterialInstance* findInstance (const std::string& name);
MaterialInstance* searchInstance (const std::string& name);
/// @return was anything removed?
bool removeCache (const std::string& pattern);
static const std::string mBinaryCacheName;
};
}
#endif

@ -1,17 +0,0 @@
#ifndef SH_LANGUAGE_H
#define SH_LANGUAGE_H
namespace sh
{
enum Language
{
Language_CG,
Language_HLSL,
Language_GLSL,
Language_GLSLES,
Language_Count,
Language_None
};
}
#endif

@ -1,261 +0,0 @@
#include "MaterialInstance.hpp"
#include <stdexcept>
#include <iostream>
#include "Factory.hpp"
#include "ShaderSet.hpp"
namespace sh
{
MaterialInstance::MaterialInstance (const std::string& name, Factory* f)
: mName(name)
, mShadersEnabled(true)
, mFactory(f)
, mListener(NULL)
, mFailedToCreate(false)
{
}
MaterialInstance::~MaterialInstance ()
{
}
void MaterialInstance::setParentInstance (const std::string& name)
{
mParentInstance = name;
}
std::string MaterialInstance::getParentInstance ()
{
return mParentInstance;
}
void MaterialInstance::create (Platform* platform)
{
mMaterial = platform->createMaterial(mName);
if (hasProperty ("shadow_caster_material"))
mMaterial->setShadowCasterMaterial (retrieveValue<StringValue>(getProperty("shadow_caster_material"), NULL).get());
if (hasProperty ("lod_values"))
mMaterial->setLodLevels (retrieveValue<StringValue>(getProperty("lod_values"), NULL).get());
}
void MaterialInstance::destroyAll ()
{
if (hasProperty("create_configuration"))
return;
mMaterial->removeAll();
mTexUnits.clear();
mFailedToCreate = false;
}
void MaterialInstance::setProperty (const std::string& name, PropertyValuePtr value)
{
PropertySetGet::setProperty (name, value);
destroyAll(); // trigger updates
}
bool MaterialInstance::createForConfiguration (const std::string& configuration, unsigned short lodIndex)
{
if (mFailedToCreate)
return false;
try{
mMaterial->ensureLoaded();
bool res = mMaterial->createConfiguration(configuration, lodIndex);
if (!res)
return false; // listener was false positive
if (mListener)
mListener->requestedConfiguration (this, configuration);
mFactory->setActiveConfiguration (configuration);
mFactory->setActiveLodLevel (lodIndex);
bool allowFixedFunction = true;
if (!mShadersEnabled && hasProperty("allow_fixed_function"))
{
allowFixedFunction = retrieveValue<BooleanValue>(getProperty("allow_fixed_function"), NULL).get();
}
bool useShaders = mShadersEnabled || !allowFixedFunction;
// get passes of the top-most parent
PassVector* passes = getParentPasses();
if (passes->empty())
throw std::runtime_error ("material \"" + mName + "\" does not have any passes");
for (PassVector::iterator it = passes->begin(); it != passes->end(); ++it)
{
boost::shared_ptr<Pass> pass = mMaterial->createPass (configuration, lodIndex);
it->copyAll (pass.get(), this);
// texture samplers used in the shaders
std::vector<std::string> usedTextureSamplersVertex;
std::vector<std::string> usedTextureSamplersFragment;
PropertySetGet* context = this;
// create or retrieve shaders
bool hasVertex = it->hasProperty("vertex_program")
&& !retrieveValue<StringValue>(it->getProperty("vertex_program"), context).get().empty();
bool hasFragment = it->hasProperty("fragment_program")
&& !retrieveValue<StringValue>(it->getProperty("fragment_program"), context).get().empty();
if (useShaders)
{
it->setContext(context);
it->mShaderProperties.setContext(context);
if (hasVertex)
{
ShaderSet* vertex = mFactory->getShaderSet(retrieveValue<StringValue>(it->getProperty("vertex_program"), context).get());
ShaderInstance* v = vertex->getInstance(&it->mShaderProperties);
if (v)
{
pass->assignProgram (GPT_Vertex, v->getName());
v->setUniformParameters (pass, &it->mShaderProperties);
std::vector<std::string> sharedParams = v->getSharedParameters ();
for (std::vector<std::string>::iterator it2 = sharedParams.begin(); it2 != sharedParams.end(); ++it2)
{
pass->addSharedParameter (GPT_Vertex, *it2);
}
std::vector<std::string> vector = v->getUsedSamplers ();
usedTextureSamplersVertex.insert(usedTextureSamplersVertex.end(), vector.begin(), vector.end());
}
}
if (hasFragment)
{
ShaderSet* fragment = mFactory->getShaderSet(retrieveValue<StringValue>(it->getProperty("fragment_program"), context).get());
ShaderInstance* f = fragment->getInstance(&it->mShaderProperties);
if (f)
{
pass->assignProgram (GPT_Fragment, f->getName());
f->setUniformParameters (pass, &it->mShaderProperties);
std::vector<std::string> sharedParams = f->getSharedParameters ();
for (std::vector<std::string>::iterator it2 = sharedParams.begin(); it2 != sharedParams.end(); ++it2)
{
pass->addSharedParameter (GPT_Fragment, *it2);
}
std::vector<std::string> vector = f->getUsedSamplers ();
usedTextureSamplersFragment.insert(usedTextureSamplersFragment.end(), vector.begin(), vector.end());
}
}
}
// create texture units
std::vector<MaterialInstanceTextureUnit>* texUnits = &it->mTexUnits;
int i=0;
for (std::vector<MaterialInstanceTextureUnit>::iterator texIt = texUnits->begin(); texIt != texUnits->end(); ++texIt )
{
// only create those that are needed by the shader, OR those marked to be created in fixed function pipeline if shaders are disabled
bool foundVertex = std::find(usedTextureSamplersVertex.begin(), usedTextureSamplersVertex.end(), texIt->getName()) != usedTextureSamplersVertex.end();
bool foundFragment = std::find(usedTextureSamplersFragment.begin(), usedTextureSamplersFragment.end(), texIt->getName()) != usedTextureSamplersFragment.end();
if ( (foundVertex || foundFragment)
|| (((!useShaders || (!hasVertex || !hasFragment)) && allowFixedFunction) && texIt->hasProperty("create_in_ffp") && retrieveValue<BooleanValue>(texIt->getProperty("create_in_ffp"), this).get()))
{
boost::shared_ptr<TextureUnitState> texUnit = pass->createTextureUnitState (texIt->getName());
texIt->copyAll (texUnit.get(), context);
mTexUnits.push_back(texUnit);
// set texture unit indices (required by GLSL)
if (useShaders && ((hasVertex && foundVertex) || (hasFragment && foundFragment)) && (mFactory->getCurrentLanguage () == Language_GLSL
|| mFactory->getCurrentLanguage() == Language_GLSLES))
{
pass->setTextureUnitIndex (foundVertex ? GPT_Vertex : GPT_Fragment, texIt->getName(), i);
++i;
}
}
}
}
if (mListener)
mListener->createdConfiguration (this, configuration);
return true;
} catch (std::runtime_error& e)
{
destroyAll();
mFailedToCreate = true;
std::stringstream msg;
msg << "Error while creating material " << mName << ": " << e.what();
std::cerr << msg.str() << std::endl;
mFactory->logError(msg.str());
return false;
}
}
Material* MaterialInstance::getMaterial ()
{
return mMaterial.get();
}
MaterialInstancePass* MaterialInstance::createPass ()
{
mPasses.push_back (MaterialInstancePass());
mPasses.back().setContext(this);
return &mPasses.back();
}
void MaterialInstance::deletePass(unsigned int index)
{
assert(mPasses.size() > index);
mPasses.erase(mPasses.begin()+index);
}
PassVector* MaterialInstance::getParentPasses()
{
if (mParent)
return static_cast<MaterialInstance*>(mParent)->getParentPasses();
else
return &mPasses;
}
PassVector* MaterialInstance::getPasses()
{
return &mPasses;
}
void MaterialInstance::setShadersEnabled (bool enabled)
{
if (enabled == mShadersEnabled)
return;
mShadersEnabled = enabled;
// trigger updates
if (mMaterial.get())
destroyAll();
}
void MaterialInstance::save (std::ofstream& stream)
{
stream << "material " << mName << "\n"
<< "{\n";
if (mParent)
{
stream << "\t" << "parent " << static_cast<MaterialInstance*>(mParent)->getName() << "\n";
}
const PropertyMap& properties = listProperties ();
for (PropertyMap::const_iterator it = properties.begin(); it != properties.end(); ++it)
{
stream << "\t" << it->first << " " << retrieveValue<StringValue>(getProperty(it->first), NULL).get() << "\n";
}
for (PassVector::iterator it = mPasses.begin(); it != mPasses.end(); ++it)
{
stream << "\tpass" << '\n';
stream << "\t{" << '\n';
it->save(stream);
stream << "\t}" << '\n';
}
stream << "}\n";
}
}

@ -1,109 +0,0 @@
#ifndef SH_MATERIALINSTANCE_H
#define SH_MATERIALINSTANCE_H
#include <vector>
#include <fstream>
#include "PropertyBase.hpp"
#include "Platform.hpp"
#include "MaterialInstancePass.hpp"
namespace sh
{
class Factory;
typedef std::vector<MaterialInstancePass> PassVector;
/**
* @brief
* Allows you to be notified when a certain configuration for a material was just about to be created. \n
* Useful for adjusting some properties prior to the material being created (Or you could also re-create
* the whole material from scratch, i.e. use this as a method to create this material entirely in code)
*/
class MaterialInstanceListener
{
public:
virtual void requestedConfiguration (MaterialInstance* m, const std::string& configuration) = 0; ///< called before creating
virtual void createdConfiguration (MaterialInstance* m, const std::string& configuration) = 0; ///< called after creating
virtual ~MaterialInstanceListener(){}
};
/**
* @brief
* A specific material instance, which has all required properties set
* (for example the diffuse & normal map, ambient/diffuse/specular values). \n
* Depending on these properties, the system will automatically select a shader permutation
* that suits these and create the backend materials / passes (provided by the \a Platform class).
*/
class MaterialInstance : public PropertySetGet
{
public:
MaterialInstance (const std::string& name, Factory* f);
virtual ~MaterialInstance ();
PassVector* getParentPasses(); ///< gets the passes of the top-most parent
PassVector* getPasses(); ///< get our passes (for derived materials, none)
MaterialInstancePass* createPass ();
void deletePass (unsigned int index);
/// @attention Because the backend material passes are created on demand, the returned material here might not contain anything yet!
/// The only place where you should use this method, is for the MaterialInstance given by the MaterialListener::materialCreated event!
Material* getMaterial();
/// attach a \a MaterialInstanceListener to this specific material (as opposed to \a MaterialListener, which listens to all materials)
void setListener (MaterialInstanceListener* l) { mListener = l; }
std::string getName() { return mName; }
virtual void setProperty (const std::string& name, PropertyValuePtr value);
void setSourceFile(const std::string& sourceFile) { mSourceFile = sourceFile; }
std::string getSourceFile() { return mSourceFile; }
///< get the name of the file this material was read from, or empty if it was created dynamically by code
private:
void setParentInstance (const std::string& name);
std::string getParentInstance ();
void create (Platform* platform);
bool createForConfiguration (const std::string& configuration, unsigned short lodIndex);
void destroyAll ();
void setShadersEnabled (bool enabled);
void save (std::ofstream& stream);
bool mFailedToCreate;
friend class Factory;
private:
std::string mParentInstance;
///< this is only used during the file-loading phase. an instance could be loaded before its parent is loaded,
/// so initially only the parent's name is written to this member.
/// once all instances are loaded, the actual mParent pointer (from PropertySetGet class) can be set
std::vector< boost::shared_ptr<TextureUnitState> > mTexUnits;
MaterialInstanceListener* mListener;
PassVector mPasses;
std::string mName;
std::string mSourceFile;
boost::shared_ptr<Material> mMaterial;
bool mShadersEnabled;
Factory* mFactory;
};
}
#endif

@ -1,35 +0,0 @@
#include "MaterialInstancePass.hpp"
#include <fstream>
namespace sh
{
MaterialInstanceTextureUnit* MaterialInstancePass::createTextureUnit (const std::string& name)
{
mTexUnits.push_back(MaterialInstanceTextureUnit(name));
return &mTexUnits.back();
}
void MaterialInstancePass::save(std::ofstream &stream)
{
if (mShaderProperties.listProperties().size())
{
stream << "\t\t" << "shader_properties" << '\n';
stream << "\t\t{\n";
mShaderProperties.save(stream, "\t\t\t");
stream << "\t\t}\n";
}
PropertySetGet::save(stream, "\t\t");
for (std::vector <MaterialInstanceTextureUnit>::iterator it = mTexUnits.begin();
it != mTexUnits.end(); ++it)
{
stream << "\t\ttexture_unit " << it->getName() << '\n';
stream << "\t\t{\n";
it->save(stream, "\t\t\t");
stream << "\t\t}\n";
}
}
}

@ -1,29 +0,0 @@
#ifndef SH_MATERIALINSTANCEPASS_H
#define SH_MATERIALINSTANCEPASS_H
#include <vector>
#include "PropertyBase.hpp"
#include "MaterialInstanceTextureUnit.hpp"
namespace sh
{
/**
* @brief
* Holds properties of a single texture unit in a \a MaterialInstancePass. \n
* No inheritance here for now.
*/
class MaterialInstancePass : public PropertySetGet
{
public:
MaterialInstanceTextureUnit* createTextureUnit (const std::string& name);
void save (std::ofstream& stream);
PropertySetGet mShaderProperties;
std::vector <MaterialInstanceTextureUnit> mTexUnits;
};
}
#endif

@ -1,14 +0,0 @@
#include "MaterialInstanceTextureUnit.hpp"
namespace sh
{
MaterialInstanceTextureUnit::MaterialInstanceTextureUnit (const std::string& name)
: mName(name)
{
}
std::string MaterialInstanceTextureUnit::getName() const
{
return mName;
}
}

@ -1,27 +0,0 @@
#ifndef SH_MATERIALINSTANCETEXTUREUNIT_H
#define SH_MATERIALINSTANCETEXTUREUNIT_H
#include "PropertyBase.hpp"
namespace sh
{
/**
* @brief
* A single texture unit state that belongs to a \a MaterialInstancePass \n
* this is not the real "backend" \a TextureUnitState (provided by \a Platform),
* it is merely a placeholder for properties. \n
* @note The backend \a TextureUnitState will only be created if this texture unit is
* actually used (i.e. referenced in the shader, or marked with property create_in_ffp = true).
*/
class MaterialInstanceTextureUnit : public PropertySetGet
{
public:
MaterialInstanceTextureUnit (const std::string& name);
std::string getName() const;
void setName (const std::string& name) { mName = name; }
private:
std::string mName;
};
}
#endif

@ -1,89 +0,0 @@
#include "Platform.hpp"
#include <stdexcept>
#include "Factory.hpp"
namespace sh
{
Platform::Platform (const std::string& basePath)
: mBasePath(basePath)
, mCacheFolder("./")
, mFactory(NULL)
{
}
Platform::~Platform ()
{
}
void Platform::setFactory (Factory* factory)
{
mFactory = factory;
}
std::string Platform::getBasePath ()
{
return mBasePath;
}
bool Platform::supportsMaterialQueuedListener ()
{
return false;
}
bool Platform::supportsShaderSerialization ()
{
return false;
}
MaterialInstance* Platform::fireMaterialRequested (const std::string& name, const std::string& configuration, unsigned short lodIndex)
{
return mFactory->requestMaterial (name, configuration, lodIndex);
}
void Platform::serializeShaders (const std::string& file)
{
throw std::runtime_error ("Shader serialization not supported by this platform");
}
void Platform::deserializeShaders (const std::string& file)
{
throw std::runtime_error ("Shader serialization not supported by this platform");
}
void Platform::setCacheFolder (const std::string& folder)
{
mCacheFolder = folder;
}
std::string Platform::getCacheFolder() const
{
return mCacheFolder;
}
// ------------------------------------------------------------------------------
bool TextureUnitState::setPropertyOverride (const std::string& name, PropertyValuePtr& value, PropertySetGet *context)
{
if (name == "texture_alias")
{
std::string aliasName = retrieveValue<StringValue>(value, context).get();
Factory::getInstance().addTextureAliasInstance (aliasName, this);
setTextureName (Factory::getInstance().retrieveTextureAlias (aliasName));
return true;
}
else
return false;
}
TextureUnitState::~TextureUnitState()
{
Factory* f = Factory::getInstancePtr ();
if (f)
f->removeTextureAliasInstances (this);
}
}

@ -1,147 +0,0 @@
#ifndef SH_PLATFORM_H
#define SH_PLATFORM_H
#include <string>
#include <boost/shared_ptr.hpp>
#include "Language.hpp"
#include "PropertyBase.hpp"
namespace sh
{
class Factory;
class MaterialInstance;
enum GpuProgramType
{
GPT_Vertex,
GPT_Fragment
// GPT_Geometry
};
// These classes are supposed to be filled by the platform implementation
class GpuProgram
{
public:
virtual ~GpuProgram() {}
virtual bool getSupported () = 0; ///< @return true if the compilation was successful
/// @param name name of the uniform in the shader
/// @param autoConstantName name of the auto constant (for example world_viewproj_matrix)
/// @param extraInfo if any extra info is needed (e.g. light index), put it here
virtual void setAutoConstant (const std::string& name, const std::string& autoConstantName, const std::string& extraInfo = "") = 0;
};
class TextureUnitState : public PropertySet
{
public:
virtual ~TextureUnitState();
virtual void setTextureName (const std::string& textureName) = 0;
protected:
virtual bool setPropertyOverride (const std::string& name, PropertyValuePtr& value, PropertySetGet *context);
};
class Pass : public PropertySet
{
public:
virtual boost::shared_ptr<TextureUnitState> createTextureUnitState (const std::string& name) = 0;
virtual void assignProgram (GpuProgramType type, const std::string& name) = 0;
/// @param type gpu program type
/// @param name name of the uniform in the shader
/// @param vt type of value, e.g. vector4
/// @param value value to set
/// @param context used for retrieving linked values
virtual void setGpuConstant (int type, const std::string& name, ValueType vt, PropertyValuePtr value, PropertySetGet* context) = 0;
virtual void setTextureUnitIndex (int programType, const std::string& name, int index) = 0;
virtual void addSharedParameter (int type, const std::string& name) = 0;
};
class Material : public PropertySet
{
public:
virtual boost::shared_ptr<Pass> createPass (const std::string& configuration, unsigned short lodIndex) = 0;
virtual bool createConfiguration (const std::string& name, unsigned short lodIndex) = 0; ///< @return false if already exists
virtual void removeAll () = 0; ///< remove all configurations
virtual bool isUnreferenced() = 0;
virtual void unreferenceTextures() = 0;
virtual void ensureLoaded() = 0;
virtual void setLodLevels (const std::string& lodLevels) = 0;
virtual void setShadowCasterMaterial (const std::string& name) = 0;
};
class Platform
{
public:
Platform (const std::string& basePath);
virtual ~Platform ();
/// set the folder to use for shader caching
void setCacheFolder (const std::string& folder);
private:
virtual boost::shared_ptr<Material> createMaterial (const std::string& name) = 0;
virtual boost::shared_ptr<GpuProgram> createGpuProgram (
GpuProgramType type,
const std::string& compileArguments,
const std::string& name, const std::string& profile,
const std::string& source, Language lang) = 0;
virtual void destroyGpuProgram (const std::string& name) = 0;
virtual void setSharedParameter (const std::string& name, PropertyValuePtr value) = 0;
virtual bool isProfileSupported (const std::string& profile) = 0;
virtual void serializeShaders (const std::string& file);
virtual void deserializeShaders (const std::string& file);
std::string getCacheFolder () const;
friend class Factory;
friend class MaterialInstance;
friend class ShaderInstance;
friend class ShaderSet;
protected:
/**
* this will be \a true if the platform supports serialization (writing shader microcode
* to disk) and deserialization (create gpu program from saved microcode)
*/
virtual bool supportsShaderSerialization ();
/**
* this will be \a true if the platform supports a listener that notifies the system
* whenever a material is requested for rendering. if this is supported, shaders can be
* compiled on-demand when needed (and not earlier)
* @todo the Factory is not designed yet to handle the case where this method returns false
*/
virtual bool supportsMaterialQueuedListener ();
/**
* fire event: material requested for rendering
* @param name material name
* @param configuration requested configuration
*/
MaterialInstance* fireMaterialRequested (const std::string& name, const std::string& configuration, unsigned short lodIndex);
std::string mCacheFolder;
Factory* mFactory;
private:
void setFactory (Factory* factory);
std::string mBasePath;
std::string getBasePath();
};
}
#endif

@ -1,151 +0,0 @@
#include "Preprocessor.hpp"
#include <boost/wave.hpp>
#include <boost/wave/cpplexer/cpp_lex_token.hpp>
#include <boost/wave/cpplexer/cpp_lex_iterator.hpp>
#include <boost/filesystem/fstream.hpp>
/*
Almost exact copy of load_file_to_string policy found in
boost::wave headers with the only change that it uses
boost::filesystem facility to handle UTF-8 paths properly on windows.
Original namespace is used due to required bost::wave
internal symbols.
*/
namespace boost {
namespace wave {
namespace iteration_context_policies {
struct load_utf8_path_to_string
{
template <typename IterContextT>
class inner
{
public:
template <typename PositionT>
static void init_iterators(IterContextT &iter_ctx,
PositionT const &act_pos, language_support language)
{
typedef typename IterContextT::iterator_type iterator_type;
namespace bfs = boost::filesystem;
// read in the file
bfs::ifstream instream(bfs::path(iter_ctx.filename.c_str()));
if (!instream.is_open()) {
BOOST_WAVE_THROW_CTX(iter_ctx.ctx, preprocess_exception,
bad_include_file, iter_ctx.filename.c_str(), act_pos);
return;
}
instream.unsetf(std::ios::skipws);
iter_ctx.instring.assign(
std::istreambuf_iterator<char>(instream.rdbuf()),
std::istreambuf_iterator<char>());
iter_ctx.first = iterator_type(
iter_ctx.instring.begin(), iter_ctx.instring.end(),
PositionT(iter_ctx.filename), language);
iter_ctx.last = iterator_type();
}
private:
std::string instring;
};
};
} } }
namespace sh
{
std::string Preprocessor::preprocess (std::string source, const std::string& includePath, std::vector<std::string> definitions, const std::string& name)
{
std::stringstream returnString;
// current file position is saved for exception handling
boost::wave::util::file_position_type current_position;
try
{
// This token type is one of the central types used throughout the library.
// It is a template parameter to some of the public classes and instances
// of this type are returned from the iterators.
typedef boost::wave::cpplexer::lex_token<> token_type;
// The template boost::wave::cpplexer::lex_iterator<> is the lexer type to
// to use as the token source for the preprocessing engine. It is
// parametrized with the token type.
typedef boost::wave::cpplexer::lex_iterator<token_type> lex_iterator_type;
// This is the resulting context type. The first template parameter should
// match the iterator type used during construction of the context
// instance (see below). It is the type of the underlying input stream.
typedef boost::wave::context<std::string::iterator, lex_iterator_type
, boost::wave::iteration_context_policies::load_utf8_path_to_string,
emit_custom_line_directives_hooks>
context_type;
// The preprocessor iterator shouldn't be constructed directly. It is
// generated through a wave::context<> object. This wave:context<> object
// is additionally used to initialize and define different parameters of
// the actual preprocessing.
//
// The preprocessing of the input stream is done on the fly behind the
// scenes during iteration over the range of context_type::iterator_type
// instances.
context_type ctx (source.begin(), source.end(), name.c_str());
ctx.add_include_path(includePath.c_str());
for (std::vector<std::string>::iterator it = definitions.begin(); it != definitions.end(); ++it)
{
ctx.add_macro_definition(*it);
}
// Get the preprocessor iterators and use them to generate the token
// sequence.
context_type::iterator_type first = ctx.begin();
context_type::iterator_type last = ctx.end();
// The input stream is preprocessed for you while iterating over the range
// [first, last). The dereferenced iterator returns tokens holding
// information about the preprocessed input stream, such as token type,
// token value, and position.
while (first != last)
{
current_position = (*first).get_position();
returnString << (*first).get_value();
++first;
}
}
catch (boost::wave::cpp_exception const& e)
{
// some preprocessing error
std::stringstream error;
error
<< e.file_name() << "(" << e.line_no() << "): "
<< e.description();
throw std::runtime_error(error.str());
}
catch (std::exception const& e)
{
// use last recognized token to retrieve the error position
std::stringstream error;
error
<< current_position.get_file()
<< "(" << current_position.get_line() << "): "
<< "exception caught: " << e.what();
throw std::runtime_error(error.str());
}
catch (...)
{
// use last recognized token to retrieve the error position
std::stringstream error;
error
<< current_position.get_file()
<< "(" << current_position.get_line() << "): "
<< "unexpected exception caught.";
throw std::runtime_error(error.str());
}
return returnString.str();
}
}

@ -1,69 +0,0 @@
#ifndef SH_PREPROCESSOR_H
#define SH_PREPROCESSOR_H
#include <string>
#include <vector>
#include <cstdio>
#include <ostream>
#include <string>
#include <algorithm>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/wave/cpp_throw.hpp>
#include <boost/wave/cpp_exceptions.hpp>
#include <boost/wave/token_ids.hpp>
#include <boost/wave/util/macro_helpers.hpp>
#include <boost/wave/preprocessing_hooks.hpp>
namespace sh
{
/**
* @brief A simple interface for the boost::wave preprocessor
*/
class Preprocessor
{
public:
/**
* @brief Run a shader source string through the preprocessor
* @param source source string
* @param includePath path to search for includes (that are included with #include)
* @param definitions macros to predefine (vector of strings of the format MACRO=value, or just MACRO to define it as 1)
* @param name name to use for error messages
* @return processed string
*/
static std::string preprocess (std::string source, const std::string& includePath, std::vector<std::string> definitions, const std::string& name);
};
class emit_custom_line_directives_hooks
: public boost::wave::context_policies::default_preprocessing_hooks
{
public:
template <typename ContextT, typename ContainerT>
bool
emit_line_directive(ContextT const& ctx, ContainerT &pending,
typename ContextT::token_type const& act_token)
{
// emit a #line directive showing the relative filename instead
typename ContextT::position_type pos = act_token.get_position();
unsigned int column = 1;
typedef typename ContextT::token_type result_type;
// no line directives for now
pos.set_column(column);
pending.push_back(result_type(boost::wave::T_GENERATEDNEWLINE, "\n", pos));
return true;
}
};
}
#endif

@ -1,302 +0,0 @@
#include "PropertyBase.hpp"
#include <vector>
#include <iostream>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <fstream>
namespace sh
{
IntValue::IntValue(int in)
: mValue(in)
{
}
IntValue::IntValue(const std::string& in)
{
mValue = boost::lexical_cast<int>(in);
}
std::string IntValue::serialize()
{
return boost::lexical_cast<std::string>(mValue);
}
// ------------------------------------------------------------------------------
BooleanValue::BooleanValue (bool in)
: mValue(in)
{
}
BooleanValue::BooleanValue (const std::string& in)
{
if (in == "true")
mValue = true;
else if (in == "false")
mValue = false;
else
{
std::stringstream msg;
msg << "sh::BooleanValue: Warning: Unrecognized value \"" << in << "\" for property value of type BooleanValue";
throw std::runtime_error(msg.str());
}
}
std::string BooleanValue::serialize ()
{
if (mValue)
return "true";
else
return "false";
}
// ------------------------------------------------------------------------------
StringValue::StringValue (const std::string& in)
{
mStringValue = in;
}
std::string StringValue::serialize()
{
return mStringValue;
}
// ------------------------------------------------------------------------------
LinkedValue::LinkedValue (const std::string& in)
{
mStringValue = in;
mStringValue.erase(0, 1);
}
std::string LinkedValue::serialize()
{
throw std::runtime_error ("can't directly get a linked value");
}
std::string LinkedValue::get(PropertySetGet* context) const
{
PropertyValuePtr p = context->getProperty(mStringValue);
return retrieveValue<StringValue>(p, NULL).get();
}
// ------------------------------------------------------------------------------
FloatValue::FloatValue (float in)
{
mValue = in;
}
FloatValue::FloatValue (const std::string& in)
{
mValue = boost::lexical_cast<float>(in);
}
std::string FloatValue::serialize ()
{
return boost::lexical_cast<std::string>(mValue);
}
// ------------------------------------------------------------------------------
Vector2::Vector2 (float x, float y)
: mX(x)
, mY(y)
{
}
Vector2::Vector2 (const std::string& in)
{
std::vector<std::string> tokens;
boost::split(tokens, in, boost::is_any_of(" "));
assert ((tokens.size() == 2) && "Invalid Vector2 conversion");
mX = boost::lexical_cast<float> (tokens[0]);
mY = boost::lexical_cast<float> (tokens[1]);
}
std::string Vector2::serialize ()
{
return boost::lexical_cast<std::string>(mX) + " "
+ boost::lexical_cast<std::string>(mY);
}
// ------------------------------------------------------------------------------
Vector3::Vector3 (float x, float y, float z)
: mX(x)
, mY(y)
, mZ(z)
{
}
Vector3::Vector3 (const std::string& in)
{
std::vector<std::string> tokens;
boost::split(tokens, in, boost::is_any_of(" "));
assert ((tokens.size() == 3) && "Invalid Vector3 conversion");
mX = boost::lexical_cast<float> (tokens[0]);
mY = boost::lexical_cast<float> (tokens[1]);
mZ = boost::lexical_cast<float> (tokens[2]);
}
std::string Vector3::serialize ()
{
return boost::lexical_cast<std::string>(mX) + " "
+ boost::lexical_cast<std::string>(mY) + " "
+ boost::lexical_cast<std::string>(mZ);
}
// ------------------------------------------------------------------------------
Vector4::Vector4 (float x, float y, float z, float w)
: mX(x)
, mY(y)
, mZ(z)
, mW(w)
{
}
Vector4::Vector4 (const std::string& in)
{
std::vector<std::string> tokens;
boost::split(tokens, in, boost::is_any_of(" "));
assert ((tokens.size() == 4) && "Invalid Vector4 conversion");
mX = boost::lexical_cast<float> (tokens[0]);
mY = boost::lexical_cast<float> (tokens[1]);
mZ = boost::lexical_cast<float> (tokens[2]);
mW = boost::lexical_cast<float> (tokens[3]);
}
std::string Vector4::serialize ()
{
return boost::lexical_cast<std::string>(mX) + " "
+ boost::lexical_cast<std::string>(mY) + " "
+ boost::lexical_cast<std::string>(mZ) + " "
+ boost::lexical_cast<std::string>(mW);
}
// ------------------------------------------------------------------------------
void PropertySet::setProperty (const std::string& name, PropertyValuePtr &value, PropertySetGet* context)
{
if (!setPropertyOverride (name, value, context))
{
std::stringstream msg;
msg << "sh::PropertySet: Warning: No match for property with name '" << name << "'";
throw std::runtime_error(msg.str());
}
}
bool PropertySet::setPropertyOverride (const std::string& name, PropertyValuePtr &value, PropertySetGet* context)
{
// if we got here, none of the sub-classes were able to make use of the property
return false;
}
// ------------------------------------------------------------------------------
PropertySetGet::PropertySetGet (PropertySetGet* parent)
: mParent(parent)
, mContext(NULL)
{
}
PropertySetGet::PropertySetGet ()
: mParent(NULL)
, mContext(NULL)
{
}
void PropertySetGet::setParent (PropertySetGet* parent)
{
mParent = parent;
}
void PropertySetGet::setContext (PropertySetGet* context)
{
mContext = context;
}
PropertySetGet* PropertySetGet::getContext()
{
return mContext;
}
void PropertySetGet::setProperty (const std::string& name, PropertyValuePtr value)
{
mProperties [name] = value;
}
void PropertySetGet::deleteProperty(const std::string &name)
{
mProperties.erase(name);
}
PropertyValuePtr& PropertySetGet::getProperty (const std::string& name)
{
bool found = (mProperties.find(name) != mProperties.end());
if (!found)
{
if (!mParent)
throw std::runtime_error ("Trying to retrieve property \"" + name + "\" that does not exist");
else
return mParent->getProperty (name);
}
else
return mProperties[name];
}
bool PropertySetGet::hasProperty (const std::string& name) const
{
bool found = (mProperties.find(name) != mProperties.end());
if (!found)
{
if (!mParent)
return false;
else
return mParent->hasProperty (name);
}
else
return true;
}
void PropertySetGet::copyAll (PropertySet* target, PropertySetGet* context, bool copyParent)
{
if (mParent && copyParent)
mParent->copyAll (target, context);
for (PropertyMap::iterator it = mProperties.begin(); it != mProperties.end(); ++it)
{
target->setProperty(it->first, it->second, context);
}
}
void PropertySetGet::copyAll (PropertySetGet* target, PropertySetGet* context, bool copyParent)
{
if (mParent && copyParent)
mParent->copyAll (target, context);
for (PropertyMap::iterator it = mProperties.begin(); it != mProperties.end(); ++it)
{
std::string val = retrieveValue<StringValue>(it->second, this).get();
target->setProperty(it->first, sh::makeProperty(new sh::StringValue(val)));
}
}
void PropertySetGet::save(std::ofstream &stream, const std::string& indentation)
{
for (PropertyMap::iterator it = mProperties.begin(); it != mProperties.end(); ++it)
{
if (typeid( *(it->second) ) == typeid(LinkedValue))
stream << indentation << it->first << " " << "$" + static_cast<LinkedValue*>(&*(it->second))->_getStringValue() << '\n';
else
stream << indentation << it->first << " " << retrieveValue<StringValue>(it->second, this).get() << '\n';
}
}
}

@ -1,244 +0,0 @@
#ifndef SH_PROPERTYBASE_H
#define SH_PROPERTYBASE_H
#include <string>
#include <map>
#include <boost/shared_ptr.hpp>
namespace sh
{
class StringValue;
class PropertySetGet;
class LinkedValue;
enum ValueType
{
VT_String,
VT_Int,
VT_Float,
VT_Vector2,
VT_Vector3,
VT_Vector4
};
class PropertyValue
{
public:
PropertyValue() {}
virtual ~PropertyValue() {}
std::string _getStringValue() { return mStringValue; }
virtual std::string serialize() = 0;
protected:
std::string mStringValue; ///< this will possibly not contain anything in the specialised classes
};
typedef boost::shared_ptr<PropertyValue> PropertyValuePtr;
class StringValue : public PropertyValue
{
public:
StringValue (const std::string& in);
std::string get() const { return mStringValue; }
virtual std::string serialize();
};
/**
* @brief Used for retrieving a named property from a context
*/
class LinkedValue : public PropertyValue
{
public:
LinkedValue (const std::string& in);
std::string get(PropertySetGet* context) const;
virtual std::string serialize();
};
class FloatValue : public PropertyValue
{
public:
FloatValue (float in);
FloatValue (const std::string& in);
float get() const { return mValue; }
virtual std::string serialize();
private:
float mValue;
};
class IntValue : public PropertyValue
{
public:
IntValue (int in);
IntValue (const std::string& in);
int get() const { return mValue; }
virtual std::string serialize();
private:
int mValue;
};
class BooleanValue : public PropertyValue
{
public:
BooleanValue (bool in);
BooleanValue (const std::string& in);
bool get() const { return mValue; }
virtual std::string serialize();
private:
bool mValue;
};
class Vector2 : public PropertyValue
{
public:
Vector2 (float x, float y);
Vector2 (const std::string& in);
float mX, mY;
virtual std::string serialize();
};
class Vector3 : public PropertyValue
{
public:
Vector3 (float x, float y, float z);
Vector3 (const std::string& in);
float mX, mY, mZ;
virtual std::string serialize();
};
class Vector4 : public PropertyValue
{
public:
Vector4 (float x, float y, float z, float w);
Vector4 (const std::string& in);
float mX, mY, mZ, mW;
virtual std::string serialize();
};
/// \brief base class that allows setting properties with any kind of value-type
class PropertySet
{
public:
virtual ~PropertySet() {}
void setProperty (const std::string& name, PropertyValuePtr& value, PropertySetGet* context);
protected:
virtual bool setPropertyOverride (const std::string& name, PropertyValuePtr& value, PropertySetGet* context);
///< @return \a true if the specified property was found, or false otherwise
};
typedef std::map<std::string, PropertyValuePtr> PropertyMap;
/// \brief base class that allows setting properties with any kind of value-type and retrieving them
class PropertySetGet
{
public:
PropertySetGet (PropertySetGet* parent);
PropertySetGet ();
virtual ~PropertySetGet() {}
void save (std::ofstream& stream, const std::string& indentation);
void copyAll (PropertySet* target, PropertySetGet* context, bool copyParent=true);
///< call setProperty for each property/value pair stored in \a this
void copyAll (PropertySetGet* target, PropertySetGet* context, bool copyParent=true);
///< call setProperty for each property/value pair stored in \a this
void setParent (PropertySetGet* parent);
PropertySetGet* getParent () { return mParent; }
void setContext (PropertySetGet* context);
PropertySetGet* getContext();
virtual void setProperty (const std::string& name, PropertyValuePtr value);
PropertyValuePtr& getProperty (const std::string& name);
void deleteProperty (const std::string& name);
const PropertyMap& listProperties() { return mProperties; }
bool hasProperty (const std::string& name) const;
private:
PropertyMap mProperties;
protected:
PropertySetGet* mParent;
///< the parent can provide properties as well (when they are retrieved via getProperty) \n
/// multiple levels of inheritance are also supported \n
/// children can override properties of their parents
PropertySetGet* mContext;
///< used to retrieve linked property values
};
template <typename T>
static T retrieveValue (boost::shared_ptr<PropertyValue>& value, PropertySetGet* context)
{
if (typeid(*value).name() == typeid(LinkedValue).name())
{
std::string v = static_cast<LinkedValue*>(value.get())->get(context);
PropertyValuePtr newVal = PropertyValuePtr (new StringValue(v));
return retrieveValue<T>(newVal, NULL);
}
if (typeid(T).name() == typeid(*value).name())
{
// requested type is the same as source type, only have to cast it
return *static_cast<T*>(value.get());
}
if ((typeid(T).name() == typeid(StringValue).name())
&& typeid(*value).name() != typeid(StringValue).name())
{
// if string type is requested and value is not string, use serialize method to convert to string
T* ptr = new T (value->serialize()); // note that T is always StringValue here, but we can't use it here
value = boost::shared_ptr<PropertyValue> (static_cast<PropertyValue*>(ptr));
return *ptr;
}
{
// remaining case: deserialization from string by passing the string to constructor of class T
T* ptr = new T(value->_getStringValue());
PropertyValuePtr newVal (static_cast<PropertyValue*>(ptr));
value = newVal;
return *ptr;
}
}
///<
/// @brief alternate version that supports linked values (use of $variables in parent material)
/// @note \a value is changed in-place to the converted object
/// @return converted object \n
/// Create a property from a string
inline PropertyValuePtr makeProperty (const std::string& prop)
{
if (prop.size() > 1 && prop[0] == '$')
return PropertyValuePtr (static_cast<PropertyValue*>(new LinkedValue(prop)));
else
return PropertyValuePtr (static_cast<PropertyValue*> (new StringValue(prop)));
}
template <typename T>
/// Create a property of any type
/// Example: sh::makeProperty (new sh::Vector4(1, 1, 1, 1))
inline PropertyValuePtr makeProperty (T* p)
{
return PropertyValuePtr ( static_cast<PropertyValue*>(p) );
}
}
#endif

@ -1,414 +0,0 @@
#include "ScriptLoader.hpp"
#include <vector>
#include <map>
#include <exception>
#include <fstream>
#include <boost/filesystem.hpp>
namespace sh
{
void ScriptLoader::loadAllFiles(ScriptLoader* c, const std::string& path)
{
for ( boost::filesystem::recursive_directory_iterator end, dir(path); dir != end; ++dir )
{
boost::filesystem::path p(*dir);
if(p.extension() == c->mFileEnding)
{
c->mCurrentFileName = (*dir).path().string();
std::ifstream in((*dir).path().string().c_str(), std::ios::binary);
c->parseScript(in);
}
}
}
ScriptLoader::ScriptLoader(const std::string& fileEnding)
: mLoadOrder(0)
, mToken(TOKEN_NewLine)
, mLastToken(TOKEN_NewLine)
{
mFileEnding = fileEnding;
}
ScriptLoader::~ScriptLoader()
{
clearScriptList();
}
void ScriptLoader::clearScriptList()
{
std::map <std::string, ScriptNode *>::iterator i;
for (i = m_scriptList.begin(); i != m_scriptList.end(); ++i)
{
delete i->second;
}
m_scriptList.clear();
}
ScriptNode *ScriptLoader::getConfigScript(const std::string &name)
{
std::map <std::string, ScriptNode*>::iterator i;
std::string key = name;
i = m_scriptList.find(key);
//If found..
if (i != m_scriptList.end())
{
return i->second;
}
else
{
return NULL;
}
}
std::map <std::string, ScriptNode*> ScriptLoader::getAllConfigScripts ()
{
return m_scriptList;
}
void ScriptLoader::parseScript(std::ifstream &stream)
{
//Get first token
_nextToken(stream);
if (mToken == TOKEN_EOF)
{
stream.close();
return;
}
//Parse the script
_parseNodes(stream, 0);
stream.close();
}
void ScriptLoader::_nextToken(std::ifstream &stream)
{
//EOF token
if (!stream.good())
{
mToken = TOKEN_EOF;
return;
}
//(Get next character)
int ch = stream.get();
while ((ch == ' ' || ch == 9) && !stream.eof())
{ //Skip leading spaces / tabs
ch = stream.get();
}
if (!stream.good())
{
mToken = TOKEN_EOF;
return;
}
//Newline token
if (ch == '\r' || ch == '\n')
{
do
{
ch = stream.get();
} while ((ch == '\r' || ch == '\n') && !stream.eof());
stream.unget();
mToken = TOKEN_NewLine;
return;
}
//Open brace token
else if (ch == '{')
{
mToken = TOKEN_OpenBrace;
return;
}
//Close brace token
else if (ch == '}')
{
mToken = TOKEN_CloseBrace;
return;
}
//Text token
if (ch < 32 || ch > 122) //Verify valid char
{
throw std::runtime_error("Parse Error: Invalid character, ConfigLoader::load()");
}
mTokenValue = "";
mToken = TOKEN_Text;
do
{
//Skip comments
if (ch == '/')
{
int ch2 = stream.peek();
//C++ style comment (//)
if (ch2 == '/')
{
stream.get();
do
{
ch = stream.get();
} while (ch != '\r' && ch != '\n' && !stream.eof());
mToken = TOKEN_NewLine;
return;
}
}
//Add valid char to tokVal
mTokenValue += (char)ch;
//Next char
ch = stream.get();
} while (ch > 32 && ch <= 122 && !stream.eof());
stream.unget();
return;
}
void ScriptLoader::_skipNewLines(std::ifstream &stream)
{
while (mToken == TOKEN_NewLine)
{
_nextToken(stream);
}
}
void ScriptLoader::_parseNodes(std::ifstream &stream, ScriptNode *parent)
{
typedef std::pair<std::string, ScriptNode*> ScriptItem;
while (true)
{
switch (mToken)
{
//Node
case TOKEN_Text:
{
//Add the new node
ScriptNode *newNode;
if (parent)
{
newNode = parent->addChild(mTokenValue);
}
else
{
newNode = new ScriptNode(0, mTokenValue);
}
//Get values
_nextToken(stream);
std::string valueStr;
int i=0;
while (mToken == TOKEN_Text)
{
if (i == 0)
valueStr += mTokenValue;
else
valueStr += " " + mTokenValue;
_nextToken(stream);
++i;
}
newNode->setValue(valueStr);
//Add root nodes to scriptList
if (!parent)
{
std::string key;
if (newNode->getValue() == "")
throw std::runtime_error("Root node must have a name (\"" + newNode->getName() + "\")");
key = newNode->getValue();
m_scriptList.insert(ScriptItem(key, newNode));
}
_skipNewLines(stream);
//Add any sub-nodes
if (mToken == TOKEN_OpenBrace)
{
//Parse nodes
_nextToken(stream);
_parseNodes(stream, newNode);
//Check for matching closing brace
if (mToken != TOKEN_CloseBrace)
{
throw std::runtime_error("Parse Error: Expecting closing brace");
}
_nextToken(stream);
_skipNewLines(stream);
}
newNode->mFileName = mCurrentFileName;
break;
}
//Out of place brace
case TOKEN_OpenBrace:
throw std::runtime_error("Parse Error: Opening brace out of plane");
break;
//Return if end of nodes have been reached
case TOKEN_CloseBrace:
return;
//Return if reached end of file
case TOKEN_EOF:
return;
case TOKEN_NewLine:
_nextToken(stream);
break;
}
};
}
ScriptNode::ScriptNode(ScriptNode *parent, const std::string &name)
{
mName = name;
mParent = parent;
mRemoveSelf = true; //For proper destruction
mLastChildFound = -1;
//Add self to parent's child list (unless this is the root node being created)
if (parent != NULL)
{
mParent->mChildren.push_back(this);
mIter = --(mParent->mChildren.end());
}
}
ScriptNode::~ScriptNode()
{
//Delete all children
std::vector<ScriptNode*>::iterator i;
for (i = mChildren.begin(); i != mChildren.end(); ++i)
{
ScriptNode *node = *i;
node->mRemoveSelf = false;
delete node;
}
mChildren.clear();
//Remove self from parent's child list
if (mRemoveSelf && mParent != NULL)
{
mParent->mChildren.erase(mIter);
}
}
ScriptNode *ScriptNode::addChild(const std::string &name, bool replaceExisting)
{
if (replaceExisting)
{
ScriptNode *node = findChild(name, false);
if (node)
{
return node;
}
}
return new ScriptNode(this, name);
}
ScriptNode *ScriptNode::findChild(const std::string &name, bool recursive)
{
int indx;
int childCount = (int)mChildren.size();
if (mLastChildFound != -1)
{
//If possible, try checking the nodes neighboring the last successful search
//(often nodes searched for in sequence, so this will boost search speeds).
int prevC = mLastChildFound-1;
if (prevC < 0)
prevC = 0;
else if (prevC >= childCount)
prevC = childCount-1;
int nextC = mLastChildFound+1;
if (nextC < 0)
nextC = 0;
else if (nextC >= childCount)
nextC = childCount-1;
for (indx = prevC; indx <= nextC; ++indx)
{
ScriptNode *node = mChildren[indx];
if (node->mName == name)
{
mLastChildFound = indx;
return node;
}
}
//If not found that way, search for the node from start to finish, avoiding the
//already searched area above.
for (indx = nextC + 1; indx < childCount; ++indx)
{
ScriptNode *node = mChildren[indx];
if (node->mName == name) {
mLastChildFound = indx;
return node;
}
}
for (indx = 0; indx < prevC; ++indx)
{
ScriptNode *node = mChildren[indx];
if (node->mName == name) {
mLastChildFound = indx;
return node;
}
}
}
else
{
//Search for the node from start to finish
for (indx = 0; indx < childCount; ++indx){
ScriptNode *node = mChildren[indx];
if (node->mName == name) {
mLastChildFound = indx;
return node;
}
}
}
//If not found, search child nodes (if recursive == true)
if (recursive)
{
for (indx = 0; indx < childCount; ++indx)
{
mChildren[indx]->findChild(name, recursive);
}
}
//Not found anywhere
return NULL;
}
void ScriptNode::setParent(ScriptNode *newParent)
{
//Remove self from current parent
mParent->mChildren.erase(mIter);
//Set new parent
mParent = newParent;
//Add self to new parent
mParent->mChildren.push_back(this);
mIter = --(mParent->mChildren.end());
}
}

@ -1,134 +0,0 @@
#ifndef SH_CONFIG_LOADER_H__
#define SH_CONFIG_LOADER_H__
#include <map>
#include <vector>
#include <cassert>
#include <string>
namespace sh
{
class ScriptNode;
/**
* @brief The base class of loaders that read Ogre style script files to get configuration and settings.
* Heavily inspired by: http://www.ogre3d.org/tikiwiki/All-purpose+script+parser
* ( "Non-ogre version")
*/
class ScriptLoader
{
public:
static void loadAllFiles(ScriptLoader* c, const std::string& path);
ScriptLoader(const std::string& fileEnding);
virtual ~ScriptLoader();
std::string mFileEnding;
// For a line like
// entity animals/dog
// {
// ...
// }
// The type is "entity" and the name is "animals/dog"
// Or if animal/dog was not there then name is ""
ScriptNode *getConfigScript (const std::string &name);
std::map <std::string, ScriptNode*> getAllConfigScripts ();
void parseScript(std::ifstream &stream);
std::string mCurrentFileName;
protected:
float mLoadOrder;
// like "*.object"
std::map <std::string, ScriptNode*> m_scriptList;
enum Token
{
TOKEN_Text,
TOKEN_NewLine,
TOKEN_OpenBrace,
TOKEN_CloseBrace,
TOKEN_EOF
};
Token mToken, mLastToken;
std::string mTokenValue;
void _parseNodes(std::ifstream &stream, ScriptNode *parent);
void _nextToken(std::ifstream &stream);
void _skipNewLines(std::ifstream &stream);
void clearScriptList();
};
class ScriptNode
{
public:
ScriptNode(ScriptNode *parent, const std::string &name = "untitled");
~ScriptNode();
inline void setName(const std::string &name)
{
this->mName = name;
}
inline std::string &getName()
{
return mName;
}
inline void setValue(const std::string &value)
{
mValue = value;
}
inline std::string &getValue()
{
return mValue;
}
ScriptNode *addChild(const std::string &name = "untitled", bool replaceExisting = false);
ScriptNode *findChild(const std::string &name, bool recursive = false);
inline std::vector<ScriptNode*> &getChildren()
{
return mChildren;
}
inline ScriptNode *getChild(unsigned int index = 0)
{
assert(index < mChildren.size());
return mChildren[index];
}
void setParent(ScriptNode *newParent);
inline ScriptNode *getParent()
{
return mParent;
}
std::string mFileName;
private:
std::string mName;
std::string mValue;
std::vector<ScriptNode*> mChildren;
ScriptNode *mParent;
int mLastChildFound; //The last child node's index found with a call to findChild()
std::vector<ScriptNode*>::iterator mIter;
bool mRemoveSelf;
};
}
#endif

@ -1,698 +0,0 @@
#include "ShaderInstance.hpp"
#include <stdexcept>
#include <iostream>
#include <fstream>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/bind.hpp>
#include <boost/filesystem.hpp>
#include "Preprocessor.hpp"
#include "Factory.hpp"
#include "ShaderSet.hpp"
namespace
{
std::string convertLang (sh::Language lang)
{
if (lang == sh::Language_CG)
return "SH_CG";
else if (lang == sh::Language_HLSL)
return "SH_HLSL";
else if (lang == sh::Language_GLSL)
return "SH_GLSL";
else if (lang == sh::Language_GLSLES)
return "SH_GLSLES";
throw std::runtime_error("invalid language");
}
char getComponent(int num)
{
if (num == 0)
return 'x';
else if (num == 1)
return 'y';
else if (num == 2)
return 'z';
else if (num == 3)
return 'w';
else
throw std::runtime_error("invalid component");
}
std::string getFloat(sh::Language lang, int num_components)
{
if (lang == sh::Language_CG || lang == sh::Language_HLSL)
return (num_components == 1) ? "float" : "float" + boost::lexical_cast<std::string>(num_components);
else
return (num_components == 1) ? "float" : "vec" + boost::lexical_cast<std::string>(num_components);
}
bool isCmd (const std::string& source, size_t pos, const std::string& cmd)
{
return (source.size() >= pos + cmd.size() && source.substr(pos, cmd.size()) == cmd);
}
void writeDebugFile (const std::string& content, const std::string& filename)
{
boost::filesystem::path full_path(boost::filesystem::current_path());
std::ofstream of ((full_path / filename ).string().c_str() , std::ios_base::out);
of.write(content.c_str(), content.size());
of.close();
}
}
namespace sh
{
std::string Passthrough::expand_assign(std::string toAssign)
{
std::string res;
int i = 0;
int current_passthrough = passthrough_number;
int current_component_left = component_start;
int current_component_right = 0;
int components_left = num_components;
int components_at_once;
while (i < num_components)
{
if (components_left + current_component_left <= 4)
components_at_once = components_left;
else
components_at_once = 4 - current_component_left;
std::string componentStr = ".";
for (int j = 0; j < components_at_once; ++j)
componentStr += getComponent(j + current_component_left);
std::string componentStr2 = ".";
for (int j = 0; j < components_at_once; ++j)
componentStr2 += getComponent(j + current_component_right);
if (num_components == 1)
{
componentStr2 = "";
}
res += "passthrough" + boost::lexical_cast<std::string>(current_passthrough) + componentStr + " = " + toAssign + componentStr2;
current_component_left += components_at_once;
current_component_right += components_at_once;
components_left -= components_at_once;
i += components_at_once;
if (components_left == 0)
{
// finished
return res;
}
else
{
// add semicolon to every instruction but the last
res += "; ";
}
if (current_component_left == 4)
{
current_passthrough++;
current_component_left = 0;
}
}
throw std::runtime_error("expand_assign error"); // this should never happen, but gets us rid of the "control reaches end of non-void function" warning
}
std::string Passthrough::expand_receive()
{
std::string res;
res += getFloat(lang, num_components) + "(";
int i = 0;
int current_passthrough = passthrough_number;
int current_component = component_start;
int components_left = num_components;
while (i < num_components)
{
int components_at_once = std::min(components_left, 4 - current_component);
std::string componentStr;
for (int j = 0; j < components_at_once; ++j)
componentStr += getComponent(j + current_component);
res += "passthrough" + boost::lexical_cast<std::string>(current_passthrough) + "." + componentStr;
current_component += components_at_once;
components_left -= components_at_once;
i += components_at_once;
if (components_left == 0)
{
// finished
return res + ")";
;
}
else
{
// add comma to every variable but the last
res += ", ";
}
if (current_component == 4)
{
current_passthrough++;
current_component = 0;
}
}
throw std::runtime_error("expand_receive error"); // this should never happen, but gets us rid of the "control reaches end of non-void function" warning
}
// ------------------------------------------------------------------------------
void ShaderInstance::parse (std::string& source, PropertySetGet* properties)
{
size_t pos = 0;
while (true)
{
pos = source.find("@", pos);
if (pos == std::string::npos)
break;
if (isCmd(source, pos, "@shProperty"))
{
std::vector<std::string> args = extractMacroArguments (pos, source);
size_t start = source.find("(", pos);
size_t end = source.find(")", pos);
std::string cmd = source.substr(pos+1, start-(pos+1));
std::string replaceValue;
if (cmd == "shPropertyBool")
{
std::string propertyName = args[0];
PropertyValuePtr value = properties->getProperty(propertyName);
bool val = retrieveValue<BooleanValue>(value, properties->getContext()).get();
replaceValue = val ? "1" : "0";
}
else if (cmd == "shPropertyString")
{
std::string propertyName = args[0];
PropertyValuePtr value = properties->getProperty(propertyName);
replaceValue = retrieveValue<StringValue>(value, properties->getContext()).get();
}
else if (cmd == "shPropertyEqual")
{
std::string propertyName = args[0];
std::string comparedAgainst = args[1];
std::string value = retrieveValue<StringValue>(properties->getProperty(propertyName), properties->getContext()).get();
replaceValue = (value == comparedAgainst) ? "1" : "0";
}
else if (isCmd(source, pos, "@shPropertyHasValue"))
{
assert(args.size() == 1);
std::string propertyName = args[0];
PropertyValuePtr value = properties->getProperty(propertyName);
std::string val = retrieveValue<StringValue>(value, properties->getContext()).get();
replaceValue = (val.empty() ? "0" : "1");
}
else
throw std::runtime_error ("unknown command \"" + cmd + "\"");
source.replace(pos, (end+1)-pos, replaceValue);
}
else if (isCmd(source, pos, "@shGlobalSetting"))
{
std::vector<std::string> args = extractMacroArguments (pos, source);
std::string cmd = source.substr(pos+1, source.find("(", pos)-(pos+1));
std::string replaceValue;
if (cmd == "shGlobalSettingBool")
{
std::string settingName = args[0];
std::string value = retrieveValue<StringValue>(mParent->getCurrentGlobalSettings()->getProperty(settingName), NULL).get();
replaceValue = (value == "true" || value == "1") ? "1" : "0";
}
else if (cmd == "shGlobalSettingEqual")
{
std::string settingName = args[0];
std::string comparedAgainst = args[1];
std::string value = retrieveValue<StringValue>(mParent->getCurrentGlobalSettings()->getProperty(settingName), NULL).get();
replaceValue = (value == comparedAgainst) ? "1" : "0";
}
else if (cmd == "shGlobalSettingString")
{
std::string settingName = args[0];
replaceValue = retrieveValue<StringValue>(mParent->getCurrentGlobalSettings()->getProperty(settingName), NULL).get();
}
else
throw std::runtime_error ("unknown command \"" + cmd + "\"");
source.replace(pos, (source.find(")", pos)+1)-pos, replaceValue);
}
else if (isCmd(source, pos, "@shForeach"))
{
assert(source.find("@shEndForeach", pos) != std::string::npos);
size_t block_end = source.find("@shEndForeach", pos);
// get the argument for parsing
size_t start = source.find("(", pos);
size_t end = start;
int brace_depth = 1;
while (brace_depth > 0)
{
++end;
if (source[end] == '(')
++brace_depth;
else if (source[end] == ')')
--brace_depth;
}
std::string arg = source.substr(start+1, end-(start+1));
parse(arg, properties);
int num = boost::lexical_cast<int>(arg);
// get the content of the inner block
std::string content = source.substr(end+1, block_end - (end+1));
// replace both outer and inner block with content of inner block num times
std::string replaceStr;
for (int i=0; i<num; ++i)
{
// replace @shIterator with the current iteration
std::string addStr = content;
while (true)
{
size_t pos2 = addStr.find("@shIterator");
if (pos2 == std::string::npos)
break;
// optional offset parameter.
size_t openBracePos = pos2 + std::string("@shIterator").length();
if (addStr[openBracePos] == '(')
{
// get the argument for parsing
size_t _start = openBracePos;
size_t _end = _start;
int _brace_depth = 1;
while (_brace_depth > 0)
{
++_end;
if (addStr[_end] == '(')
++_brace_depth;
else if (addStr[_end] == ')')
--_brace_depth;
}
std::string arg = addStr.substr(_start+1, _end-(_start+1));
parse(arg, properties);
int offset = boost::lexical_cast<int> (arg);
addStr.replace(pos2, (_end+1)-pos2, boost::lexical_cast<std::string>(i+offset));
}
else
{
addStr.replace(pos2, std::string("@shIterator").length(), boost::lexical_cast<std::string>(i));
}
}
replaceStr += addStr;
}
source.replace(pos, (block_end+std::string("@shEndForeach").length())-pos, replaceStr);
}
else if (source.size() > pos+1)
++pos; // skip
}
}
ShaderInstance::ShaderInstance (ShaderSet* parent, const std::string& name, PropertySetGet* properties)
: mName(name)
, mParent(parent)
, mSupported(true)
, mCurrentPassthrough(0)
, mCurrentComponent(0)
{
std::string source = mParent->getSource();
int type = mParent->getType();
std::string basePath = mParent->getBasePath();
size_t pos;
bool readCache = Factory::getInstance ().getReadSourceCache () && boost::filesystem::exists(
Factory::getInstance ().getCacheFolder () + "/" + mName);
bool writeCache = Factory::getInstance ().getWriteSourceCache ();
if (readCache)
{
std::ifstream ifs( std::string(Factory::getInstance ().getCacheFolder () + "/" + mName).c_str() );
std::stringstream ss;
ss << ifs.rdbuf();
source = ss.str();
}
else
{
std::vector<std::string> definitions;
if (mParent->getType() == GPT_Vertex)
definitions.push_back("SH_VERTEX_SHADER");
else
definitions.push_back("SH_FRAGMENT_SHADER");
definitions.push_back(convertLang(Factory::getInstance().getCurrentLanguage()));
parse(source, properties);
if (Factory::getInstance ().getShaderDebugOutputEnabled ())
writeDebugFile(source, name + ".pre");
// why do we need our own preprocessor? there are several custom commands available in the shader files
// (for example for binding uniforms to properties or auto constants) - more below. it is important that these
// commands are _only executed if the specific code path actually "survives" the compilation.
// thus, we run the code through a preprocessor first to remove the parts that are unused because of
// unmet #if conditions (or other preprocessor directives).
source = Preprocessor::preprocess(source, basePath, definitions, name);
// parse counter
std::map<int, int> counters;
while (true)
{
pos = source.find("@shCounter");
if (pos == std::string::npos)
break;
size_t end = source.find(")", pos);
std::vector<std::string> args = extractMacroArguments (pos, source);
assert(args.size());
int index = boost::lexical_cast<int>(args[0]);
if (counters.find(index) == counters.end())
counters[index] = 0;
source.replace(pos, (end+1)-pos, boost::lexical_cast<std::string>(counters[index]++));
}
// parse passthrough declarations
while (true)
{
pos = source.find("@shAllocatePassthrough");
if (pos == std::string::npos)
break;
if (mCurrentPassthrough > 7)
throw std::runtime_error ("too many passthrough's requested (max 8)");
std::vector<std::string> args = extractMacroArguments (pos, source);
assert(args.size() == 2);
size_t end = source.find(")", pos);
Passthrough passthrough;
passthrough.num_components = boost::lexical_cast<int>(args[0]);
assert (passthrough.num_components != 0);
std::string passthroughName = args[1];
passthrough.lang = Factory::getInstance().getCurrentLanguage ();
passthrough.component_start = mCurrentComponent;
passthrough.passthrough_number = mCurrentPassthrough;
mPassthroughMap[passthroughName] = passthrough;
mCurrentComponent += passthrough.num_components;
if (mCurrentComponent > 3)
{
mCurrentComponent -= 4;
++mCurrentPassthrough;
}
source.erase(pos, (end+1)-pos);
}
// passthrough assign
while (true)
{
pos = source.find("@shPassthroughAssign");
if (pos == std::string::npos)
break;
std::vector<std::string> args = extractMacroArguments (pos, source);
assert(args.size() == 2);
size_t end = source.find(")", pos);
std::string passthroughName = args[0];
std::string assignTo = args[1];
assert(mPassthroughMap.find(passthroughName) != mPassthroughMap.end());
Passthrough& p = mPassthroughMap[passthroughName];
source.replace(pos, (end+1)-pos, p.expand_assign(assignTo));
}
// passthrough receive
while (true)
{
pos = source.find("@shPassthroughReceive");
if (pos == std::string::npos)
break;
std::vector<std::string> args = extractMacroArguments (pos, source);
assert(args.size() == 1);
size_t end = source.find(")", pos);
std::string passthroughName = args[0];
assert(mPassthroughMap.find(passthroughName) != mPassthroughMap.end());
Passthrough& p = mPassthroughMap[passthroughName];
source.replace(pos, (end+1)-pos, p.expand_receive());
}
// passthrough vertex outputs
while (true)
{
pos = source.find("@shPassthroughVertexOutputs");
if (pos == std::string::npos)
break;
std::string result;
for (int i = 0; i < mCurrentPassthrough+1; ++i)
{
// not using newlines here, otherwise the line numbers reported by compiler would be messed up..
if (Factory::getInstance().getCurrentLanguage () == Language_CG || Factory::getInstance().getCurrentLanguage () == Language_HLSL)
result += ", out float4 passthrough" + boost::lexical_cast<std::string>(i) + " : TEXCOORD" + boost::lexical_cast<std::string>(i);
/*
else
result += "out vec4 passthrough" + boost::lexical_cast<std::string>(i) + "; ";
*/
else
result += "varying vec4 passthrough" + boost::lexical_cast<std::string>(i) + "; ";
}
source.replace(pos, std::string("@shPassthroughVertexOutputs").length(), result);
}
// passthrough fragment inputs
while (true)
{
pos = source.find("@shPassthroughFragmentInputs");
if (pos == std::string::npos)
break;
std::string result;
for (int i = 0; i < mCurrentPassthrough+1; ++i)
{
// not using newlines here, otherwise the line numbers reported by compiler would be messed up..
if (Factory::getInstance().getCurrentLanguage () == Language_CG || Factory::getInstance().getCurrentLanguage () == Language_HLSL)
result += ", in float4 passthrough" + boost::lexical_cast<std::string>(i) + " : TEXCOORD" + boost::lexical_cast<std::string>(i);
/*
else
result += "in vec4 passthrough" + boost::lexical_cast<std::string>(i) + "; ";
*/
else
result += "varying vec4 passthrough" + boost::lexical_cast<std::string>(i) + "; ";
}
source.replace(pos, std::string("@shPassthroughFragmentInputs").length(), result);
}
}
// save to cache _here_ - we want to preserve some macros
if (writeCache && !readCache)
{
std::ofstream of (std::string(Factory::getInstance ().getCacheFolder () + "/" + mName).c_str(), std::ios_base::out);
of.write(source.c_str(), source.size());
of.close();
}
// parse shared parameters
while (true)
{
pos = source.find("@shSharedParameter");
if (pos == std::string::npos)
break;
std::vector<std::string> args = extractMacroArguments (pos, source);
assert(args.size());
size_t end = source.find(")", pos);
mSharedParameters.push_back(args[0]);
source.erase(pos, (end+1)-pos);
}
// parse auto constants
typedef std::map< std::string, std::pair<std::string, std::string> > AutoConstantMap;
AutoConstantMap autoConstants;
while (true)
{
pos = source.find("@shAutoConstant");
if (pos == std::string::npos)
break;
std::vector<std::string> args = extractMacroArguments (pos, source);
assert(args.size() >= 2);
size_t end = source.find(")", pos);
std::string autoConstantName, uniformName;
std::string extraData;
uniformName = args[0];
autoConstantName = args[1];
if (args.size() > 2)
extraData = args[2];
autoConstants[uniformName] = std::make_pair(autoConstantName, extraData);
source.erase(pos, (end+1)-pos);
}
// parse uniform properties
while (true)
{
pos = source.find("@shUniformProperty");
if (pos == std::string::npos)
break;
std::vector<std::string> args = extractMacroArguments (pos, source);
assert(args.size() == 2);
size_t start = source.find("(", pos);
size_t end = source.find(")", pos);
std::string cmd = source.substr(pos, start-pos);
ValueType vt;
if (cmd == "@shUniformProperty4f")
vt = VT_Vector4;
else if (cmd == "@shUniformProperty3f")
vt = VT_Vector3;
else if (cmd == "@shUniformProperty2f")
vt = VT_Vector2;
else if (cmd == "@shUniformProperty1f")
vt = VT_Float;
else if (cmd == "@shUniformPropertyInt")
vt = VT_Int;
else
throw std::runtime_error ("unsupported command \"" + cmd + "\"");
std::string propertyName, uniformName;
uniformName = args[0];
propertyName = args[1];
mUniformProperties[uniformName] = std::make_pair(propertyName, vt);
source.erase(pos, (end+1)-pos);
}
// parse texture samplers used
while (true)
{
pos = source.find("@shUseSampler");
if (pos == std::string::npos)
break;
size_t end = source.find(")", pos);
mUsedSamplers.push_back(extractMacroArguments (pos, source)[0]);
source.erase(pos, (end+1)-pos);
}
// convert any left-over @'s to #
boost::algorithm::replace_all(source, "@", "#");
Platform* platform = Factory::getInstance().getPlatform();
std::string profile;
if (Factory::getInstance ().getCurrentLanguage () == Language_CG)
profile = mParent->getCgProfile ();
else if (Factory::getInstance ().getCurrentLanguage () == Language_HLSL)
profile = mParent->getHlslProfile ();
if (type == GPT_Vertex)
mProgram = boost::shared_ptr<GpuProgram>(platform->createGpuProgram(GPT_Vertex, "", mName, profile, source, Factory::getInstance().getCurrentLanguage()));
else if (type == GPT_Fragment)
mProgram = boost::shared_ptr<GpuProgram>(platform->createGpuProgram(GPT_Fragment, "", mName, profile, source, Factory::getInstance().getCurrentLanguage()));
if (Factory::getInstance ().getShaderDebugOutputEnabled ())
writeDebugFile(source, name);
if (!mProgram->getSupported())
{
std::cerr << " Full source code below: \n" << source << std::endl;
mSupported = false;
return;
}
// set auto constants
for (AutoConstantMap::iterator it = autoConstants.begin(); it != autoConstants.end(); ++it)
{
mProgram->setAutoConstant(it->first, it->second.first, it->second.second);
}
}
std::string ShaderInstance::getName ()
{
return mName;
}
bool ShaderInstance::getSupported () const
{
return mSupported;
}
std::vector<std::string> ShaderInstance::getUsedSamplers()
{
return mUsedSamplers;
}
void ShaderInstance::setUniformParameters (boost::shared_ptr<Pass> pass, PropertySetGet* properties)
{
for (UniformMap::iterator it = mUniformProperties.begin(); it != mUniformProperties.end(); ++it)
{
pass->setGpuConstant(mParent->getType(), it->first, it->second.second, properties->getProperty(it->second.first), properties->getContext());
}
}
std::vector<std::string> ShaderInstance::extractMacroArguments (size_t pos, const std::string& source)
{
size_t start = source.find("(", pos);
size_t end = source.find(")", pos);
std::string args = source.substr(start+1, end-(start+1));
std::vector<std::string> results;
boost::algorithm::split(results, args, boost::is_any_of(","));
std::for_each(results.begin(), results.end(),
boost::bind(&boost::trim<std::string>,
_1, std::locale() ));
return results;
}
}

@ -1,71 +0,0 @@
#ifndef SH_SHADERINSTANCE_H
#define SH_SHADERINSTANCE_H
#include <vector>
#include "Platform.hpp"
namespace sh
{
class ShaderSet;
typedef std::map< std::string, std::pair<std::string, ValueType > > UniformMap;
struct Passthrough
{
Language lang; ///< language to generate for
int num_components; ///< e.g. 4 for a float4
int passthrough_number;
int component_start; ///< 0 = x
std::string expand_assign(std::string assignTo);
std::string expand_receive();
};
typedef std::map<std::string, Passthrough> PassthroughMap;
/**
* @brief A specific instance of a \a ShaderSet with a deterministic shader source
*/
class ShaderInstance
{
public:
ShaderInstance (ShaderSet* parent, const std::string& name, PropertySetGet* properties);
std::string getName();
bool getSupported () const;
std::vector<std::string> getUsedSamplers();
std::vector<std::string> getSharedParameters() { return mSharedParameters; }
void setUniformParameters (boost::shared_ptr<Pass> pass, PropertySetGet* properties);
private:
boost::shared_ptr<GpuProgram> mProgram;
std::string mName;
ShaderSet* mParent;
bool mSupported; ///< shader compilation was sucessful?
std::vector<std::string> mUsedSamplers;
///< names of the texture samplers that are used by this shader
std::vector<std::string> mSharedParameters;
UniformMap mUniformProperties;
///< uniforms that this depends on, and their property names / value-types
/// @note this lists shared uniform parameters as well
int mCurrentPassthrough; ///< 0 - x
int mCurrentComponent; ///< 0:x, 1:y, 2:z, 3:w
PassthroughMap mPassthroughMap;
std::vector<std::string> extractMacroArguments (size_t pos, const std::string& source); ///< take a macro invocation and return vector of arguments
void parse (std::string& source, PropertySetGet* properties);
};
}
#endif

@ -1,195 +0,0 @@
#include "ShaderSet.hpp"
#include <fstream>
#include <sstream>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/functional/hash.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/filesystem.hpp>
#include "Factory.hpp"
namespace sh
{
ShaderSet::ShaderSet (const std::string& type, const std::string& cgProfile, const std::string& hlslProfile, const std::string& sourceFile, const std::string& basePath,
const std::string& name, PropertySetGet* globalSettingsPtr)
: mBasePath(basePath)
, mName(name)
, mCgProfile(cgProfile)
, mHlslProfile(hlslProfile)
{
if (type == "vertex")
mType = GPT_Vertex;
else // if (type == "fragment")
mType = GPT_Fragment;
std::ifstream stream(sourceFile.c_str(), std::ifstream::in);
std::stringstream buffer;
boost::filesystem::path p (sourceFile);
p = p.branch_path();
mBasePath = p.string();
buffer << stream.rdbuf();
stream.close();
mSource = buffer.str();
parse();
}
ShaderSet::~ShaderSet()
{
for (ShaderInstanceMap::iterator it = mInstances.begin(); it != mInstances.end(); ++it)
{
sh::Factory::getInstance().getPlatform()->destroyGpuProgram(it->second.getName());
}
}
void ShaderSet::parse()
{
std::string currentToken;
bool tokenIsRecognized = false;
bool isInBraces = false;
for (std::string::const_iterator it = mSource.begin(); it != mSource.end(); ++it)
{
char c = *it;
if (((c == ' ') && !isInBraces) || (c == '\n') ||
( ((c == '(') || (c == ')'))
&& !tokenIsRecognized))
{
if (tokenIsRecognized)
{
if (boost::starts_with(currentToken, "@shGlobalSetting"))
{
assert ((currentToken.find('(') != std::string::npos) && (currentToken.find(')') != std::string::npos));
size_t start = currentToken.find('(')+1;
mGlobalSettings.push_back(currentToken.substr(start, currentToken.find(')')-start));
}
else if (boost::starts_with(currentToken, "@shPropertyHasValue"))
{
assert ((currentToken.find('(') != std::string::npos) && (currentToken.find(')') != std::string::npos));
size_t start = currentToken.find('(')+1;
mPropertiesToExist.push_back(currentToken.substr(start, currentToken.find(')')-start));
}
else if (boost::starts_with(currentToken, "@shPropertyEqual"))
{
assert ((currentToken.find('(') != std::string::npos) && (currentToken.find(')') != std::string::npos)
&& (currentToken.find(',') != std::string::npos));
size_t start = currentToken.find('(')+1;
size_t end = currentToken.find(',');
mProperties.push_back(currentToken.substr(start, end-start));
}
else if (boost::starts_with(currentToken, "@shProperty"))
{
assert ((currentToken.find('(') != std::string::npos) && (currentToken.find(')') != std::string::npos));
size_t start = currentToken.find('(')+1;
std::string propertyName = currentToken.substr(start, currentToken.find(')')-start);
// if the property name is constructed dynamically (e.g. through an iterator) then there is nothing we can do
if (propertyName.find("@") == std::string::npos)
mProperties.push_back(propertyName);
}
}
currentToken = "";
}
else
{
if (currentToken == "")
{
if (c == '@')
tokenIsRecognized = true;
else
tokenIsRecognized = false;
}
else
{
if (c == '@')
{
// ouch, there are nested macros
// ( for example @shForeach(@shPropertyString(foobar)) )
currentToken = "";
}
}
if (c == '(' && tokenIsRecognized)
isInBraces = true;
else if (c == ')' && tokenIsRecognized)
isInBraces = false;
currentToken += c;
}
}
}
ShaderInstance* ShaderSet::getInstance (PropertySetGet* properties)
{
size_t h = buildHash (properties);
if (std::find(mFailedToCompile.begin(), mFailedToCompile.end(), h) != mFailedToCompile.end())
return NULL;
if (mInstances.find(h) == mInstances.end())
{
ShaderInstance newInstance(this, mName + "_" + boost::lexical_cast<std::string>(h), properties);
if (!newInstance.getSupported())
{
mFailedToCompile.push_back(h);
return NULL;
}
mInstances.insert(std::make_pair(h, newInstance));
}
return &mInstances.find(h)->second;
}
size_t ShaderSet::buildHash (PropertySetGet* properties)
{
size_t seed = 0;
PropertySetGet* currentGlobalSettings = getCurrentGlobalSettings ();
for (std::vector<std::string>::iterator it = mProperties.begin(); it != mProperties.end(); ++it)
{
std::string v = retrieveValue<StringValue>(properties->getProperty(*it), properties->getContext()).get();
boost::hash_combine(seed, v);
}
for (std::vector <std::string>::iterator it = mGlobalSettings.begin(); it != mGlobalSettings.end(); ++it)
{
boost::hash_combine(seed, retrieveValue<StringValue>(currentGlobalSettings->getProperty(*it), NULL).get());
}
for (std::vector<std::string>::iterator it = mPropertiesToExist.begin(); it != mPropertiesToExist.end(); ++it)
{
std::string v = retrieveValue<StringValue>(properties->getProperty(*it), properties->getContext()).get();
boost::hash_combine(seed, static_cast<bool>(v != ""));
}
boost::hash_combine(seed, static_cast<int>(Factory::getInstance().getCurrentLanguage()));
return seed;
}
PropertySetGet* ShaderSet::getCurrentGlobalSettings() const
{
return Factory::getInstance ().getCurrentGlobalSettings ();
}
std::string ShaderSet::getBasePath() const
{
return mBasePath;
}
std::string ShaderSet::getSource() const
{
return mSource;
}
std::string ShaderSet::getCgProfile() const
{
return mCgProfile;
}
std::string ShaderSet::getHlslProfile() const
{
return mHlslProfile;
}
int ShaderSet::getType() const
{
return mType;
}
}

@ -1,69 +0,0 @@
#ifndef SH_SHADERSET_H
#define SH_SHADERSET_H
#include <string>
#include <vector>
#include <map>
#include "ShaderInstance.hpp"
namespace sh
{
class PropertySetGet;
typedef std::map<size_t, ShaderInstance> ShaderInstanceMap;
/**
* @brief Contains possible shader permutations of a single uber-shader (represented by one source file)
*/
class ShaderSet
{
public:
ShaderSet (const std::string& type, const std::string& cgProfile, const std::string& hlslProfile, const std::string& sourceFile, const std::string& basePath,
const std::string& name, PropertySetGet* globalSettingsPtr);
~ShaderSet();
/// Retrieve a shader instance for the given properties. \n
/// If a \a ShaderInstance with the same properties exists already, simply returns this instance. \n
/// Otherwise, creates a new \a ShaderInstance (i.e. compiles a new shader). \n
/// Might also return NULL if the shader failed to compile. \n
/// @note Only the properties that actually affect the shader source are taken into consideration here,
/// so it does not matter if you pass any extra properties that the shader does not care about.
ShaderInstance* getInstance (PropertySetGet* properties);
private:
PropertySetGet* getCurrentGlobalSettings() const;
std::string getBasePath() const;
std::string getSource() const;
std::string getCgProfile() const;
std::string getHlslProfile() const;
int getType() const;
friend class ShaderInstance;
private:
GpuProgramType mType;
std::string mSource;
std::string mBasePath;
std::string mCgProfile;
std::string mHlslProfile;
std::string mName;
std::vector <size_t> mFailedToCompile;
std::vector <std::string> mGlobalSettings; ///< names of the global settings that affect the shader source
std::vector <std::string> mProperties; ///< names of the per-material properties that affect the shader source
std::vector <std::string> mPropertiesToExist;
///< same as mProperties, however in this case, it is only relevant if the property is empty or not
/// (we don't care about the value)
ShaderInstanceMap mInstances; ///< maps permutation ID (generated from the properties) to \a ShaderInstance
void parse(); ///< find out which properties and global settings affect the shader source
size_t buildHash (PropertySetGet* properties);
};
}
#endif

@ -1,69 +0,0 @@
#include <stdexcept>
#include "OgreGpuProgram.hpp"
#include <boost/lexical_cast.hpp>
#include <OgreHighLevelGpuProgramManager.h>
#include <OgreGpuProgramManager.h>
#include <OgreVector4.h>
namespace sh
{
OgreGpuProgram::OgreGpuProgram(
GpuProgramType type,
const std::string& compileArguments,
const std::string& name, const std::string& profile,
const std::string& source, const std::string& lang,
const std::string& resourceGroup)
: GpuProgram()
{
Ogre::HighLevelGpuProgramManager& mgr = Ogre::HighLevelGpuProgramManager::getSingleton();
assert (mgr.getByName(name).isNull() && "Vertex program already exists");
Ogre::GpuProgramType t;
if (type == GPT_Vertex)
t = Ogre::GPT_VERTEX_PROGRAM;
else
t = Ogre::GPT_FRAGMENT_PROGRAM;
mProgram = mgr.createProgram(name, resourceGroup, lang, t);
if (lang != "glsl" && lang != "glsles")
mProgram->setParameter("entry_point", "main");
if (lang == "hlsl")
mProgram->setParameter("target", profile);
else if (lang == "cg")
mProgram->setParameter("profiles", profile);
mProgram->setSource(source);
mProgram->load();
if (mProgram.isNull() || !mProgram->isSupported())
std::cerr << "Failed to compile shader \"" << name << "\". Consider the OGRE log for more information." << std::endl;
}
bool OgreGpuProgram::getSupported()
{
return (!mProgram.isNull() && mProgram->isSupported());
}
void OgreGpuProgram::setAutoConstant (const std::string& name, const std::string& autoConstantName, const std::string& extraInfo)
{
assert (!mProgram.isNull() && mProgram->isSupported());
const Ogre::GpuProgramParameters::AutoConstantDefinition* d = Ogre::GpuProgramParameters::getAutoConstantDefinition(autoConstantName);
if (!d)
throw std::runtime_error ("can't find auto constant with name \"" + autoConstantName + "\"");
Ogre::GpuProgramParameters::AutoConstantType t = d->acType;
// this simplifies debugging for CG a lot.
mProgram->getDefaultParameters()->setIgnoreMissingParams(true);
if (d->dataType == Ogre::GpuProgramParameters::ACDT_NONE)
mProgram->getDefaultParameters()->setNamedAutoConstant (name, t, 0);
else if (d->dataType == Ogre::GpuProgramParameters::ACDT_INT)
mProgram->getDefaultParameters()->setNamedAutoConstant (name, t, extraInfo == "" ? 0 : boost::lexical_cast<int>(extraInfo));
else if (d->dataType == Ogre::GpuProgramParameters::ACDT_REAL)
mProgram->getDefaultParameters()->setNamedAutoConstantReal (name, t, extraInfo == "" ? 0.f : boost::lexical_cast<float>(extraInfo));
}
}

@ -1,31 +0,0 @@
#ifndef SH_OGREGPUPROGRAM_H
#define SH_OGREGPUPROGRAM_H
#include <string>
#include <OgreHighLevelGpuProgram.h>
#include "../../Main/Platform.hpp"
namespace sh
{
class OgreGpuProgram : public GpuProgram
{
public:
OgreGpuProgram (
GpuProgramType type,
const std::string& compileArguments,
const std::string& name, const std::string& profile,
const std::string& source, const std::string& lang,
const std::string& resourceGroup);
virtual bool getSupported();
virtual void setAutoConstant (const std::string& name, const std::string& autoConstantName, const std::string& extraInfo = "");
private:
Ogre::HighLevelGpuProgramPtr mProgram;
};
}
#endif

@ -1,120 +0,0 @@
#include "OgreMaterial.hpp"
#include <OgreMaterialManager.h>
#include <OgreTechnique.h>
#include <stdexcept>
#include "OgrePass.hpp"
#include "OgreMaterialSerializer.hpp"
#include "OgrePlatform.hpp"
namespace sh
{
static const std::string sDefaultTechniqueName = "SH_DefaultTechnique";
OgreMaterial::OgreMaterial (const std::string& name, const std::string& resourceGroup)
: Material()
{
mName = name;
assert (Ogre::MaterialManager::getSingleton().getByName(name).isNull() && "Material already exists");
mMaterial = Ogre::MaterialManager::getSingleton().create (name, resourceGroup);
mMaterial->removeAllTechniques();
mMaterial->createTechnique()->setSchemeName (sDefaultTechniqueName);
mMaterial->compile();
}
void OgreMaterial::ensureLoaded()
{
if (mMaterial.isNull())
mMaterial = Ogre::MaterialManager::getSingleton().getByName(mName);
}
bool OgreMaterial::isUnreferenced()
{
// Resource system internals hold 3 shared pointers, we hold one, so usecount of 4 means unused
return (!mMaterial.isNull() && mMaterial.useCount() <= Ogre::ResourceGroupManager::RESOURCE_SYSTEM_NUM_REFERENCE_COUNTS+1);
}
void OgreMaterial::unreferenceTextures()
{
mMaterial->unload();
}
OgreMaterial::~OgreMaterial()
{
if (!mMaterial.isNull())
Ogre::MaterialManager::getSingleton().remove(mMaterial->getName());
}
boost::shared_ptr<Pass> OgreMaterial::createPass (const std::string& configuration, unsigned short lodIndex)
{
return boost::shared_ptr<Pass> (new OgrePass (this, configuration, lodIndex));
}
void OgreMaterial::removeAll ()
{
if (mMaterial.isNull())
return;
mMaterial->removeAllTechniques();
mMaterial->createTechnique()->setSchemeName (sDefaultTechniqueName);
mMaterial->compile();
}
void OgreMaterial::setLodLevels (const std::string& lodLevels)
{
OgreMaterialSerializer& s = OgrePlatform::getSerializer();
s.setMaterialProperty ("lod_values", lodLevels, mMaterial);
}
bool OgreMaterial::createConfiguration (const std::string& name, unsigned short lodIndex)
{
for (int i=0; i<mMaterial->getNumTechniques(); ++i)
{
if (mMaterial->getTechnique(i)->getSchemeName() == name && mMaterial->getTechnique(i)->getLodIndex() == lodIndex)
return false;
}
Ogre::Technique* t = mMaterial->createTechnique();
t->setSchemeName (name);
t->setLodIndex (lodIndex);
if (mShadowCasterMaterial != "")
t->setShadowCasterMaterial(mShadowCasterMaterial);
mMaterial->compile();
return true;
}
Ogre::MaterialPtr OgreMaterial::getOgreMaterial ()
{
return mMaterial;
}
Ogre::Technique* OgreMaterial::getOgreTechniqueForConfiguration (const std::string& configurationName, unsigned short lodIndex)
{
for (int i=0; i<mMaterial->getNumTechniques(); ++i)
{
if (mMaterial->getTechnique(i)->getSchemeName() == configurationName && mMaterial->getTechnique(i)->getLodIndex() == lodIndex)
{
return mMaterial->getTechnique(i);
}
}
// Prepare and throw error message
std::stringstream message;
message << "Could not find configurationName '" << configurationName
<< "' and lodIndex " << lodIndex;
throw std::runtime_error(message.str());
}
void OgreMaterial::setShadowCasterMaterial (const std::string& name)
{
mShadowCasterMaterial = name;
for (int i=0; i<mMaterial->getNumTechniques(); ++i)
{
mMaterial->getTechnique(i)->setShadowCasterMaterial(mShadowCasterMaterial);
}
}
}

@ -1,43 +0,0 @@
#ifndef SH_OGREMATERIAL_H
#define SH_OGREMATERIAL_H
#include <string>
#include <OgreMaterial.h>
#include "../../Main/Platform.hpp"
namespace sh
{
class OgreMaterial : public Material
{
public:
OgreMaterial (const std::string& name, const std::string& resourceGroup);
virtual ~OgreMaterial();
virtual boost::shared_ptr<Pass> createPass (const std::string& configuration, unsigned short lodIndex);
virtual bool createConfiguration (const std::string& name, unsigned short lodIndex);
virtual bool isUnreferenced();
virtual void unreferenceTextures();
virtual void ensureLoaded();
virtual void removeAll ();
Ogre::MaterialPtr getOgreMaterial();
virtual void setLodLevels (const std::string& lodLevels);
Ogre::Technique* getOgreTechniqueForConfiguration (const std::string& configurationName, unsigned short lodIndex = 0);
virtual void setShadowCasterMaterial (const std::string& name);
private:
Ogre::MaterialPtr mMaterial;
std::string mName;
std::string mShadowCasterMaterial;
};
}
#endif

@ -1,85 +0,0 @@
#include "OgreMaterialSerializer.hpp"
#include <OgrePass.h>
#include <OgreStringConverter.h>
namespace sh
{
void OgreMaterialSerializer::reset()
{
mScriptContext.section = Ogre::MSS_NONE;
mScriptContext.material.setNull();
mScriptContext.technique = 0;
mScriptContext.pass = 0;
mScriptContext.textureUnit = 0;
mScriptContext.program.setNull();
mScriptContext.lineNo = 0;
mScriptContext.filename.clear();
mScriptContext.techLev = -1;
mScriptContext.passLev = -1;
mScriptContext.stateLev = -1;
}
bool OgreMaterialSerializer::setPassProperty (const std::string& param, std::string value, Ogre::Pass* pass)
{
// workaround https://ogre3d.atlassian.net/browse/OGRE-158
if (param == "transparent_sorting" && value == "force")
{
pass->setTransparentSortingForced(true);
return true;
}
reset();
mScriptContext.section = Ogre::MSS_PASS;
mScriptContext.pass = pass;
if (mPassAttribParsers.find (param) == mPassAttribParsers.end())
return false;
else
{
mPassAttribParsers.find(param)->second(value, mScriptContext);
return true;
}
}
bool OgreMaterialSerializer::setTextureUnitProperty (const std::string& param, std::string value, Ogre::TextureUnitState* t)
{
// quick access to automip setting, without having to use 'texture' which doesn't like spaces in filenames
if (param == "num_mipmaps")
{
t->setNumMipmaps(Ogre::StringConverter::parseInt(value));
return true;
}
reset();
mScriptContext.section = Ogre::MSS_TEXTUREUNIT;
mScriptContext.textureUnit = t;
if (mTextureUnitAttribParsers.find (param) == mTextureUnitAttribParsers.end())
return false;
else
{
mTextureUnitAttribParsers.find(param)->second(value, mScriptContext);
return true;
}
}
bool OgreMaterialSerializer::setMaterialProperty (const std::string& param, std::string value, Ogre::MaterialPtr m)
{
reset();
mScriptContext.section = Ogre::MSS_MATERIAL;
mScriptContext.material = m;
if (mMaterialAttribParsers.find (param) == mMaterialAttribParsers.end())
return false;
else
{
mMaterialAttribParsers.find(param)->second(value, mScriptContext);
return true;
}
}
}

@ -1,29 +0,0 @@
#ifndef SH_OGREMATERIALSERIALIZER_H
#define SH_OGREMATERIALSERIALIZER_H
#include <OgreMaterialSerializer.h>
namespace Ogre
{
class Pass;
}
namespace sh
{
/**
* @brief This class allows me to let Ogre handle the pass & texture unit properties
*/
class OgreMaterialSerializer : public Ogre::MaterialSerializer
{
public:
bool setPassProperty (const std::string& param, std::string value, Ogre::Pass* pass);
bool setTextureUnitProperty (const std::string& param, std::string value, Ogre::TextureUnitState* t);
bool setMaterialProperty (const std::string& param, std::string value, Ogre::MaterialPtr m);
private:
void reset();
};
}
#endif

@ -1,131 +0,0 @@
#include <stdexcept>
#include "OgrePass.hpp"
#include <OgrePass.h>
#include <OgreTechnique.h>
#include "OgreTextureUnitState.hpp"
#include "OgreGpuProgram.hpp"
#include "OgreMaterial.hpp"
#include "OgreMaterialSerializer.hpp"
#include "OgrePlatform.hpp"
namespace sh
{
OgrePass::OgrePass (OgreMaterial* parent, const std::string& configuration, unsigned short lodIndex)
: Pass()
{
Ogre::Technique* t = parent->getOgreTechniqueForConfiguration(configuration, lodIndex);
mPass = t->createPass();
}
boost::shared_ptr<TextureUnitState> OgrePass::createTextureUnitState (const std::string& name)
{
return boost::shared_ptr<TextureUnitState> (new OgreTextureUnitState (this, name));
}
void OgrePass::assignProgram (GpuProgramType type, const std::string& name)
{
if (type == GPT_Vertex)
mPass->setVertexProgram (name);
else if (type == GPT_Fragment)
mPass->setFragmentProgram (name);
else
throw std::runtime_error("unsupported GpuProgramType");
}
Ogre::Pass* OgrePass::getOgrePass ()
{
return mPass;
}
bool OgrePass::setPropertyOverride (const std::string &name, PropertyValuePtr& value, PropertySetGet* context)
{
if (((typeid(*value) == typeid(StringValue)) || typeid(*value) == typeid(LinkedValue))
&& retrieveValue<StringValue>(value, context).get() == "default")
return true;
if (name == "vertex_program")
return true; // handled already
else if (name == "fragment_program")
return true; // handled already
else
{
OgreMaterialSerializer& s = OgrePlatform::getSerializer();
return s.setPassProperty (name, retrieveValue<StringValue>(value, context).get(), mPass);
}
}
void OgrePass::setGpuConstant (int type, const std::string& name, ValueType vt, PropertyValuePtr value, PropertySetGet* context)
{
Ogre::GpuProgramParametersSharedPtr params;
if (type == GPT_Vertex)
{
if (!mPass->hasVertexProgram ())
return;
params = mPass->getVertexProgramParameters();
}
else if (type == GPT_Fragment)
{
if (!mPass->hasFragmentProgram ())
return;
params = mPass->getFragmentProgramParameters();
}
if (vt == VT_Float)
params->setNamedConstant (name, retrieveValue<FloatValue>(value, context).get());
else if (vt == VT_Int)
params->setNamedConstant (name, retrieveValue<IntValue>(value, context).get());
else if (vt == VT_Vector4)
{
Vector4 v = retrieveValue<Vector4>(value, context);
params->setNamedConstant (name, Ogre::Vector4(v.mX, v.mY, v.mZ, v.mW));
}
else if (vt == VT_Vector3)
{
Vector3 v = retrieveValue<Vector3>(value, context);
params->setNamedConstant (name, Ogre::Vector4(v.mX, v.mY, v.mZ, 1.0));
}
else if (vt == VT_Vector2)
{
Vector2 v = retrieveValue<Vector2>(value, context);
params->setNamedConstant (name, Ogre::Vector4(v.mX, v.mY, 1.0, 1.0));
}
else
throw std::runtime_error ("unsupported constant type");
}
void OgrePass::addSharedParameter (int type, const std::string& name)
{
Ogre::GpuProgramParametersSharedPtr params;
if (type == GPT_Vertex)
params = mPass->getVertexProgramParameters();
else if (type == GPT_Fragment)
params = mPass->getFragmentProgramParameters();
try
{
params->addSharedParameters (name);
}
catch (Ogre::Exception& )
{
std::stringstream msg;
msg << "Could not create a shared parameter instance for '"
<< name << "'. Make sure this shared parameter has a value set (via Factory::setSharedParameter)!";
throw std::runtime_error(msg.str());
}
}
void OgrePass::setTextureUnitIndex (int programType, const std::string& name, int index)
{
Ogre::GpuProgramParametersSharedPtr params;
if (programType == GPT_Vertex)
params = mPass->getVertexProgramParameters();
else if (programType == GPT_Fragment)
params = mPass->getFragmentProgramParameters();
params->setNamedConstant(name, index);
}
}

@ -1,35 +0,0 @@
#ifndef SH_OGREPASS_H
#define SH_OGREPASS_H
#include <OgrePass.h>
#include "../../Main/Platform.hpp"
namespace sh
{
class OgreMaterial;
class OgrePass : public Pass
{
public:
OgrePass (OgreMaterial* parent, const std::string& configuration, unsigned short lodIndex);
virtual boost::shared_ptr<TextureUnitState> createTextureUnitState (const std::string& name);
virtual void assignProgram (GpuProgramType type, const std::string& name);
Ogre::Pass* getOgrePass();
virtual void setGpuConstant (int type, const std::string& name, ValueType vt, PropertyValuePtr value, PropertySetGet* context);
virtual void addSharedParameter (int type, const std::string& name);
virtual void setTextureUnitIndex (int programType, const std::string& name, int index);
private:
Ogre::Pass* mPass;
protected:
virtual bool setPropertyOverride (const std::string &name, PropertyValuePtr& value, PropertySetGet* context);
};
}
#endif

@ -1,193 +0,0 @@
#include <stdexcept>
#include "OgrePlatform.hpp"
#include <OgreDataStream.h>
#include <OgreGpuProgramManager.h>
#include <OgreHighLevelGpuProgramManager.h>
#include <OgreRoot.h>
#include "OgreMaterial.hpp"
#include "OgreGpuProgram.hpp"
#include "OgreMaterialSerializer.hpp"
#include "../../Main/MaterialInstance.hpp"
#include "../../Main/Factory.hpp"
namespace
{
std::string convertLang (sh::Language lang)
{
if (lang == sh::Language_CG)
return "cg";
else if (lang == sh::Language_HLSL)
return "hlsl";
else if (lang == sh::Language_GLSL)
return "glsl";
else if (lang == sh::Language_GLSLES)
return "glsles";
throw std::runtime_error ("invalid language, valid are: cg, hlsl, glsl, glsles");
}
}
namespace sh
{
OgreMaterialSerializer* OgrePlatform::sSerializer = 0;
OgrePlatform::OgrePlatform(const std::string& resourceGroupName, const std::string& basePath)
: Platform(basePath)
, mResourceGroup(resourceGroupName)
{
Ogre::MaterialManager::getSingleton().addListener(this);
if (supportsShaderSerialization())
Ogre::GpuProgramManager::getSingletonPtr()->setSaveMicrocodesToCache(true);
sSerializer = new OgreMaterialSerializer();
}
OgreMaterialSerializer& OgrePlatform::getSerializer()
{
assert(sSerializer);
return *sSerializer;
}
OgrePlatform::~OgrePlatform ()
{
Ogre::MaterialManager::getSingleton().removeListener(this);
delete sSerializer;
}
bool OgrePlatform::isProfileSupported (const std::string& profile)
{
return Ogre::GpuProgramManager::getSingleton().isSyntaxSupported(profile);
}
bool OgrePlatform::supportsShaderSerialization ()
{
#if OGRE_VERSION >= (1 << 16 | 9 << 8 | 0)
return true;
#else
return Ogre::Root::getSingleton ().getRenderSystem ()->getName ().find("OpenGL") == std::string::npos;
#endif
}
bool OgrePlatform::supportsMaterialQueuedListener ()
{
return true;
}
boost::shared_ptr<Material> OgrePlatform::createMaterial (const std::string& name)
{
OgreMaterial* material = new OgreMaterial(name, mResourceGroup);
return boost::shared_ptr<Material> (material);
}
void OgrePlatform::destroyGpuProgram(const std::string &name)
{
Ogre::HighLevelGpuProgramManager::getSingleton().remove(name);
}
boost::shared_ptr<GpuProgram> OgrePlatform::createGpuProgram (
GpuProgramType type,
const std::string& compileArguments,
const std::string& name, const std::string& profile,
const std::string& source, Language lang)
{
OgreGpuProgram* prog = new OgreGpuProgram (type, compileArguments, name, profile, source, convertLang(lang), mResourceGroup);
return boost::shared_ptr<GpuProgram> (static_cast<GpuProgram*>(prog));
}
Ogre::Technique* OgrePlatform::handleSchemeNotFound (
unsigned short schemeIndex, const Ogre::String &schemeName, Ogre::Material *originalMaterial,
unsigned short lodIndex, const Ogre::Renderable *rend)
{
MaterialInstance* m = fireMaterialRequested(originalMaterial->getName(), schemeName, lodIndex);
if (m)
{
OgreMaterial* _m = static_cast<OgreMaterial*>(m->getMaterial());
return _m->getOgreTechniqueForConfiguration (schemeName, lodIndex);
}
else
return 0; // material does not belong to us
}
void OgrePlatform::serializeShaders (const std::string& file)
{
#if OGRE_VERSION >= (1 << 16 | 9 << 8 | 0)
if (Ogre::GpuProgramManager::getSingleton().isCacheDirty())
#endif
{
std::fstream output;
output.open(file.c_str(), std::ios::out | std::ios::binary);
Ogre::DataStreamPtr shaderCache (OGRE_NEW Ogre::FileStreamDataStream(file, &output, false));
Ogre::GpuProgramManager::getSingleton().saveMicrocodeCache(shaderCache);
}
}
void OgrePlatform::deserializeShaders (const std::string& file)
{
std::ifstream inp;
inp.open(file.c_str(), std::ios::in | std::ios::binary);
Ogre::DataStreamPtr shaderCache(OGRE_NEW Ogre::FileStreamDataStream(file, &inp, false));
Ogre::GpuProgramManager::getSingleton().loadMicrocodeCache(shaderCache);
}
void OgrePlatform::setSharedParameter (const std::string& name, PropertyValuePtr value)
{
Ogre::GpuSharedParametersPtr params;
if (mSharedParameters.find(name) == mSharedParameters.end())
{
params = Ogre::GpuProgramManager::getSingleton().createSharedParameters(name);
Ogre::GpuConstantType type;
if (typeid(*value) == typeid(Vector4))
type = Ogre::GCT_FLOAT4;
else if (typeid(*value) == typeid(Vector3))
type = Ogre::GCT_FLOAT3;
else if (typeid(*value) == typeid(Vector2))
type = Ogre::GCT_FLOAT2;
else if (typeid(*value) == typeid(FloatValue))
type = Ogre::GCT_FLOAT1;
else if (typeid(*value) == typeid(IntValue))
type = Ogre::GCT_INT1;
else
throw std::runtime_error("unexpected type");
params->addConstantDefinition(name, type);
mSharedParameters[name] = params;
}
else
params = mSharedParameters.find(name)->second;
Ogre::Vector4 v (1.0, 1.0, 1.0, 1.0);
if (typeid(*value) == typeid(Vector4))
{
Vector4 vec = retrieveValue<Vector4>(value, NULL);
v.x = vec.mX;
v.y = vec.mY;
v.z = vec.mZ;
v.w = vec.mW;
}
else if (typeid(*value) == typeid(Vector3))
{
Vector3 vec = retrieveValue<Vector3>(value, NULL);
v.x = vec.mX;
v.y = vec.mY;
v.z = vec.mZ;
}
else if (typeid(*value) == typeid(Vector2))
{
Vector2 vec = retrieveValue<Vector2>(value, NULL);
v.x = vec.mX;
v.y = vec.mY;
}
else if (typeid(*value) == typeid(FloatValue))
v.x = retrieveValue<FloatValue>(value, NULL).get();
else if (typeid(*value) == typeid(IntValue))
v.x = static_cast<float>(retrieveValue<IntValue>(value, NULL).get());
else
throw std::runtime_error ("unsupported property type for shared parameter \"" + name + "\"");
params->setNamedConstant(name, v);
}
}

@ -1,74 +0,0 @@
#ifndef SH_OGREPLATFORM_H
#define SH_OGREPLATFORM_H
/**
* @addtogroup Platforms
* @{
*/
/**
* @addtogroup Ogre
* A set of classes to interact with Ogre's material system
* @{
*/
#include "../../Main/Platform.hpp"
#include <OgreMaterialManager.h>
#include <OgreGpuProgramParams.h>
namespace sh
{
class OgreMaterialSerializer;
class OgrePlatform : public Platform, public Ogre::MaterialManager::Listener
{
public:
OgrePlatform (const std::string& resourceGroupName, const std::string& basePath);
virtual ~OgrePlatform ();
virtual Ogre::Technique* handleSchemeNotFound (
unsigned short schemeIndex, const Ogre::String &schemeName, Ogre::Material *originalMaterial,
unsigned short lodIndex, const Ogre::Renderable *rend);
static OgreMaterialSerializer& getSerializer();
private:
virtual bool isProfileSupported (const std::string& profile);
virtual void serializeShaders (const std::string& file);
virtual void deserializeShaders (const std::string& file);
virtual boost::shared_ptr<Material> createMaterial (const std::string& name);
virtual boost::shared_ptr<GpuProgram> createGpuProgram (
GpuProgramType type,
const std::string& compileArguments,
const std::string& name, const std::string& profile,
const std::string& source, Language lang);
virtual void destroyGpuProgram (const std::string& name);
virtual void setSharedParameter (const std::string& name, PropertyValuePtr value);
friend class ShaderInstance;
friend class Factory;
protected:
virtual bool supportsShaderSerialization ();
virtual bool supportsMaterialQueuedListener ();
std::string mResourceGroup;
static OgreMaterialSerializer* sSerializer;
std::map <std::string, Ogre::GpuSharedParametersPtr> mSharedParameters;
};
}
/**
* @}
* @}
*/
#endif

@ -1,72 +0,0 @@
#include "OgreTextureUnitState.hpp"
#include <iomanip>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include "OgrePass.hpp"
#include "OgrePlatform.hpp"
#include "OgreMaterialSerializer.hpp"
namespace sh
{
OgreTextureUnitState::OgreTextureUnitState (OgrePass* parent, const std::string& name)
: TextureUnitState()
{
mTextureUnitState = parent->getOgrePass()->createTextureUnitState("");
mTextureUnitState->setName(name);
}
bool OgreTextureUnitState::setPropertyOverride (const std::string &name, PropertyValuePtr& value, PropertySetGet* context)
{
OgreMaterialSerializer& s = OgrePlatform::getSerializer();
if (name == "texture_alias")
{
// texture alias in this library refers to something else than in ogre
// delegate up
return TextureUnitState::setPropertyOverride (name, value, context);
}
else if (name == "direct_texture")
{
setTextureName (retrieveValue<StringValue>(value, context).get());
return true;
}
else if (name == "anim_texture2")
{
std::string val = retrieveValue<StringValue>(value, context).get();
std::vector<std::string> tokens;
boost::split(tokens, val, boost::is_any_of(" "));
assert(tokens.size() == 3);
std::string texture = tokens[0];
int frames = boost::lexical_cast<int>(tokens[1]);
float duration = boost::lexical_cast<float>(tokens[2]);
std::vector<Ogre::String> frameTextures;
for (int i=0; i<frames; ++i)
{
std::stringstream stream;
stream << std::setw(2);
stream << std::setfill('0');
stream << i;
stream << '.';
std::string tex = texture;
boost::replace_last(tex, ".", stream.str());
frameTextures.push_back(tex);
}
mTextureUnitState->setAnimatedTextureName(&frameTextures[0], frames, duration);
return true;
}
else if (name == "create_in_ffp")
return true; // handled elsewhere
return s.setTextureUnitProperty (name, retrieveValue<StringValue>(value, context).get(), mTextureUnitState);
}
void OgreTextureUnitState::setTextureName (const std::string& textureName)
{
mTextureUnitState->setTextureName(textureName);
}
}

@ -1,27 +0,0 @@
#ifndef SH_OGRETEXTUREUNITSTATE_H
#define SH_OGRETEXTUREUNITSTATE_H
#include <OgreTextureUnitState.h>
#include "../../Main/Platform.hpp"
namespace sh
{
class OgrePass;
class OgreTextureUnitState : public TextureUnitState
{
public:
OgreTextureUnitState (OgrePass* parent, const std::string& name);
virtual void setTextureName (const std::string& textureName);
private:
Ogre::TextureUnitState* mTextureUnitState;
protected:
virtual bool setPropertyOverride (const std::string &name, PropertyValuePtr& value, PropertySetGet* context);
};
}
#endif

@ -1,33 +0,0 @@
shiny - a shader and material management library for OGRE
FEATURES
- High-level layer on top of OGRE's material system. It allows you to generate multiple techniques for all your materials from a set of high-level per-material properties.
- Several available Macros in shader source files. Just a few examples of the possibilities: binding OGRE auto constants, binding uniforms to material properties, foreach loops (repeat shader source a given number of times), retrieving per-material properties in an #if condition, automatic packing for vertex to fragment passthroughs. These macros allow you to generate even very complex shaders (for example the Ogre::Terrain shader) without assembling them in C++ code.
- Integrated preprocessor (no, I didn't reinvent the wheel, I used boost::wave which turned out to be an excellent choice) that allows me to blend out macros that shouldn't be in use because e.g. the shader permutation doesn't need this specific feature.
- User settings integration. They can be set by a C++ interface and retrieved through a macro in shader files.
- Automatic handling of shader permutations, i.e. shaders are shared between materials in a smart way.
- An optional "meta-language" (well, actually it's just a small header with some conditional defines) that you may use to compile the same shader source for different target languages. If you don't like it, you can still code in GLSL / CG etc separately. You can also switch between the languages at runtime.
- On-demand material and shader creation. It uses Ogre's material listener to compile the shaders as soon as they are needed for rendering, and not earlier.
- Shader changes are fully dynamic and real-time. Changing a user setting will recompile all shaders affected by this setting when they are next needed.
- Serialization system that extends Ogre's material script system, it uses Ogre's script parser, but also adds some additional properties that are not available in Ogre's material system.
- A concept called "Configuration" allowing you to create a different set of your shaders, doing the same thing except for some minor differences: the properties that are overridden by the active configuration. Possible uses for this are using simpler shaders (no shadows, no fog etc) when rendering for example realtime reflections or a minimap. You can easily switch between configurations by changing the active Ogre material scheme (for example on a viewport level).
- Fixed function support. You can globally enable or disable shaders at any time, and for texture units you can specify if they're only needed for the shader-based path (e.g. normal maps) or if they should also be created in the fixed function path.
LICENSE
see License.txt
AUTHOR
scrawl <scrawl@baseoftrash.de>

@ -1,7 +1,6 @@
set(OENGINE_OGRE
#ogre/renderer.cpp
ogre/lights.cpp
ogre/selectionbuffer.cpp
)
set(OENGINE_GUI

@ -1,164 +0,0 @@
#include "selectionbuffer.hpp"
#include <OgreHardwarePixelBuffer.h>
#include <OgreRenderTexture.h>
#include <OgreSubEntity.h>
#include <OgreEntity.h>
#include <OgreTechnique.h>
#include <OgreTextureManager.h>
#include <OgreViewport.h>
#include <stdexcept>
#include <openengine/misc/rng.hpp>
#include <extern/shiny/Main/Factory.hpp>
namespace OEngine
{
namespace Render
{
SelectionBuffer::SelectionBuffer(Ogre::Camera *camera, int sizeX, int sizeY, int visibilityFlags)
: mCamera(camera)
, mVisibilityFlags(visibilityFlags)
{
mTexture = Ogre::TextureManager::getSingleton().createManual("SelectionBuffer",
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, sizeX, sizeY, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET, this);
setupRenderTarget();
mCurrentColour = Ogre::ColourValue(0.3f, 0.3f, 0.3f);
}
void SelectionBuffer::setupRenderTarget()
{
mRenderTarget = mTexture->getBuffer()->getRenderTarget();
mRenderTarget->removeAllViewports();
Ogre::Viewport* vp = mRenderTarget->addViewport(mCamera);
vp->setOverlaysEnabled(false);
vp->setBackgroundColour(Ogre::ColourValue(0, 0, 0, 0));
vp->setShadowsEnabled(false);
vp->setMaterialScheme("selectionbuffer");
if (mVisibilityFlags != 0)
vp->setVisibilityMask (mVisibilityFlags);
mRenderTarget->setActive(true);
mRenderTarget->setAutoUpdated (false);
}
void SelectionBuffer::loadResource(Ogre::Resource *resource)
{
Ogre::Texture* tex = dynamic_cast<Ogre::Texture*>(resource);
if (!tex)
return;
tex->createInternalResources();
mRenderTarget = NULL;
// Don't need to re-render texture, because we have a copy in system memory (mBuffer)
}
SelectionBuffer::~SelectionBuffer()
{
Ogre::TextureManager::getSingleton ().remove("SelectionBuffer");
}
void SelectionBuffer::update ()
{
Ogre::MaterialManager::getSingleton ().addListener (this);
mTexture->load();
if (mRenderTarget == NULL)
setupRenderTarget();
mRenderTarget->update();
Ogre::MaterialManager::getSingleton ().removeListener (this);
mTexture->convertToImage(mBuffer);
}
int SelectionBuffer::getSelected(int xPos, int yPos)
{
Ogre::ColourValue clr = mBuffer.getColourAt (xPos, yPos, 0);
clr.a = 1;
if (mColourMap.find(clr) != mColourMap.end())
return mColourMap[clr];
else
return -1; // nothing selected
}
Ogre::Technique* SelectionBuffer::handleSchemeNotFound (
unsigned short schemeIndex, const Ogre::String &schemeName, Ogre::Material *originalMaterial,
unsigned short lodIndex, const Ogre::Renderable *rend)
{
if (schemeName == "selectionbuffer")
{
sh::Factory::getInstance ()._ensureMaterial ("SelectionColour", "Default");
Ogre::MaterialPtr m = Ogre::MaterialManager::getSingleton ().getByName("SelectionColour");
if(typeid(*rend) == typeid(Ogre::SubEntity))
{
const Ogre::SubEntity *subEntity = static_cast<const Ogre::SubEntity *>(rend);
int id = Ogre::any_cast<int>(subEntity->getParent ()->getUserObjectBindings().getUserAny());
bool found = false;
Ogre::ColourValue colour;
for (std::map<Ogre::ColourValue, int, cmp_ColourValue>::iterator it = mColourMap.begin(); it != mColourMap.end(); ++it)
{
if (it->second == id)
{
found = true;
colour = it->first;
}
}
if (!found)
{
getNextColour();
const_cast<Ogre::SubEntity *>(subEntity)->setCustomParameter(1, Ogre::Vector4(mCurrentColour.r, mCurrentColour.g, mCurrentColour.b, 1.0));
mColourMap[mCurrentColour] = id;
}
else
{
const_cast<Ogre::SubEntity *>(subEntity)->setCustomParameter(1, Ogre::Vector4(colour.r, colour.g, colour.b, 1.0));
}
assert(m->getTechnique(1));
return m->getTechnique(1);
}
else
{
m = Ogre::MaterialManager::getSingleton().getByName("NullMaterial");
if(m.isNull())
{
m = Ogre::MaterialManager::getSingleton().create("NullMaterial", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
m->getTechnique(0)->getPass(0)->setDepthCheckEnabled(true);
m->getTechnique(0)->getPass(0)->setDepthFunction(Ogre::CMPF_ALWAYS_FAIL);
}
return m->getTechnique(0);
}
}
return NULL;
}
void SelectionBuffer::getNextColour ()
{
Ogre::ARGB color = static_cast<Ogre::ARGB>(OEngine::Misc::Rng::rollClosedProbability() * std::numeric_limits<Ogre::uint32>::max());
if (mCurrentColour.getAsARGB () == color)
{
getNextColour();
return;
}
mCurrentColour.setAsARGB(color);
mCurrentColour.a = 1;
}
}
}

@ -1,62 +0,0 @@
#ifndef OENGINE_SELECTIONBUFFER_H
#define OENGINE_SELECTIONBUFFER_H
#include <OgreTexture.h>
#include <OgreRenderTarget.h>
#include <OgreMaterialManager.h>
#include <OgreColourValue.h>
namespace OEngine
{
namespace Render
{
struct cmp_ColourValue
{
bool operator()(const Ogre::ColourValue &a, const Ogre::ColourValue &b) const
{
return a.getAsBGRA() < b.getAsBGRA();
}
};
class SelectionBuffer : public Ogre::MaterialManager::Listener, public Ogre::ManualResourceLoader
{
public:
SelectionBuffer(Ogre::Camera* camera, int sizeX, int sizeY, int visibilityFlags);
virtual ~SelectionBuffer();
int getSelected(int xPos, int yPos);
///< @return ID of the selected object
void update();
virtual void loadResource(Ogre::Resource* resource);
virtual Ogre::Technique* handleSchemeNotFound (
unsigned short schemeIndex, const Ogre::String &schemeName, Ogre::Material *originalMaterial,
unsigned short lodIndex, const Ogre::Renderable *rend);
private:
Ogre::TexturePtr mTexture;
Ogre::RenderTexture* mRenderTarget;
Ogre::Image mBuffer;
std::map<Ogre::ColourValue, int, cmp_ColourValue> mColourMap;
Ogre::ColourValue mCurrentColour;
Ogre::Camera* mCamera;
int mVisibilityFlags;
void getNextColour();
void setupRenderTarget();
};
}
}
#endif
Loading…
Cancel
Save