Add xml shader and the loader

This commit is contained in:
Benau 2018-01-21 13:19:00 +08:00
parent b199b81427
commit 390554eca1
29 changed files with 1274 additions and 608 deletions

View File

@ -0,0 +1,133 @@
<spshader>
<!--
Notice: boolean Y or N here is case-sensitive
name: The name of the shader (cannot be empty), you have to make sure
no duplicated name will be introduced, and "_skinned" word is
reserved for automatic skinned mesh shader adding.
fallback-shader: The name of the shader to be used when advanced
lighting is off, make sure that shader is loaded first
(default is empty). STK will load list of sps*.xml
files in ascending order from a directory.
transparent: If Y, than this shader will be used in transparent pass
(default N).
drawing-priority: The larger this number, the later the meshes using
this shader will be drawn. Only useful in transparent
shader where drawing order matters because of alpha
blending (default 0 which means order doesn't
matter).
use-alpha-channel: If Y, this shader is going to access alpha channel
from mesh texture layers. It's used to hint STK not
to encode colorization mask for this material using
this shader which it will overwrite the alpha
channel (default N).
use-tangents: If Y, than meshes using this shader will have tangents
and bitangents defined and you can access them in shader
(default N).
srgb: Sample mesh texture layers in srgb or not (in 6 Ys / Ns), when
advanced lighting is off, srgb will always be false
default (Y Y N N N N), even if any texture layer is unused in
shader, you cannot skip it from the above Y / N array.
You can only specific 1st and shadow pass of shader in .xml
-->
<shader-info name="solid" fallback-shader="" transparent="N"
drawing-priority="0" use-alpha-channel="N" use-tangents="N"
srgb="Y Y N N N N"/>
<!--
use-function: Specify function to be run before drawing meshes with
this shader:
alphaBlendUse will be suitable for drawing alpha blend material.
additiveUse will be suitable for drawing additive material.
ghostUse will be suitable for drawing object with translucent
effect with face culling and depth buffer writing on.
unuse-function: Specify function to be run after drawing meshes with
this shader (none at the moment).
vertex-shader: Specify the vertex shader, it will search in the
directory of the location of this xml file first, if not
found it will search in the official shader directory.
Notice: if you use #stk_include in your shader file, STK
will only search the include header in official shader
directory.
fragment-shader: Specify the fragment shader, searching rule is the
same as above.
skinned-mesh-shader: Specify the skinned mesh version of the vertex
shader, searching rule is the same as above. You
have to make sure the uniforms and the textures
used in both skinned mesh / non-skinned mesh
shader are the same.
-->
<first-pass use-function="" unuse-function="" vertex-shader="sp_pass.vert"
fragment-shader="sp_solid.frag" skinned-mesh-shader="sp_skinning.vert">
<prefilled-textures>
<!--
prefilled-textures: Define the prefilled textures used in
shaders, they will be the same for all
meshes drawn using this shader.
name: Name of the texture used in shader (cannot be empty).
file: Filename of the texture, it will search using the order
in pushed texture searching directory
(cannot be empty).
srgb: Sample in srgb or not (specify in Y/N, default is N).
sampler: nearest, nearest_clamped, bilinear,
bilinear_clamped, trilinear, trilinear_clamped
and semi_trilinear are possible right now, default
is trilinear.
Example:
<prefilled-texture name="name_used_in_shader" file="texture.png"
srgb="Y" sampler="trilinear"/>-->
</prefilled-textures>
</first-pass>
<shadow-pass use-function="" unuse-function=""
vertex-shader="sp_shadow.vert" fragment-shader="white.frag"
skinned-mesh-shader="sp_skinning_shadow.vert">
<uniforms>
<!--
uniforms: Define the uniforms in shader with the name of the
type (int, float, mat4, vec4, vec3, vec2).
-->
<uniform name="layer" type="int"/>
</uniforms>
</shadow-pass>
<!--
uniform-assigners: List of uniform assigners functions to be auto-run
when "use" the shader which set the above uniforms,
currently there are:
shadowCascadeUniformAssigner will set the current shadow
cascade being drawn.
windDirectionUniformAssigner will set the wind direction.
zeroAlphaUniformAssigner should be used in transparent shader.
fogUniformAssigner will set 0 / 1 if fog is enabled in track.
ghostAlphaUniformAssigner will set ghost (kart) color based on sun
color of track.
You have to specify the uniform name in shader together with the
bundled uniform-assigners.
-->
<uniform-assigners>
<uniform-assigner name="layer"
function="shadowCascadeUniformAssigner"/>
</uniform-assigners>
</spshader>

View File

@ -0,0 +1,18 @@
<spshader>
<shader-info name="normalmap" fallback-shader="solid" use-tangents="Y"/>
<first-pass vertex-shader="sp_pass.vert"
fragment-shader="sp_normal_map.frag"
skinned-mesh-shader="sp_skinning.vert">
</first-pass>
<shadow-pass vertex-shader="sp_shadow.vert"
fragment-shader="white.frag"
skinned-mesh-shader="sp_skinning_shadow.vert">
<uniforms>
<uniform name="layer" type="int"/>
</uniforms>
</shadow-pass>
<uniform-assigners>
<uniform-assigner name="layer"
function="shadowCascadeUniformAssigner"/>
</uniform-assigners>
</spshader>

View File

@ -0,0 +1,17 @@
<spshader>
<shader-info name="unlit" fallback-shader="solid" use-alpha-channel="Y"/>
<first-pass vertex-shader="sp_pass.vert"
fragment-shader="sp_unlit.frag" skinned-mesh-shader="sp_skinning.vert">
</first-pass>
<shadow-pass vertex-shader="sp_shadow.vert"
fragment-shader="sp_shadow_alpha_test.frag"
skinned-mesh-shader="sp_skinning_shadow.vert">
<uniforms>
<uniform name="layer" type="int"/>
</uniforms>
</shadow-pass>
<uniform-assigners>
<uniform-assigner name="layer"
function="shadowCascadeUniformAssigner"/>
</uniform-assigners>
</spshader>

View File

@ -0,0 +1,16 @@
<spshader>
<shader-info name="decal"/>
<first-pass vertex-shader="sp_pass.vert"
fragment-shader="sp_decal.frag" skinned-mesh-shader="sp_skinning.vert">
</first-pass>
<shadow-pass vertex-shader="sp_shadow.vert" fragment-shader="white.frag"
skinned-mesh-shader="sp_skinning_shadow.vert">
<uniforms>
<uniform name="layer" type="int"/>
</uniforms>
</shadow-pass>
<uniform-assigners>
<uniform-assigner name="layer"
function="shadowCascadeUniformAssigner"/>
</uniform-assigners>
</spshader>

View File

@ -0,0 +1,22 @@
<spshader>
<shader-info name="grass" use-alpha-channel="Y"/>
<first-pass vertex-shader="sp_grass_pass.vert"
fragment-shader="sp_grass.frag">
<uniforms>
<uniform name="wind_direction" type="vec3"/>
</uniforms>
</first-pass>
<shadow-pass vertex-shader="sp_grass_shadow.vert"
fragment-shader="sp_shadow_alpha_test.frag">
<uniforms>
<uniform name="wind_direction" type="vec3"/>
<uniform name="layer" type="int"/>
</uniforms>
</shadow-pass>
<uniform-assigners>
<uniform-assigner name="layer"
function="shadowCascadeUniformAssigner"/>
<uniform-assigner name="wind_direction"
function="windDirectionUniformAssigner"/>
</uniform-assigners>
</spshader>

View File

@ -0,0 +1,18 @@
<spshader>
<shader-info name="alphatest" use-alpha-channel="Y"/>
<first-pass vertex-shader="sp_pass.vert"
fragment-shader="sp_alpha_test.frag"
skinned-mesh-shader="sp_skinning.vert">
</first-pass>
<shadow-pass vertex-shader="sp_shadow.vert"
fragment-shader="sp_shadow_alpha_test.frag"
skinned-mesh-shader="sp_skinning_shadow.vert">
<uniforms>
<uniform name="layer" type="int"/>
</uniforms>
</shadow-pass>
<uniform-assigners>
<uniform-assigner name="layer"
function="shadowCascadeUniformAssigner"/>
</uniform-assigners>
</spshader>

View File

@ -0,0 +1,17 @@
<spshader>
<shader-info name="alphablend" transparent="Y" use-alpha-channel="Y"/>
<first-pass use-function="alphaBlendUse" vertex-shader="sp_pass.vert"
fragment-shader="sp_transparent.frag"
skinned-mesh-shader="sp_skinning.vert">
<uniforms>
<uniform name="fog_enabled" type="int"/>
<uniform name="custom_alpha" type="float"/>
</uniforms>
</first-pass>
<uniform-assigners>
<uniform-assigner name="fog_enabled"
function="fogUniformAssigner"/>
<uniform-assigner name="custom_alpha"
function="zeroAlphaUniformAssigner"/>
</uniform-assigners>
</spshader>

View File

@ -0,0 +1,17 @@
<spshader>
<shader-info name="additive" transparent="Y" use-alpha-channel="Y"/>
<first-pass use-function="additiveUse" vertex-shader="sp_pass.vert"
fragment-shader="sp_transparent.frag"
skinned-mesh-shader="sp_skinning.vert">
<uniforms>
<uniform name="fog_enabled" type="int"/>
<uniform name="custom_alpha" type="float"/>
</uniforms>
</first-pass>
<uniform-assigners>
<uniform-assigner name="fog_enabled"
function="fogUniformAssigner"/>
<uniform-assigner name="custom_alpha"
function="zeroAlphaUniformAssigner"/>
</uniform-assigners>
</spshader>

View File

@ -0,0 +1,14 @@
<spshader>
<shader-info name="ghost" transparent="Y" drawing-priority="900"/>
<first-pass use-function="ghostUse" vertex-shader="sp_pass.vert"
fragment-shader="sp_ghost.frag"
skinned-mesh-shader="sp_skinning.vert">
<uniforms>
<uniform name="custom_alpha" type="float"/>
</uniforms>
</first-pass>
<uniform-assigners>
<uniform-assigner name="custom_alpha"
function="ghostAlphaUniformAssigner"/>
</uniform-assigners>
</spshader>

View File

