Add xml shader and the loader
This commit is contained in:
parent
b199b81427
commit
390554eca1
133
data/shaders/sps_0_solid.xml
Normal file
133
data/shaders/sps_0_solid.xml
Normal 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>
|
18
data/shaders/sps_1_normalmap.xml
Normal file
18
data/shaders/sps_1_normalmap.xml
Normal 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>
|
17
data/shaders/sps_2_unlit.xml
Normal file
17
data/shaders/sps_2_unlit.xml
Normal 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>
|
16
data/shaders/sps_3_decal.xml
Normal file
16
data/shaders/sps_3_decal.xml
Normal 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>
|
22
data/shaders/sps_4_grass.xml
Normal file
22
data/shaders/sps_4_grass.xml
Normal 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>
|
18
data/shaders/sps_5_alphatest.xml
Normal file
18
data/shaders/sps_5_alphatest.xml
Normal 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>
|
17
data/shaders/sps_6_alphablend.xml
Normal file
17
data/shaders/sps_6_alphablend.xml
Normal 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>
|
17
data/shaders/sps_7_additive.xml
Normal file
17
data/shaders/sps_7_additive.xml
Normal 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>
|
14
data/shaders/sps_8_ghost.xml
Normal file
14
data/shaders/sps_8_ghost.xml
Normal 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>
|
@ -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/*")
|
||||
|
@ -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
|
||||
|
@ -368,9 +368,6 @@ public:
|
||||
glDetachShader(m_program, *shader);
|
||||
}
|
||||
} // loadProgram
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void bindCustomTextures() {}
|
||||
// ------------------------------------------------------------------------
|
||||
void drawFullScreenEffect(Args...args)
|
||||
{
|
||||
|
@ -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) ?
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
}
|
||||
|
@ -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; }
|
||||
|
||||
};
|
||||
|
||||
|
596
src/graphics/sp/sp_shader_manager.cpp
Normal file
596
src/graphics/sp/sp_shader_manager.cpp
Normal 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
|
||||
|
||||
}
|
183
src/graphics/sp/sp_shader_manager.hpp
Normal file
183
src/graphics/sp/sp_shader_manager.hpp
Normal 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
|
@ -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"
|
||||
|
@ -77,8 +77,6 @@ private:
|
||||
// ------------------------------------------------------------------------
|
||||
void applyMask(video::IImage* texture, video::IImage* mask);
|
||||
// ------------------------------------------------------------------------
|
||||
void addTextureHandle();
|
||||
// ------------------------------------------------------------------------
|
||||
void createTransparent()
|
||||
{
|
||||
#ifndef SERVER_ONLY
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user