@ -1,5 +1,5 @@
# Modify this file to change the last-modified date when you add/remove a file.
# This will then trigger a new cmake run automatically.
# This will then trigger a new cmake run automatically.
file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp")
file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp")
file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*")

View File

@ -432,7 +432,7 @@ void Material::loadContainerId()
if (!file_manager->searchTextureContainerId(m_container_id, m_texname))
{
Log::warn("Material", "Missing container id for %s, no texture"
" compression for it will be done", m_texname.c_str());
" compression for it will be done.", m_texname.c_str());
}
}
} // loadContainerId

View File

@ -368,9 +368,6 @@ public:
glDetachShader(m_program, *shader);
}
} // loadProgram
// ------------------------------------------------------------------------
virtual void bindCustomTextures() {}
// ------------------------------------------------------------------------
void drawFullScreenEffect(Args...args)
{

View File

@ -116,8 +116,8 @@ void ShaderFilesManager::readFile(const std::string& file,
* \param file Filename of the shader to load.
* \param type Type of the shader.
*/
SharedShader ShaderFilesManager::loadShader(const std::string& full_path,
unsigned type)
ShaderFilesManager::SharedShader ShaderFilesManager::loadShader
(const std::string& full_path, unsigned type)
{
GLuint* ss_ptr = new GLuint;
*ss_ptr = glCreateShader(type);
@ -239,8 +239,8 @@ SharedShader ShaderFilesManager::loadShader(const std::string& full_path,
* \param file Filename of the shader to load.
* \param type Type of the shader.
*/
SharedShader ShaderFilesManager::addShaderFile(const std::string& full_path,
unsigned type)
ShaderFilesManager::SharedShader ShaderFilesManager::addShaderFile
(const std::string& full_path, unsigned type)
{
#ifdef DEBUG
// Make sure no duplicated shader is added somewhere else
@ -259,8 +259,8 @@ SharedShader ShaderFilesManager::addShaderFile(const std::string& full_path,
* \param file Filename of the shader to load.
* \param type Type of the shader.
*/
SharedShader ShaderFilesManager::getShaderFile(const std::string &file,
unsigned type)
ShaderFilesManager::SharedShader ShaderFilesManager::getShaderFile
(const std::string &file, unsigned type)
{
const std::string full_path = (file.find('/') != std::string::npos ||
file.find('\\') != std::string::npos) ?

View File

@ -30,13 +30,13 @@
#include <memory>
#include <unordered_map>
typedef std::shared_ptr<GLuint> SharedShader;
class ShaderFilesManager : public Singleton<ShaderFilesManager>, NoCopy
{
private:
typedef std::shared_ptr<GLuint> SharedShader;
/**
* Map from a filename to a shader indentifier. Used for caching shaders.
* Map from a filename in full path to a shader indentifier.
* Used for caching shaders.
*/
std::unordered_map<std::string, SharedShader> m_shader_files_loaded;

View File

@ -19,7 +19,7 @@
#include "graphics/shadow.hpp"
#include "karts/abstract_kart.hpp"
#include "karts/skidding.hpp"
#include "graphics/sp/sp_base.hpp"
#include "graphics/sp/sp_shader_manager.hpp"
#include "graphics/sp/sp_dynamic_draw_call.hpp"
#include "physics/btKart.hpp"
#include "utils/mini_glm.hpp"
@ -31,7 +31,9 @@ Shadow::Shadow(Material* shadow_mat, const AbstractKart& kart)
: m_dy_dc(NULL), m_shadow_enabled(false), m_kart(kart)
{
m_dy_dc = std::make_shared<SP::SPDynamicDrawCall>
(scene::EPT_TRIANGLE_STRIP, SP::getSPShader("alphablend"), shadow_mat);
(scene::EPT_TRIANGLE_STRIP,
SP::SPShaderManager::get()->getSPShaderPtr("alphablend"),
shadow_mat);
m_dy_dc->getVerticesVector().resize(4);
video::S3DVertexSkinnedMesh* v = m_dy_dc->getVerticesVector().data();

View File

@ -25,10 +25,9 @@
#include "karts/abstract_kart.hpp"
#include "karts/skidding.hpp"
#include "modes/world.hpp"
#include "graphics/sp/sp_base.hpp"
#include "graphics/sp/sp_dynamic_draw_call.hpp"
#include "graphics/sp/sp_per_object_uniform.hpp"
#include "graphics/sp/sp_shader.hpp"
#include "graphics/sp/sp_shader_manager.hpp"
#include "graphics/sp/sp_uniform_assigner.hpp"
#include "physics/btKart.hpp"
#include "utils/mini_glm.hpp"
@ -45,7 +44,7 @@ SkidMarks::SkidMarks(const AbstractKart& kart, float width) : m_kart(kart)
m_width = width;
m_material = material_manager->getMaterialSPM("skidmarks.png", "",
"alphablend");
m_shader = SP::getSPShader("alphablend");
m_shader = SP::SPShaderManager::get()->getSPShaderPtr("alphablend");
assert(m_shader != NULL);
m_skid_marking = false;
} // SkidMark

View File

@ -38,6 +38,7 @@
#include "graphics/sp/sp_mesh_buffer.hpp"
#include "graphics/sp/sp_mesh_node.hpp"
#include "graphics/sp/sp_shader.hpp"
#include "graphics/sp/sp_shader_manager.hpp"
#include "graphics/sp/sp_texture.hpp"
#include "graphics/sp/sp_texture_manager.hpp"
#include "graphics/sp/sp_uniform_assigner.hpp"
@ -96,8 +97,6 @@ std::array<GLuint, 1> sp_prefilled_tex;
// ----------------------------------------------------------------------------
std::vector<float> g_bounding_boxes;
// ----------------------------------------------------------------------------
core::vector3df g_wind_dir;
// ----------------------------------------------------------------------------
std::vector<std::shared_ptr<SPDynamicDrawCall> > g_dy_dc;
// ----------------------------------------------------------------------------
float g_frustums[5][24] = { { } };
@ -127,78 +126,13 @@ bool sp_first_frame = false;
// ----------------------------------------------------------------------------
GLuint sp_fog_ubo = 0;
// ----------------------------------------------------------------------------
core::vector3df sp_wind_dir;
// ----------------------------------------------------------------------------
GLuint g_skinning_tex;
// ----------------------------------------------------------------------------
GLuint g_skinning_buf;
// ----------------------------------------------------------------------------
unsigned g_skinning_size;
// ----------------------------------------------------------------------------
void shadowCascadeUniformAssigner(SPUniformAssigner* ua)
{
ua->setValue(sp_cur_shadow_cascade);
} // shadowCascadeUniformAssigner
// ----------------------------------------------------------------------------
void fogUniformAssigner(SPUniformAssigner* ua)
{
int fog_enable = Track::getCurrentTrack() ?
Track::getCurrentTrack()->isFogEnabled() ? 1 : 0 : 0;
ua->setValue(fog_enable);
} // fogUniformAssigner
// ----------------------------------------------------------------------------
void zeroAlphaUniformAssigner(SPUniformAssigner* ua)
{
ua->setValue(0.0f);
} // zeroAlphaUniformAssigner
// ----------------------------------------------------------------------------
void ghostAlphaAssigner(SPUniformAssigner* ua)
{
float alpha = 1.0f;
if (Track::getCurrentTrack())
{
const video::SColor& c = Track::getCurrentTrack()->getSunColor();
float y = 0.2126f * c.getRed() + 0.7152f * c.getGreen() +
0.0722f * c.getBlue();
alpha = y > 128.0f ? 0.5f : 0.35f;
}
ua->setValue(alpha);
} // ghostAlphaAssigner
// ----------------------------------------------------------------------------
void alphaBlendUse()
{
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glDisable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
} // alphaBlendUse
// ----------------------------------------------------------------------------
void additiveUse()
{
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glDisable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE);
} // additiveUse
// ----------------------------------------------------------------------------
void ghostUse()
{
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
} // ghostUse
// ----------------------------------------------------------------------------
void displaceUniformAssigner(SP::SPUniformAssigner* ua)
{
@ -229,6 +163,77 @@ void displaceUniformAssigner(SP::SPUniformAssigner* ua)
ua->setValue(g_direction);
} // displaceUniformAssigner
// ----------------------------------------------------------------------------
void displaceShaderInit(SPShader* shader)
{
shader->addShaderFile("sp_pass.vert", GL_VERTEX_SHADER, RP_1ST);
shader->addShaderFile("white.frag", GL_FRAGMENT_SHADER, RP_1ST);
shader->linkShaderFiles(RP_1ST);
shader->use(RP_1ST);
shader->addBasicUniforms(RP_1ST);
shader->setUseFunction([]()->void
{
assert(g_stk_sbr->getRTTs() != NULL);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glDisable(GL_CULL_FACE);
glDisable(GL_BLEND);
glClear(GL_STENCIL_BUFFER_BIT);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
g_stk_sbr->getRTTs()->getFBO(FBO_TMP1_WITH_DS).bind(),
glClear(GL_COLOR_BUFFER_BIT);
}, RP_1ST);
shader->addShaderFile("sp_pass.vert", GL_VERTEX_SHADER, RP_RESERVED);
shader->addShaderFile("sp_displace.frag", GL_FRAGMENT_SHADER, RP_RESERVED);
shader->linkShaderFiles(RP_RESERVED);
shader->use(RP_RESERVED);
shader->addBasicUniforms(RP_RESERVED);
shader->addUniform("direction", typeid(std::array<float, 4>), RP_RESERVED);
shader->setUseFunction([]()->void
{
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glDisable(GL_CULL_FACE);
glDisable(GL_BLEND);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
g_stk_sbr->getRTTs()->getFBO(FBO_DISPLACE).bind(),
glClear(GL_COLOR_BUFFER_BIT);
}, RP_RESERVED);
shader->addCustomPrefilledTextures(ST_BILINEAR,
GL_TEXTURE_2D, "displacement_tex", []()->GLuint
{
return irr_driver->getTexture(FileManager::TEXTURE,
"displace.png")->getOpenGLTextureName();
}, RP_RESERVED);
shader->addCustomPrefilledTextures(ST_BILINEAR,
GL_TEXTURE_2D, "mask_tex", []()->GLuint
{
return g_stk_sbr->getRTTs()->getFBO(FBO_TMP1_WITH_DS).getRTT()[0];
}, RP_RESERVED);
shader->addCustomPrefilledTextures(ST_BILINEAR,
GL_TEXTURE_2D, "color_tex", []()->GLuint
{
return g_stk_sbr->getRTTs()->getFBO(FBO_COLORS).getRTT()[0];
}, RP_RESERVED);
shader->addAllTextures(RP_RESERVED);
shader->setUnuseFunction([]()->void
{
g_stk_sbr->getRTTs()->getFBO(FBO_COLORS).bind();
glStencilFunc(GL_EQUAL, 1, 0xFF);
g_stk_sbr->getPostProcessing()->renderPassThrough
(g_stk_sbr->getRTTs()->getFBO(FBO_DISPLACE).getRTT()[0],
g_stk_sbr->getRTTs()->getFBO(FBO_COLORS).getWidth(),
g_stk_sbr->getRTTs()->getFBO(FBO_COLORS).getHeight());
glDisable(GL_STENCIL_TEST);
}, RP_RESERVED);
static_cast<SPPerObjectUniform*>(shader)
->addAssignerFunction("direction", displaceUniformAssigner);
} // displaceShaderInit
// ----------------------------------------------------------------------------
void resizeSkinning(unsigned number)
{
@ -329,463 +334,72 @@ void addShader(SPShader* shader)
// ----------------------------------------------------------------------------
void loadShaders()
{
// ========================================================================
SPShader* shader = new SPShader("solid");
shader->addShaderFile("sp_pass.vert", GL_VERTEX_SHADER, RP_1ST);
shader->addShaderFile("sp_solid.frag", GL_FRAGMENT_SHADER, RP_1ST);
shader->linkShaderFiles(RP_1ST);
shader->use(RP_1ST);
shader->addBasicUniforms(RP_1ST);
shader->addAllTextures(RP_1ST);
shader->addShaderFile("sp_shadow.vert", GL_VERTEX_SHADER, RP_SHADOW);
shader->addShaderFile("white.frag", GL_FRAGMENT_SHADER, RP_SHADOW);
shader->linkShaderFiles(RP_SHADOW);
shader->use(RP_SHADOW);
shader->addBasicUniforms(RP_SHADOW);
shader->addUniform("layer", typeid(int), RP_SHADOW);
shader->addAllTextures(RP_SHADOW);
static_cast<SPPerObjectUniform*>(shader)->addAssignerFunction("layer",
shadowCascadeUniformAssigner);
addShader(shader);
shader = new SPShader("solid_skinned");
shader->addShaderFile("sp_skinning.vert", GL_VERTEX_SHADER, RP_1ST);
shader->addShaderFile("sp_solid.frag", GL_FRAGMENT_SHADER, RP_1ST);
shader->linkShaderFiles(RP_1ST);
shader->use(RP_1ST);
shader->addBasicUniforms(RP_1ST);
shader->addAllTextures(RP_1ST);
shader->addShaderFile("sp_skinning_shadow.vert", GL_VERTEX_SHADER, RP_SHADOW);
shader->addShaderFile("white.frag", GL_FRAGMENT_SHADER, RP_SHADOW);
shader->linkShaderFiles(RP_SHADOW);
shader->use(RP_SHADOW);
shader->addBasicUniforms(RP_SHADOW);
shader->addUniform("layer", typeid(int), RP_SHADOW);
shader->addAllTextures(RP_SHADOW);
static_cast<SPPerObjectUniform*>(shader)->addAssignerFunction("layer",
shadowCascadeUniformAssigner);
addShader(shader);
// ========================================================================
shader = new SPShader("decal");
shader->addShaderFile("sp_pass.vert", GL_VERTEX_SHADER, RP_1ST);
shader->addShaderFile("sp_decal.frag", GL_FRAGMENT_SHADER, RP_1ST);
shader->linkShaderFiles(RP_1ST);
shader->use(RP_1ST);
shader->addBasicUniforms(RP_1ST);
shader->addAllTextures(RP_1ST);
shader->addShaderFile("sp_shadow.vert", GL_VERTEX_SHADER, RP_SHADOW);
shader->addShaderFile("white.frag", GL_FRAGMENT_SHADER, RP_SHADOW);
shader->linkShaderFiles(RP_SHADOW);
shader->use(RP_SHADOW);
shader->addBasicUniforms(RP_SHADOW);
shader->addUniform("layer", typeid(int), RP_SHADOW);
shader->addAllTextures(RP_SHADOW);
static_cast<SPPerObjectUniform*>(shader)->addAssignerFunction("layer",
shadowCascadeUniformAssigner);
addShader(shader);
shader = new SPShader("decal_skinned");
shader->addShaderFile("sp_skinning.vert", GL_VERTEX_SHADER, RP_1ST);
shader->addShaderFile("sp_decal.frag", GL_FRAGMENT_SHADER, RP_1ST);
shader->linkShaderFiles(RP_1ST);
shader->use(RP_1ST);
shader->addBasicUniforms(RP_1ST);
shader->addAllTextures(RP_1ST);
shader->addShaderFile("sp_skinning_shadow.vert", GL_VERTEX_SHADER, RP_SHADOW);
shader->addShaderFile("white.frag", GL_FRAGMENT_SHADER, RP_SHADOW);
shader->linkShaderFiles(RP_SHADOW);
shader->use(RP_SHADOW);
shader->addBasicUniforms(RP_SHADOW);
shader->addUniform("layer", typeid(int), RP_SHADOW);
shader->addAllTextures(RP_SHADOW);
static_cast<SPPerObjectUniform*>(shader)->addAssignerFunction("layer",
shadowCascadeUniformAssigner);
addShader(shader);
// ========================================================================
shader = new SPShader("alphatest", {{ 0, 1, -1 }}, false, 0, true);
shader->addShaderFile("sp_pass.vert", GL_VERTEX_SHADER, RP_1ST);
shader->addShaderFile("sp_alpha_test.frag", GL_FRAGMENT_SHADER, RP_1ST);
shader->linkShaderFiles(RP_1ST);
shader->use(RP_1ST);
shader->addBasicUniforms(RP_1ST);
shader->addAllTextures(RP_1ST);
shader->addShaderFile("sp_shadow.vert", GL_VERTEX_SHADER, RP_SHADOW);
shader->addShaderFile("sp_shadow_alpha_test.frag", GL_FRAGMENT_SHADER, RP_SHADOW);
shader->linkShaderFiles(RP_SHADOW);
shader->use(RP_SHADOW);
shader->addBasicUniforms(RP_SHADOW);
shader->addUniform("layer", typeid(int), RP_SHADOW);
shader->addAllTextures(RP_SHADOW);
static_cast<SPPerObjectUniform*>(shader)->addAssignerFunction("layer",
shadowCascadeUniformAssigner);
addShader(shader);
shader = new SPShader("alphatest_skinned", {{ 0, 1, -1 }}, false, 0, true);
shader->addShaderFile("sp_skinning.vert", GL_VERTEX_SHADER, RP_1ST);
shader->addShaderFile("sp_alpha_test.frag", GL_FRAGMENT_SHADER, RP_1ST);
shader->linkShaderFiles(RP_1ST);
shader->use(RP_1ST);
shader->addBasicUniforms(RP_1ST);
shader->addAllTextures(RP_1ST);
shader->addShaderFile("sp_skinning_shadow.vert", GL_VERTEX_SHADER, RP_SHADOW);
shader->addShaderFile("sp_shadow_alpha_test.frag", GL_FRAGMENT_SHADER, RP_SHADOW);
shader->linkShaderFiles(RP_SHADOW);
shader->use(RP_SHADOW);
shader->addBasicUniforms(RP_SHADOW);
shader->addUniform("layer", typeid(int), RP_SHADOW);
shader->addAllTextures(RP_SHADOW);
static_cast<SPPerObjectUniform*>(shader)->addAssignerFunction("layer",
shadowCascadeUniformAssigner);
addShader(shader);
// ========================================================================
shader = new SPShader("unlit", {{ 0, 1, -1 }}, false, 0, true);
shader->addShaderFile("sp_pass.vert", GL_VERTEX_SHADER, RP_1ST);
shader->addShaderFile("sp_unlit.frag", GL_FRAGMENT_SHADER, RP_1ST);
shader->linkShaderFiles(RP_1ST);
shader->use(RP_1ST);
shader->addBasicUniforms(RP_1ST);
shader->addAllTextures(RP_1ST);
shader->addShaderFile("sp_shadow.vert", GL_VERTEX_SHADER, RP_SHADOW);
shader->addShaderFile("sp_shadow_alpha_test.frag", GL_FRAGMENT_SHADER, RP_SHADOW);
shader->linkShaderFiles(RP_SHADOW);
shader->use(RP_SHADOW);
shader->addBasicUniforms(RP_SHADOW);
shader->addUniform("layer", typeid(int), RP_SHADOW);
shader->addAllTextures(RP_SHADOW);
static_cast<SPPerObjectUniform*>(shader)->addAssignerFunction("layer",
shadowCascadeUniformAssigner);
addShader(shader);
shader = new SPShader("unlit_skinned", {{ 0, 1, -1 }}, false, 0, true);
shader->addShaderFile("sp_skinning.vert", GL_VERTEX_SHADER, RP_1ST);
shader->addShaderFile("sp_unlit.frag", GL_FRAGMENT_SHADER, RP_1ST);
shader->linkShaderFiles(RP_1ST);
shader->use(RP_1ST);
shader->addBasicUniforms(RP_1ST);
shader->addAllTextures(RP_1ST);
shader->addShaderFile("sp_skinning_shadow.vert", GL_VERTEX_SHADER, RP_SHADOW);
shader->addShaderFile("sp_shadow_alpha_test.frag", GL_FRAGMENT_SHADER, RP_SHADOW);
shader->linkShaderFiles(RP_SHADOW);
shader->use(RP_SHADOW);
shader->addBasicUniforms(RP_SHADOW);
shader->addUniform("layer", typeid(int), RP_SHADOW);
shader->addAllTextures(RP_SHADOW);
static_cast<SPPerObjectUniform*>(shader)->addAssignerFunction("layer",
shadowCascadeUniformAssigner);
addShader(shader);
// ========================================================================
shader = new SPShader("normalmap");
shader->addShaderFile("sp_pass.vert", GL_VERTEX_SHADER, RP_1ST);
shader->addShaderFile("sp_normal_map.frag", GL_FRAGMENT_SHADER, RP_1ST);
shader->linkShaderFiles(RP_1ST);
shader->use(RP_1ST);
shader->addBasicUniforms(RP_1ST);
shader->addAllTextures(RP_1ST);
shader->addShaderFile("sp_shadow.vert", GL_VERTEX_SHADER, RP_SHADOW);
shader->addShaderFile("white.frag", GL_FRAGMENT_SHADER, RP_SHADOW);
shader->linkShaderFiles(RP_SHADOW);
shader->use(RP_SHADOW);
shader->addBasicUniforms(RP_SHADOW);
shader->addUniform("layer", typeid(int), RP_SHADOW);
shader->addAllTextures(RP_SHADOW);
static_cast<SPPerObjectUniform*>(shader)->addAssignerFunction("layer",
shadowCascadeUniformAssigner);
addShader(shader);
shader = new SPShader("normalmap_skinned", {{ 0, 1, -1 }}, false);
shader->addShaderFile("sp_skinning.vert", GL_VERTEX_SHADER, RP_1ST);
shader->addShaderFile("sp_normal_map.frag", GL_FRAGMENT_SHADER, RP_1ST);
shader->linkShaderFiles(RP_1ST);
shader->use(RP_1ST);
shader->addBasicUniforms(RP_1ST);
shader->addAllTextures(RP_1ST);
shader->addShaderFile("sp_skinning_shadow.vert", GL_VERTEX_SHADER, RP_SHADOW);
shader->addShaderFile("white.frag", GL_FRAGMENT_SHADER, RP_SHADOW);
shader->linkShaderFiles(RP_SHADOW);
shader->use(RP_SHADOW);
shader->addBasicUniforms(RP_SHADOW);
shader->addUniform("layer", typeid(int), RP_SHADOW);
shader->addAllTextures(RP_SHADOW);
static_cast<SPPerObjectUniform*>(shader)->addAssignerFunction("layer",
shadowCascadeUniformAssigner);
addShader(shader);
// ========================================================================
shader = new SPShader("grass", {{ 0, 1, -1 }}, false, 0, true);
shader->addShaderFile("sp_grass_pass.vert", GL_VERTEX_SHADER, RP_1ST);
shader->addShaderFile("sp_grass.frag", GL_FRAGMENT_SHADER,
RP_1ST);
shader->linkShaderFiles(RP_1ST);
shader->use(RP_1ST);
shader->addBasicUniforms(RP_1ST);
shader->addUniform("wind_direction", typeid(core::vector3df), RP_1ST);
shader->addAllTextures(RP_1ST);
shader->addShaderFile("sp_grass_shadow.vert", GL_VERTEX_SHADER, RP_SHADOW);
shader->addShaderFile("sp_shadow_alpha_test.frag", GL_FRAGMENT_SHADER, RP_SHADOW);
shader->linkShaderFiles(RP_SHADOW);
shader->use(RP_SHADOW);
shader->addBasicUniforms(RP_SHADOW);
shader->addUniform("wind_direction", typeid(core::vector3df), RP_SHADOW);
shader->addUniform("layer", typeid(int), RP_SHADOW);
shader->addAllTextures(RP_SHADOW);
static_cast<SPPerObjectUniform*>(shader)->addAssignerFunction("layer",
shadowCascadeUniformAssigner);
static_cast<SPPerObjectUniform*>(shader)
->addAssignerFunction("wind_direction", [](SPUniformAssigner* ua)
{
ua->setValue(g_wind_dir);
});
addShader(shader);
// ========================================================================
// Transparent shader
// ========================================================================
shader = new SPShader("alphablend_skinned", {{ 0, -1, -1 }}, true);
shader->addShaderFile("sp_skinning.vert", GL_VERTEX_SHADER, RP_1ST);
shader->addShaderFile("sp_transparent.frag", GL_FRAGMENT_SHADER, RP_1ST);
shader->linkShaderFiles(RP_1ST);
shader->use(RP_1ST);
shader->addBasicUniforms(RP_1ST);
shader->addUniform("fog_enabled", typeid(int), RP_1ST);
shader->addUniform("custom_alpha", typeid(float), RP_1ST);
shader->addAllTextures(RP_1ST);
shader->setUseFunction(alphaBlendUse);
static_cast<SPPerObjectUniform*>(shader)
->addAssignerFunction("fog_enabled", fogUniformAssigner);
static_cast<SPPerObjectUniform*>(shader)
->addAssignerFunction("custom_alpha", zeroAlphaUniformAssigner);
addShader(shader);
shader = new SPShader("alphablend", {{ 0, -1, -1}}, true);
shader->addShaderFile("sp_pass.vert", GL_VERTEX_SHADER, RP_1ST);
shader->addShaderFile("sp_transparent.frag", GL_FRAGMENT_SHADER, RP_1ST);
shader->linkShaderFiles(RP_1ST);
shader->use(RP_1ST);
shader->addBasicUniforms(RP_1ST);
shader->addUniform("fog_enabled", typeid(int), RP_1ST);
shader->addUniform("custom_alpha", typeid(float), RP_1ST);
shader->addAllTextures(RP_1ST);
shader->setUseFunction(alphaBlendUse);
static_cast<SPPerObjectUniform*>(shader)
->addAssignerFunction("fog_enabled", fogUniformAssigner);
static_cast<SPPerObjectUniform*>(shader)
->addAssignerFunction("custom_alpha", zeroAlphaUniformAssigner);
addShader(shader);
shader = new SPShader("additive_skinned", {{ 0, -1, -1 }}, true);
shader->addShaderFile("sp_skinning.vert", GL_VERTEX_SHADER, RP_1ST);
shader->addShaderFile("sp_transparent.frag", GL_FRAGMENT_SHADER, RP_1ST);
shader->linkShaderFiles(RP_1ST);
shader->use(RP_1ST);
shader->addBasicUniforms(RP_1ST);
shader->addUniform("fog_enabled", typeid(int), RP_1ST);
shader->addUniform("custom_alpha", typeid(float), RP_1ST);
shader->addAllTextures(RP_1ST);
shader->setUseFunction(additiveUse);
static_cast<SPPerObjectUniform*>(shader)
->addAssignerFunction("fog_enabled", fogUniformAssigner);
static_cast<SPPerObjectUniform*>(shader)
->addAssignerFunction("custom_alpha", zeroAlphaUniformAssigner);
addShader(shader);
shader = new SPShader("additive", {{ 0, -1, -1 }}, true);
shader->addShaderFile("sp_pass.vert", GL_VERTEX_SHADER, RP_1ST);
shader->addShaderFile("sp_transparent.frag", GL_FRAGMENT_SHADER, RP_1ST);
shader->linkShaderFiles(RP_1ST);
shader->use(RP_1ST);
shader->addBasicUniforms(RP_1ST);
shader->addUniform("fog_enabled", typeid(int), RP_1ST);
shader->addUniform("custom_alpha", typeid(float), RP_1ST);
shader->addAllTextures(RP_1ST);
shader->setUseFunction(additiveUse);
static_cast<SPPerObjectUniform*>(shader)
->addAssignerFunction("fog_enabled", fogUniformAssigner);
static_cast<SPPerObjectUniform*>(shader)
->addAssignerFunction("custom_alpha", zeroAlphaUniformAssigner);
addShader(shader);
shader = new SPShader("ghost_skinned", {{ 0, -1, -1 }}, true/*transparent_shader*/,
900/*drawing_priority*/);
shader->addShaderFile("sp_skinning.vert", GL_VERTEX_SHADER, RP_1ST);
shader->addShaderFile("sp_ghost.frag", GL_FRAGMENT_SHADER, RP_1ST);
shader->linkShaderFiles(RP_1ST);
shader->use(RP_1ST);
shader->addBasicUniforms(RP_1ST);
shader->addUniform("custom_alpha", typeid(float), RP_1ST);
shader->addAllTextures(RP_1ST);
shader->setUseFunction(ghostUse);
static_cast<SPPerObjectUniform*>(shader)
->addAssignerFunction("custom_alpha", ghostAlphaAssigner);
addShader(shader);
shader = new SPShader("ghost", {{ 0, -1, -1 }}, true/*transparent_shader*/,
900/*drawing_priority*/);
shader->addShaderFile("sp_pass.vert", GL_VERTEX_SHADER, RP_1ST);
shader->addShaderFile("sp_ghost.frag", GL_FRAGMENT_SHADER, RP_1ST);
shader->linkShaderFiles(RP_1ST);
shader->use(RP_1ST);
shader->addBasicUniforms(RP_1ST);
shader->addUniform("custom_alpha", typeid(float), RP_1ST);
shader->addAllTextures(RP_1ST);
shader->setUseFunction(ghostUse);
static_cast<SPPerObjectUniform*>(shader)
->addAssignerFunction("custom_alpha", ghostAlphaAssigner);
addShader(shader);
SPShaderManager::get()->loadSPShaders(file_manager->getShadersDir());
// Displace shader is not specifiable in XML due to complex callback
std::shared_ptr<SPShader> sps;
if (CVS->isDefferedEnabled())
{
// This displace shader will be drawn the last in transparent pass
shader = new SPShader("displace", {{ 0, -1, 2 }}, true/*transparent_shader*/,
999/*drawing_priority*/);
shader->addShaderFile("sp_pass.vert", GL_VERTEX_SHADER,
RP_1ST);
shader->addShaderFile("white.frag", GL_FRAGMENT_SHADER,
RP_1ST);
shader->linkShaderFiles(RP_1ST);
shader->use(RP_1ST);
shader->addBasicUniforms(RP_1ST);
shader->setUseFunction([]()->void
{
assert(g_stk_sbr->getRTTs() != NULL);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glDisable(GL_CULL_FACE);
glDisable(GL_BLEND);
glClear(GL_STENCIL_BUFFER_BIT);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
g_stk_sbr->getRTTs()->getFBO(FBO_TMP1_WITH_DS).bind(),
glClear(GL_COLOR_BUFFER_BIT);
}, RP_1ST);
shader->addShaderFile("sp_pass.vert", GL_VERTEX_SHADER,
RP_RESERVED);
shader->addShaderFile("sp_displace.frag", GL_FRAGMENT_SHADER,
RP_RESERVED);
shader->linkShaderFiles(RP_RESERVED);
shader->use(RP_RESERVED);
shader->addBasicUniforms(RP_RESERVED);
shader->addUniform("direction", typeid(std::array<float, 4>),
RP_RESERVED);
shader->setUseFunction([]()->void
{
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glDisable(GL_CULL_FACE);
glDisable(GL_BLEND);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
g_stk_sbr->getRTTs()->getFBO(FBO_DISPLACE).bind(),
glClear(GL_COLOR_BUFFER_BIT);
}, RP_RESERVED);
shader->addCustomPrefilledTextures(ST_BILINEAR,
GL_TEXTURE_2D, "displacement_tex", []()->GLuint
{
return irr_driver->getTexture(FileManager::TEXTURE,
"displace.png")->getOpenGLTextureName();
}, RP_RESERVED);
shader->addCustomPrefilledTextures(ST_BILINEAR,
GL_TEXTURE_2D, "mask_tex", []()->GLuint
{
return g_stk_sbr->getRTTs()->getFBO(FBO_TMP1_WITH_DS).getRTT()[0];
}, RP_RESERVED);
shader->addCustomPrefilledTextures(ST_BILINEAR,
GL_TEXTURE_2D, "color_tex", []()->GLuint
{
return g_stk_sbr->getRTTs()->getFBO(FBO_COLORS).getRTT()[0];
}, RP_RESERVED);
shader->addAllTextures(RP_RESERVED);
shader->setUnuseFunction([]()->void
{
g_stk_sbr->getRTTs()->getFBO(FBO_COLORS).bind();
glStencilFunc(GL_EQUAL, 1, 0xFF);
g_stk_sbr->getPostProcessing()->renderPassThrough
(g_stk_sbr->getRTTs()->getFBO(FBO_DISPLACE).getRTT()[0],
g_stk_sbr->getRTTs()->getFBO(FBO_COLORS).getWidth(),
g_stk_sbr->getRTTs()->getFBO(FBO_COLORS).getHeight());
glDisable(GL_STENCIL_TEST);
}, RP_RESERVED);
static_cast<SPPerObjectUniform*>(shader)
->addAssignerFunction("direction", displaceUniformAssigner);
addShader(shader);
sps = std::make_shared<SPShader>("displace", displaceShaderInit,
true/*transparent_shader*/, 999/*drawing_priority*/,
true/*use_alpha_channel*/);
SPShaderManager::get()->addSPShader(sps->getName(), sps);
}
else
{
// Fallback shader
SPShaderManager::get()->addSPShader("displace",
SPShaderManager::get()->getSPShader("alphablend"));
}
// ========================================================================
// Glow shader
// ========================================================================
g_glow_shader = new SPShader("sp_glow_shader", {{ 0, -1, -1 }});
g_glow_shader->setInitFunction([](SPShader* shader)
{
shader->addShaderFile("sp_pass.vert", GL_VERTEX_SHADER, RP_1ST);
shader->addShaderFile("colorize.frag", GL_FRAGMENT_SHADER, RP_1ST);
shader->linkShaderFiles(RP_1ST);
shader->use(RP_1ST);
shader->addBasicUniforms(RP_1ST);
shader->addUniform("col", typeid(irr::video::SColorf), RP_1ST);
});
g_glow_shader->init();
// ========================================================================
// Normal visualizer
// ========================================================================
#ifndef USE_GLES2
if (CVS->isARBGeometryShadersUsable())
if (CVS->isDefferedEnabled())
{
g_normal_visualizer =
new SPShader("sp_normal_visualizer", {{ 0, -1, -1 }});
g_normal_visualizer->setInitFunction([](SPShader* shader)
sps = std::make_shared<SPShader>
("sp_glow_shader", [](SPShader* shader)
{
shader->addShaderFile("sp_normal_visualizer.vert",
GL_VERTEX_SHADER, RP_1ST);
shader->addShaderFile("sp_normal_visualizer.geom",
GL_GEOMETRY_SHADER, RP_1ST);
shader->addShaderFile("sp_normal_visualizer.frag",
GL_FRAGMENT_SHADER, RP_1ST);
shader->addShaderFile("sp_pass.vert", GL_VERTEX_SHADER,
RP_1ST);
shader->addShaderFile("colorize.frag", GL_FRAGMENT_SHADER,
RP_1ST);
shader->linkShaderFiles(RP_1ST);
shader->use(RP_1ST);
shader->addBasicUniforms(RP_1ST);
shader->addAllTextures(RP_1ST);
shader->addUniform("col", typeid(irr::video::SColorf), RP_1ST);
});
g_normal_visualizer->init();
}
SPShaderManager::get()->addSPShader(sps->getName(), sps);
g_glow_shader = sps.get();
// ====================================================================
// Normal visualizer
// ====================================================================
#ifndef USE_GLES2
if (CVS->isARBGeometryShadersUsable())
{
sps = std::make_shared<SPShader>
("sp_normal_visualizer", [](SPShader* shader)
{
shader->addShaderFile("sp_normal_visualizer.vert",
GL_VERTEX_SHADER, RP_1ST);
shader->addShaderFile("sp_normal_visualizer.geom",
GL_GEOMETRY_SHADER, RP_1ST);
shader->addShaderFile("sp_normal_visualizer.frag",
GL_FRAGMENT_SHADER, RP_1ST);
shader->linkShaderFiles(RP_1ST);
shader->use(RP_1ST);
shader->addBasicUniforms(RP_1ST);
shader->addAllTextures(RP_1ST);
});
SPShaderManager::get()->addSPShader(sps->getName(), sps);
g_normal_visualizer = sps.get();
}
#endif
}
SPShaderManager::get()->setOfficialShaders();
} // loadShaders
@ -974,9 +588,8 @@ void destroy()
delete p.second;
}
g_shaders.clear();
delete g_glow_shader;
SPShaderManager::destroy();
g_glow_shader = NULL;
delete g_normal_visualizer;
g_normal_visualizer = NULL;
SPTextureManager::destroy();
@ -1147,7 +760,7 @@ void prepareDrawCalls()
return;
}
g_bounding_boxes.clear();
g_wind_dir = core::vector3df(1.0f, 0.0f, 0.0f) *
sp_wind_dir = core::vector3df(1.0f, 0.0f, 0.0f) *
(irr_driver->getDevice()->getTimer()->getTime() / 1000.0f) * 1.5f;
sp_solid_poly_count = sp_shadow_poly_count = 0;
// 1st one is identity

View File

@ -23,6 +23,7 @@
#include "utils/no_copy.hpp"
#include "irrMath.h"
#include "vector3d.h"
#include <array>
#include <cmath>
@ -94,7 +95,7 @@ extern int sp_cur_shadow_cascade;
extern bool sp_culling;
extern unsigned sp_cur_player;
extern unsigned sp_cur_buf_id[MAX_PLAYER_COUNT];
extern irr::core::vector3df sp_wind_dir;
// ----------------------------------------------------------------------------
void init();
// ----------------------------------------------------------------------------

View File

@ -41,11 +41,14 @@ class Material;
namespace SP
{
class SPShader;
class SPTexture;
class SPMeshBuffer : public IMeshBuffer, public SPPerObjectUniform
{
protected:
std::vector<std::tuple<size_t/*first_index_id*/,
unsigned/*indices_count*/, Material*> > m_stk_material;

View File

@ -21,6 +21,7 @@
#include "graphics/sp/sp_mesh.hpp"
#include "graphics/sp/sp_mesh_buffer.hpp"
#include "graphics/sp/sp_shader.hpp"
#include "graphics/sp/sp_shader_manager.hpp"
#include "graphics/graphics_restrictions.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/material.hpp"
@ -195,7 +196,7 @@ SPShader* SPMeshNode::getShader(unsigned mesh_buffer_id) const
m_mesh->getSPMeshBuffer(mesh_buffer_id)->getSTKMaterial()
->getShaderName() : m_shader_override) +
(m_animated ? "_skinned" : "");
SPShader* shader = SP::getSPShader(sn);
SPShader* shader = SPShaderManager::get()->getSPShaderPtr(sn);
if (shader && shader->isTransparent())
{
// Use real transparent shader first
@ -203,7 +204,7 @@ SPShader* SPMeshNode::getShader(unsigned mesh_buffer_id) const
}
if (m_first_render_info && m_first_render_info->isTransparent())
{
return SP::getSPShader
return SPShaderManager::get()->getSPShaderPtr
(std::string("ghost") + (m_animated ? "_skinned" : ""));
}
return shader;

View File

@ -16,15 +16,12 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "graphics/sp/sp_shader.hpp"
#include "graphics/central_settings.hpp"
#include "graphics/shader_files_manager.hpp"
#include "graphics/sp/sp_base.hpp"
#include "graphics/sp/sp_uniform_assigner.hpp"
#include "utils/no_copy.hpp"
#include "utils/string_utils.hpp"
#include <ITexture.h>
#include <string>
namespace SP
{
std::unordered_map<std::string, std::pair<unsigned, SamplerType> >
@ -37,26 +34,15 @@ std::unordered_map<std::string, std::pair<unsigned, SamplerType> >
#endif
};
// ----------------------------------------------------------------------------
SPShader::~SPShader()
{
#ifndef SERVER_ONLY
for (unsigned rp = RP_1ST; rp < RP_COUNT; rp++)
{
if (m_program[rp] != 0)
{
glDeleteProgram(m_program[rp]);
}
}
unload();
#endif
} // ~SPShader
// ----------------------------------------------------------------------------
void SPShader::addShaderFile(const std::string& name, GLint shader_type,
RenderPass rp)
{
#ifndef SERVER_ONLY
if (m_program[rp] == 0)
{
m_program[rp] = glCreateProgram();
}
auto shader_file = ShaderFilesManager::getInstance()
->getShaderFile(name, shader_type);
if (shader_file)
@ -93,6 +79,11 @@ void SPShader::linkShaderFiles(RenderPass rp)
{
glDetachShader(m_program[rp], shaders[i]);
}
if (result == GL_FALSE)
{
glDeleteProgram(m_program[rp]);
m_program[rp] = 0;
}
#endif
} // linkShaderFiles
@ -166,7 +157,7 @@ void SPShader::addCustomPrefilledTextures(SamplerType st, GLuint texture_type,
} // addCustomPrefilledTextures
// ----------------------------------------------------------------------------
void SPShader::bindPrefilledTextures(RenderPass rp)
void SPShader::bindPrefilledTextures(RenderPass rp) const
{
#ifndef SERVER_ONLY
for (auto& p : m_prefilled_samplers[rp])
@ -189,7 +180,8 @@ void SPShader::bindPrefilledTextures(RenderPass rp)
} // bindPrefilledTextures
// ----------------------------------------------------------------------------
void SPShader::bindTextures(const std::array<GLuint, 6>& tex, RenderPass rp)
void SPShader::bindTextures(const std::array<GLuint, 6>& tex,
RenderPass rp) const
{
#ifndef SERVER_ONLY
for (auto& p : m_samplers[rp])
@ -239,7 +231,7 @@ void SPShader::setUniformsPerObject(SPPerObjectUniform* sppou,
// ----------------------------------------------------------------------------
SPUniformAssigner* SPShader::getUniformAssigner(const std::string& name,
RenderPass rp)
RenderPass rp) const
{
auto ret = m_uniforms[rp].find(name);
if (ret == m_uniforms[rp].end())
@ -252,8 +244,14 @@ SPUniformAssigner* SPShader::getUniformAssigner(const std::string& name,
// ----------------------------------------------------------------------------
void SPShader::unload()
{
#ifndef SERVER_ONLY
for (unsigned rp = RP_1ST; rp < RP_COUNT; rp++)
{
if (m_program[rp] != 0)
{
glDeleteProgram(m_program[rp]);
m_program[rp] = 0;
}
for (auto& p : m_uniforms[rp])
{
delete p.second;
@ -262,10 +260,24 @@ void SPShader::unload()
m_custom_prefilled_getter[rp].clear();
m_prefilled_samplers[rp].clear();
m_samplers[rp].clear();
m_shader_files.clear();
m_use_function[rp] = nullptr;
m_unuse_function[rp] = nullptr;
}
m_shader_files.clear();
#endif
} // unload
// ----------------------------------------------------------------------------
bool SPShader::isSrgbForTextureLayer(unsigned layer) const
{
#ifndef SERVER_ONLY
if (!CVS->isDefferedEnabled())
{
return false;
}
#endif
assert(layer < 6);
return m_srgb[layer];
} // isSrgbForTextureLayer
}

View File

@ -97,7 +97,7 @@ private:
std::function<void()> m_use_function[RP_COUNT], m_unuse_function[RP_COUNT];
std::function<void(SPShader*)> m_init_function;
const std::function<void(SPShader*)> m_init_function;
const int m_drawing_priority;
@ -105,29 +105,32 @@ private:
const bool m_use_alpha_channel;
const bool m_use_tangents;
const std::array<bool, 6> m_srgb;
public:
// ------------------------------------------------------------------------
SPShader(const std::string& name,
const std::array<int, 3>& pass = {{ 0, 1, -1 }},
const std::function<void(SPShader*)>& init_func,
bool transparent_shader = false, int drawing_priority = 0,
bool use_alpha_channel = false)
: m_name(name), m_drawing_priority(drawing_priority),
bool use_alpha_channel = false, bool use_tangents = false,
const std::array<bool, 6>& srgb =
{{ true, true, false, false, false, false }})
: m_name(name), m_init_function(init_func),
m_drawing_priority(drawing_priority),
m_transparent_shader(transparent_shader),
m_use_alpha_channel(use_alpha_channel || transparent_shader)
m_use_alpha_channel(use_alpha_channel),
m_use_tangents(use_tangents), m_srgb(srgb)
{
memset(m_program, 0, 12);
#ifndef SERVER_ONLY
for (int rp : pass)
{
if (rp > -1)
{
m_program[rp] = glCreateProgram();
}
}
#endif
m_init_function(this);
}
// ------------------------------------------------------------------------
~SPShader();
~SPShader()
{
unload();
}
// ------------------------------------------------------------------------
bool hasShader(RenderPass rp) { return m_program[rp] != 0; }
// ------------------------------------------------------------------------
@ -162,10 +165,10 @@ public:
std::function<GLuint()> func,
RenderPass rp = RP_1ST);
// ------------------------------------------------------------------------
void bindPrefilledTextures(RenderPass rp = RP_1ST);
void bindPrefilledTextures(RenderPass rp = RP_1ST) const;
// ------------------------------------------------------------------------
void bindTextures(const std::array<GLuint, 6>& tex,
RenderPass rp = RP_1ST);
RenderPass rp = RP_1ST) const;
// ------------------------------------------------------------------------
void addBasicUniforms(RenderPass rp = RP_1ST)
{
@ -184,7 +187,7 @@ public:
const std::string& getName() const { return m_name; }
// ------------------------------------------------------------------------
SPUniformAssigner* getUniformAssigner(const std::string& name,
RenderPass rp = RP_1ST);
RenderPass rp = RP_1ST) const;
// ------------------------------------------------------------------------
void addUniform(const std::string& name, const std::type_info& ti,
RenderPass rp = RP_1ST);
@ -212,30 +215,20 @@ public:
bool samplerLess(RenderPass rp = RP_1ST) const
{ return m_samplers[rp].empty(); }
// ------------------------------------------------------------------------
void setInitFunction(std::function<void(SPShader*)> func)
{
m_init_function = func;
}
// ------------------------------------------------------------------------
void unload();
// ------------------------------------------------------------------------
void init()
{
if (!m_shader_files.empty())
{
Log::error("SPShader",
"Please unload the shader before (re)init.");
return;
}
if (m_init_function)
{
m_init_function(this);
}
else
{
Log::error("SPShader", "Missing init function.");
}
m_init_function(this);
}
// ------------------------------------------------------------------------
bool isSrgbForTextureLayer(unsigned layer) const;
// ------------------------------------------------------------------------
bool useTangents() const { return m_use_tangents; }
};

View File

@ -0,0 +1,596 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2018 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "graphics/sp/sp_shader_manager.hpp"
#include "io/file_manager.hpp"
#include "io/xml_node.hpp"
#include "graphics/central_settings.hpp"
#include "graphics/sp/sp_base.hpp"
#include "graphics/sp/sp_shader.hpp"
#include "graphics/sp/sp_texture.hpp"
#include "graphics/sp/sp_texture_manager.hpp"
#include "graphics/sp/sp_uniform_assigner.hpp"
#include "tracks/track.hpp"
#include "utils/string_utils.hpp"
#include "utils/log.hpp"
#include <algorithm>
namespace SP
{
SPShaderManager* SPShaderManager::m_spsm = NULL;
// ----------------------------------------------------------------------------
SPShaderManager::SPShaderManager()
{
#ifndef SERVER_ONLY
m_official_types =
{
{ "int", typeid(int) },
{ "float", typeid(float) },
{ "mat4", typeid(irr::core::matrix4) },
{ "vec4", typeid(std::array<float, 4>) },
{ "vec3", typeid(irr::core::vector3df) },
{ "vec2", typeid(irr::core::vector2df) }
};
m_official_sampler_types =
{
{ "nearest", ST_NEAREST },
{ "nearest_clamped", ST_NEAREST_CLAMPED },
{ "bilinear", ST_BILINEAR },
{ "bilinear_clamped", ST_BILINEAR_CLAMPED },
{ "trilinear", ST_TRILINEAR },
{ "trilinear_clamped", ST_TRILINEAR_CLAMPED },
{ "semi_trilinear", ST_SEMI_TRILINEAR }
};
m_official_uniform_assigner_functions =
{
{ "shadowCascadeUniformAssigner", [](SPUniformAssigner* ua)
{
ua->setValue(sp_cur_shadow_cascade);
}
},
{ "windDirectionUniformAssigner", [](SPUniformAssigner* ua)
{
ua->setValue(sp_wind_dir);
}
},
{ "zeroAlphaUniformAssigner", [](SPUniformAssigner* ua)
{
ua->setValue(0.0f);
}
},
{ "fogUniformAssigner", [](SPUniformAssigner* ua)
{
int fog_enable = Track::getCurrentTrack() ?
Track::getCurrentTrack()->isFogEnabled() ? 1 : 0 : 0;
ua->setValue(fog_enable);
}
},
{ "ghostAlphaUniformAssigner", [](SPUniformAssigner* ua)
{
float alpha = 1.0f;
if (Track::getCurrentTrack())
{
const video::SColor& c = Track::getCurrentTrack()
->getSunColor();
float y = 0.2126f * c.getRed() + 0.7152f * c.getGreen() +
0.0722f * c.getBlue();
alpha = y > 128.0f ? 0.5f : 0.35f;
}
ua->setValue(alpha);
}
}
};
m_official_use_functions =
{
{ "alphaBlendUse", []()
{
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glDisable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
},
{ "additiveUse", []()
{
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glDisable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE);
}
},
{ "ghostUse", []()
{
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
}
};
#endif
} // SPShaderManager
// ----------------------------------------------------------------------------
SPShaderManager::~SPShaderManager()
{
m_shaders.clear();
m_official_shaders.clear();
} // ~SPShaderManager
// ----------------------------------------------------------------------------
void SPShaderManager::loadEachShader(const std::string& file_name)
{
#ifndef SERVER_ONLY
std::unique_ptr<XMLNode> xml(file_manager->createXMLTree(file_name));
if (!xml || xml->getName() != "spshader")
{
Log::error("SPShaderManager", "Invalid SPShader file %s",
file_name.c_str());
return;
}
ShaderInfo si;
const XMLNode* shader_info = xml->getNode("shader-info");
if (!shader_info)
{
Log::error("SPShaderManager", "Missing shader-info header in file %s",
file_name.c_str());
return;
}
shader_info->get("name", &si.m_shader_name);
if (si.m_shader_name.empty())
{
Log::error("SPShaderManager", "Empty shader name in file %s",
file_name.c_str());
return;
}
else if (si.m_shader_name.find("_skinned") != std::string::npos)
{
Log::error("SPShaderManager", "_skinned name is reserved for auto"
" skinned mesh shader adding");
return;
}
else if (getSPShader(si.m_shader_name))
{
Log::error("SPShaderManager", "%s shader already exists",
si.m_shader_name.c_str());
return;
}
shader_info->get("fallback-shader", &si.m_fallback_name);
shader_info->get("transparent", &si.m_transparent_shader);
shader_info->get("drawing-priority", &si.m_drawing_priority);
shader_info->get("use-alpha-channel", &si.m_use_alpha_channel);
shader_info->get("use-tangents", &si.m_use_tangents);
std::string srgb_prop;
shader_info->get("srgb", &srgb_prop);
std::vector<std::string> srgb_props = StringUtils::split(srgb_prop, ' ');
if (srgb_props.size() == 6)
{
for (unsigned i = 0; i < 6; i++)
{
si.m_srgb[i] = srgb_props[i] == "Y";
}
}
else if (!srgb_prop.empty())
{
Log::error("SPShaderManager", "Invalid srgb properties in shader");
}
std::array<PassInfo, 2> pi;
loadPassInfo(xml->getNode("first-pass"), pi[0]);
if (!si.m_transparent_shader && CVS->isDefferedEnabled())
{
loadPassInfo(xml->getNode("shadow-pass"), pi[1]);
}
if (pi[0].m_vertex_shader.empty())
{
Log::error("SPShaderManager", "Missing first pass vertex shader in"
" file %s", file_name.c_str());
return;
}
if (!si.m_fallback_name.empty() && !CVS->isDefferedEnabled())
{
std::shared_ptr<SPShader> fallback_shader =
getSPShader(si.m_fallback_name);
if (!fallback_shader)
{
Log::error("SPShaderManager", "%s fallback shader missing",
si.m_fallback_name.c_str());
}
else
{
addSPShader(si.m_shader_name, fallback_shader);
if (!pi[0].m_skinned_mesh_shader.empty())
{
std::shared_ptr<SPShader> fallback_skinned_shader =
getSPShader(si.m_fallback_name + "_skinned");
if (!fallback_skinned_shader)
{
Log::error("SPShaderManager", "%s fallback skinned mesh"
" shader missing", si.m_fallback_name.c_str());
}
addSPShader(si.m_shader_name + "_skinned",
fallback_skinned_shader);
}
}
return;
}
UniformAssigners ua;
const XMLNode* uniform_assigners = xml->getNode("uniform-assigners");
if (uniform_assigners)
{
for (unsigned i = 0; i < uniform_assigners->getNumNodes(); i++)
{
const XMLNode* uniform_assigner = uniform_assigners->getNode(i);
if (uniform_assigner->getName() == "uniform-assigner")
{
std::string name, function;
uniform_assigner->get("name", &name);
uniform_assigner->get("function", &function);
if (!name.empty() && !function.empty() &&
m_official_uniform_assigner_functions.find(function) !=
m_official_uniform_assigner_functions.end())
{
ua.emplace_back(name, m_official_uniform_assigner_functions
.at(function));
}
else
{
Log::error("SPShaderManager", "Invalid uniform assigner"
" %s", function.c_str());
}
}
}
}
addSPShader(si.m_shader_name, buildSPShader(si, pi, ua, false/*skinned*/));
if (!pi[0].m_skinned_mesh_shader.empty())
{
addSPShader(si.m_shader_name + "_skinned", buildSPShader(si, pi, ua,
true/*skinned*/));
}
#endif
} // loadEachShader
// ----------------------------------------------------------------------------
void SPShaderManager::loadPassInfo(const XMLNode* pass, PassInfo& pi)
{
if (!pass)
{
return;
}
std::string use_function, unuse_function;
pass->get("use-function", &use_function);
if (!use_function.empty() && m_official_use_functions.find(use_function) !=
m_official_use_functions.end())
{
pi.m_use_function = m_official_use_functions.at(use_function);
}
pass->get("unuse-function", &unuse_function);
if (!unuse_function.empty() &&
m_official_unuse_functions.find(unuse_function) !=
m_official_unuse_functions.end())
{
pi.m_unuse_function = m_official_unuse_functions.at(unuse_function);
}
pass->get("vertex-shader", &pi.m_vertex_shader);
pi.m_vertex_shader = getShaderFullPath(pi.m_vertex_shader);
pass->get("fragment-shader", &pi.m_fragment_shader);
pi.m_fragment_shader = getShaderFullPath(pi.m_fragment_shader);
pass->get("skinned-mesh-shader", &pi.m_skinned_mesh_shader);
pi.m_skinned_mesh_shader = getShaderFullPath(pi.m_skinned_mesh_shader);
const XMLNode* uniforms = pass->getNode("uniforms");
if (uniforms)
{
for (unsigned i = 0; i < uniforms->getNumNodes(); i++)
{
const XMLNode* uniform = uniforms->getNode(i);
if (uniform->getName() == "uniform")
{
std::string name, type;
uniform->get("name", &name);
uniform->get("type", &type);
if (!name.empty() && !type.empty() &&
m_official_types.find(type) != m_official_types.end())
{
pi.m_uniforms.emplace_back(name,
m_official_types.at(type));
}
else
{
Log::error("SPShaderManager", "Invalid uniform type %s",
type.c_str());
}
}
}
}
const XMLNode* prefilled_textures = pass->getNode("prefilled-textures");
if (prefilled_textures)
{
for (unsigned i = 0; i < prefilled_textures->getNumNodes(); i++)
{
const XMLNode* prefilled_texture = prefilled_textures->getNode(i);
if (prefilled_texture->getName() == "prefilled-texture")
{
bool srgb = false;
SamplerType st = ST_TRILINEAR;
std::string name, file, srgb_props, sampler_props;
prefilled_texture->get("name", &name);
prefilled_texture->get("file", &file);
prefilled_texture->get("srgb", &srgb_props);
if (!srgb_props.empty())
{
srgb = srgb_props == "Y";
}
prefilled_texture->get("sampler", &sampler_props);
if (!sampler_props.empty() &&
m_official_sampler_types.find(sampler_props) !=
m_official_sampler_types.end())
{
st = m_official_sampler_types.at(sampler_props);
}
if (!name.empty() && !file.empty())
{
pi.m_prefilled_textures.emplace_back(name, file, srgb, st);
}
else
{
Log::error("SPShaderManager", "Invalid prefilled texture");
}
}
}
}
} // loadPassInfo
// ----------------------------------------------------------------------------
std::string SPShaderManager::getShaderFullPath(const std::string& name)
{
if (name.empty())
{
return "";
}
std::string cur_location = m_shader_directory + name;
if (file_manager->fileExists(cur_location))
{
return cur_location;
}
return file_manager->getAssetChecked(FileManager::SHADER, name);
} // getShaderFullPath
// ----------------------------------------------------------------------------
std::shared_ptr<SPShader> SPShaderManager::buildSPShader(const ShaderInfo& si,
const std::array<PassInfo, 2>& pi, const UniformAssigners& ua,
bool skinned)
{
std::shared_ptr<SPShader> sps;
#ifndef SERVER_ONLY
sps = std::make_shared<SPShader>(si.m_shader_name,
[pi, ua, skinned](SPShader* shader)
{
// First pass
assert(!pi[0].m_vertex_shader.empty() ||
(skinned && !pi[0].m_skinned_mesh_shader.empty()));
SPPerObjectUniform* pou = static_cast<SPPerObjectUniform*>(shader);
for (auto& p : ua)
{
pou->addAssignerFunction(p.first, p.second);
}
shader->addShaderFile(skinned ?
pi[0].m_skinned_mesh_shader : pi[0].m_vertex_shader,
GL_VERTEX_SHADER, RP_1ST);
if (!pi[0].m_fragment_shader.empty())
{
shader->addShaderFile(pi[0].m_fragment_shader,
GL_FRAGMENT_SHADER, RP_1ST);
}
shader->linkShaderFiles(RP_1ST);
shader->use(RP_1ST);
shader->addBasicUniforms(RP_1ST);
addUniformsToShader(shader, pi[0].m_uniforms, RP_1ST);
if (pi[0].m_use_function)
{
shader->setUseFunction(pi[0].m_use_function, RP_1ST);
}
if (pi[0].m_unuse_function)
{
shader->setUnuseFunction(pi[0].m_unuse_function, RP_1ST);
}
addPrefilledTexturesToShader(shader, pi[0].m_prefilled_textures,
RP_1ST);
shader->addAllTextures(RP_1ST);
if (pi[1].m_vertex_shader.empty())
{
return;
}
// Shadow pass
if (skinned && pi[1].m_skinned_mesh_shader.empty())
{
Log::warn("SPShader", "Missing skinned mesh vertex shader in"
" shadow pass");
return;
}
shader->addShaderFile(skinned ?
pi[1].m_skinned_mesh_shader : pi[1].m_vertex_shader,
GL_VERTEX_SHADER, RP_SHADOW);
if (!pi[1].m_fragment_shader.empty())
{
shader->addShaderFile(pi[1].m_fragment_shader,
GL_FRAGMENT_SHADER, RP_SHADOW);
}
shader->linkShaderFiles(RP_SHADOW);
shader->use(RP_SHADOW);
shader->addBasicUniforms(RP_SHADOW);
addUniformsToShader(shader, pi[1].m_uniforms, RP_SHADOW);
if (pi[1].m_use_function)
{
shader->setUseFunction(pi[1].m_use_function, RP_SHADOW);
}
if (pi[1].m_unuse_function)
{
shader->setUnuseFunction(pi[1].m_unuse_function, RP_SHADOW);
}
addPrefilledTexturesToShader(shader, pi[1].m_prefilled_textures,
RP_SHADOW);
shader->addAllTextures(RP_SHADOW);
}, si.m_transparent_shader, si.m_drawing_priority,
si.m_use_alpha_channel, si.m_use_tangents, si.m_srgb);
#endif
return sps;
} // buildSPShader
// ----------------------------------------------------------------------------
void SPShaderManager::addUniformsToShader(SPShader* s,
const std::vector<std::pair<std::string, const std::type_info&> >& u,
RenderPass rp)
{
for (auto& p : u)
{
s->addUniform(p.first, p.second, rp);
}
} // addUniformsToShader
// ----------------------------------------------------------------------------
void SPShaderManager::addPrefilledTexturesToShader(SPShader* s,
const std::vector<std::tuple<std::string, std::string, bool, SamplerType> >
&t, RenderPass rp)
{
#ifndef SERVER_ONLY
for (auto& p : t)
{
std::string full_path;
const std::string& relative_path =
file_manager->searchTexture(std::get<1>(p)/*filename*/);
if (relative_path.empty())
{
Log::warn("SPShader", "Cannot determine prefilled texture full"
" path: %s", std::get<1>(p).c_str());
}
else
{
full_path = file_manager->getFileSystem()->getAbsolutePath
(relative_path.c_str()).c_str();
}
if (!full_path.empty())
{
std::string cid;
if (!file_manager->searchTextureContainerId(cid, std::get<1>(p)))
{
Log::warn("SPShader", "Missing container id for %s, no texture"
" compression for it will be done.",
std::get<1>(p).c_str());
}
std::shared_ptr<SPTexture> pt = SPTextureManager::get()
->getTexture(full_path, NULL/*material*/, std::get<2>(p), cid);
s->addCustomPrefilledTextures(std::get<3>(p)/*sampler_type*/,
GL_TEXTURE_2D, std::get<0>(p)/*name_in_shader*/, [pt]()->GLuint
{
return pt->getOpenGLTextureName();
}, rp);
}
}
#endif
} // addPrefilledTexturesToShader
// ----------------------------------------------------------------------------
void SPShaderManager::loadSPShaders(const std::string& directory_name)
{
std::set<std::string> shaders;
file_manager->listFiles(shaders, directory_name, true/*make_full_path*/);
for (auto it = shaders.begin(); it != shaders.end();)
{
if ((*it).find("sps") == std::string::npos ||
(*it).find(".xml") == std::string::npos)
{
it = shaders.erase(it);
}
else
{
it++;
}
}
if (shaders.empty())
{
return;
}
m_shader_directory = directory_name;
for (const std::string& file_name : shaders)
{
loadEachShader(file_name);
}
m_shader_directory = "";
} // loadSPShaders
// ----------------------------------------------------------------------------
void SPShaderManager::unloadAll()
{
for (auto& p : m_shaders)
{
p.second->unload();
}
} // unloadAll
// ----------------------------------------------------------------------------
void SPShaderManager::initAll()
{
for (auto& p : m_shaders)
{
p.second->init();
}
} // initAll
// ----------------------------------------------------------------------------
void SPShaderManager::removeUnusedShaders()
{
for (auto it = m_shaders.begin(); it != m_shaders.end();)
{
if (it->second.use_count() == 1)
{
it = m_shaders.erase(it);
}
else
{
it++;
}
}
} // removeUnusedShaders
}

View File

@ -0,0 +1,183 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2018 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_SP_SHADER_MANAGER_HPP
#define HEADER_SP_SHADER_MANAGER_HPP
#include <array>
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
#include "utils/no_copy.hpp"
class XMLNode;
namespace SP
{
class SPShader;
class SPUniformAssigner;
enum SamplerType: unsigned int;
enum RenderPass: unsigned int;
class SPShaderManager : public NoCopy
{
private:
typedef std::vector<std::pair< std::string, std::function<void
(SPUniformAssigner*)> > > UniformAssigners;
struct ShaderInfo
{
std::string m_shader_name, m_fallback_name;
int m_drawing_priority = 0;
bool m_transparent_shader = false;
bool m_use_alpha_channel = false;
bool m_use_tangents = false;
std::array<bool, 6> m_srgb =
{{
true, true, false, false, false, false
}};
};
struct PassInfo
{
std::function<void()> m_use_function;
std::function<void()> m_unuse_function;
std::string m_vertex_shader;
std::string m_fragment_shader;
std::string m_skinned_mesh_shader;
std::vector<std::pair<std::string, const std::type_info&> > m_uniforms;
std::vector<std::tuple<std::string, std::string, bool, SamplerType> >
m_prefilled_textures;
};
static SPShaderManager* m_spsm;
std::unordered_map<std::string, std::shared_ptr<SPShader> > m_shaders;
std::vector<std::shared_ptr<SPShader> > m_official_shaders;
std::unordered_map<std::string, const std::type_info&> m_official_types;
std::unordered_map<std::string, SamplerType> m_official_sampler_types;
std::unordered_map<std::string, std::function<void(SPUniformAssigner*)> >
m_official_uniform_assigner_functions;
std::unordered_map<std::string, std::function<void()> >
m_official_use_functions;
std::unordered_map<std::string, std::function<void()> >
m_official_unuse_functions;
std::string m_shader_directory;
// ------------------------------------------------------------------------
std::string getShaderFullPath(const std::string& name);
// ------------------------------------------------------------------------
void loadPassInfo(const XMLNode* pass, PassInfo& pi);
// ------------------------------------------------------------------------
void loadEachShader(const std::string& file_name);
// ------------------------------------------------------------------------
std::shared_ptr<SPShader> buildSPShader(const ShaderInfo& si,
const std::array<PassInfo, 2>& pi,
const UniformAssigners& ua,
bool skinned);
// ------------------------------------------------------------------------
static void addUniformsToShader(SPShader* s,
const std::vector<std::pair<std::string, const std::type_info&> >& u,
RenderPass rp);
// ------------------------------------------------------------------------
static void addPrefilledTexturesToShader(SPShader* s,
const std::vector<std::tuple<std::string, std::string, bool,
SamplerType> >& t, RenderPass rp);
public:
// ------------------------------------------------------------------------
static SPShaderManager* get()
{
if (m_spsm == NULL)
{
m_spsm = new SPShaderManager();
}
return m_spsm;
}
// ------------------------------------------------------------------------
static void destroy()
{
delete m_spsm;
m_spsm = NULL;
}
// ------------------------------------------------------------------------
SPShaderManager();
// ------------------------------------------------------------------------
~SPShaderManager();
// ------------------------------------------------------------------------
SPShader* getSPShaderPtr(const std::string& name)
{
return getSPShader(name).get();
}
// ------------------------------------------------------------------------
std::shared_ptr<SPShader> getSPShader(const std::string& name)
{
auto ret = m_shaders.find(name);
if (ret != m_shaders.end())
{
return ret->second;
}
return NULL;
}
// ------------------------------------------------------------------------
void loadSPShaders(const std::string& directory_name);
// ------------------------------------------------------------------------
void addSPShader(const std::string& name,
std::shared_ptr<SPShader> shader)
{
m_shaders[name] = shader;
}
// ------------------------------------------------------------------------
void unloadAll();
// ------------------------------------------------------------------------
void initAll();
// ------------------------------------------------------------------------
void removeUnusedShaders();
// ------------------------------------------------------------------------
void setOfficialShaders()
{
for (auto& p : m_shaders)
{
m_official_shaders.push_back(p.second);
}
}
};
}
#endif

View File

@ -19,9 +19,10 @@
#include "config/stk_config.hpp"
#include "config/user_config.hpp"
#include "io/file_manager.hpp"
#include "graphics/sp/sp_texture_manager.hpp"
#include "graphics/sp/sp_base.hpp"
#include "graphics/sp/sp_shader.hpp"
#include "graphics/sp/sp_shader_manager.hpp"
#include "graphics/sp/sp_texture_manager.hpp"
#include "graphics/central_settings.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/material.hpp"
@ -524,7 +525,8 @@ std::shared_ptr<video::IImage>
{
// Load colorization mask
std::shared_ptr<video::IImage> mask;
SPShader* sps = SP::getSPShader(m_material->getShaderName());
std::shared_ptr<SPShader> sps =
SPShaderManager::get()->getSPShader(m_material->getShaderName());
if (sps && sps->useAlphaChannel())
{
Log::debug("SPTexture", "Don't use colorization mask or factor"

View File

@ -77,8 +77,6 @@ private:
// ------------------------------------------------------------------------
void applyMask(video::IImage* texture, video::IImage* mask);
// ------------------------------------------------------------------------
void addTextureHandle();
// ------------------------------------------------------------------------
void createTransparent()
{
#ifndef SERVER_ONLY

View File

@ -186,6 +186,10 @@ public:
{
glUniform1i(m_location, 0);
}
else if (m_type == typeid(std::array<float, 4>))
{
glUniform4f(m_location, 0.0f, 0.0f, 0.0f,0.0f);
}
#endif
}
}

View File

@ -177,7 +177,6 @@ public:
template<int N, typename... TexIds>
void setTextureUnitsImpl(GLuint tex_id, TexIds... args)
{
static_assert(N != 15, "15 is reserved for skinning texture");
if (CVS->isARBSamplerObjectsUsable())
{
glActiveTexture(GL_TEXTURE0 + m_texture_units[N]);
@ -250,18 +249,6 @@ public:
for (unsigned i = 0; i < m_sampler_ids.size(); i++)
glDeleteSamplers(1, &m_sampler_ids[i]);
} // ~TextureShader
// ------------------------------------------------------------------------
/** For AZDO to remove the old texture handles, according to specification,
* they can only be removed when the underlying texture or sampler objects
* are finally deleted. This deletion will happen only when no handle
* using the texture or sampler object is resident on any context.
*/
void recreateTrilinearSampler(int sampler_id)
{
glDeleteSamplers(1, &m_sampler_ids[sampler_id]);
m_sampler_ids[sampler_id] =
createSamplers(ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // recreateTrilinearSampler
}; // class TextureShader

View File

@ -30,6 +30,7 @@
#include "graphics/light.hpp"
#include "graphics/shader.hpp"
#include "graphics/sp/sp_base.hpp"
#include "graphics/sp/sp_shader_manager.hpp"
#include "graphics/sp/sp_texture_manager.hpp"
#include "guiengine/widgets/label_widget.hpp"
#include "guiengine/widgets/text_box_widget.hpp"
@ -248,8 +249,10 @@ bool handleContextMenuAction(s32 cmd_id)
case DEBUG_GRAPHICS_RELOAD_SHADERS:
#ifndef SERVER_ONLY
Log::info("Debug", "Reloading shaders...");
SP::SPShaderManager::get()->unloadAll();
ShaderBase::killShaders();
ShaderFilesManager::getInstance()->clearAllShaderFiles();
SP::SPShaderManager::get()->initAll();
#endif
break;
case DEBUG_GRAPHICS_RESET: