aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/shaders/object_shader/opengl_fragment.glsl131
-rw-r--r--client/shaders/object_shader/opengl_vertex.glsl44
-rw-r--r--src/client/client.cpp2
-rw-r--r--src/client/client.h2
-rw-r--r--src/client/clientenvironment.cpp57
-rw-r--r--src/client/content_cao.cpp129
-rw-r--r--src/client/content_cao.h4
-rw-r--r--src/client/shader.cpp8
-rw-r--r--src/client/shader.h2
9 files changed, 338 insertions, 41 deletions
diff --git a/client/shaders/object_shader/opengl_fragment.glsl b/client/shaders/object_shader/opengl_fragment.glsl
new file mode 100644
index 000000000..bb9e40637
--- /dev/null
+++ b/client/shaders/object_shader/opengl_fragment.glsl
@@ -0,0 +1,131 @@
+uniform sampler2D baseTexture;
+uniform sampler2D normalTexture;
+uniform sampler2D textureFlags;
+
+uniform vec4 emissiveColor;
+uniform vec4 skyBgColor;
+uniform float fogDistance;
+uniform vec3 eyePosition;
+
+varying vec3 vNormal;
+varying vec3 vPosition;
+varying vec3 worldPosition;
+
+varying vec3 eyeVec;
+varying vec3 lightVec;
+varying float vIDiff;
+
+bool normalTexturePresent = false;
+bool texTileableHorizontal = false;
+bool texTileableVertical = false;
+bool texSeamless = false;
+
+const float e = 2.718281828459;
+const float BS = 10.0;
+const float fogStart = FOG_START;
+const float fogShadingParameter = 1 / ( 1 - fogStart);
+
+void get_texture_flags()
+{
+ vec4 flags = texture2D(textureFlags, vec2(0.0, 0.0));
+ if (flags.r > 0.5) {
+ normalTexturePresent = true;
+ }
+ if (flags.g > 0.5) {
+ texTileableHorizontal = true;
+ }
+ if (flags.b > 0.5) {
+ texTileableVertical = true;
+ }
+ if (texTileableHorizontal && texTileableVertical) {
+ texSeamless = true;
+ }
+}
+
+float intensity(vec3 color)
+{
+ return (color.r + color.g + color.b) / 3.0;
+}
+
+float get_rgb_height(vec2 uv)
+{
+ if (texSeamless) {
+ return intensity(texture2D(baseTexture, uv).rgb);
+ } else {
+ return intensity(texture2D(baseTexture, clamp(uv, 0.0, 0.999)).rgb);
+ }
+}
+
+vec4 get_normal_map(vec2 uv)
+{
+ vec4 bump = texture2D(normalTexture, uv).rgba;
+ bump.xyz = normalize(bump.xyz * 2.0 - 1.0);
+ return bump;
+}
+
+void main(void)
+{
+ vec3 color;
+ vec4 bump;
+ vec2 uv = gl_TexCoord[0].st;
+ bool use_normalmap = false;
+ get_texture_flags();
+
+#if USE_NORMALMAPS == 1
+ if (normalTexturePresent) {
+ bump = get_normal_map(uv);
+ use_normalmap = true;
+ }
+#endif
+
+#if GENERATE_NORMALMAPS == 1
+ if (normalTexturePresent == false) {
+ float tl = get_rgb_height(vec2(uv.x - SAMPLE_STEP, uv.y + SAMPLE_STEP));
+ float t = get_rgb_height(vec2(uv.x - SAMPLE_STEP, uv.y - SAMPLE_STEP));
+ float tr = get_rgb_height(vec2(uv.x + SAMPLE_STEP, uv.y + SAMPLE_STEP));
+ float r = get_rgb_height(vec2(uv.x + SAMPLE_STEP, uv.y));
+ float br = get_rgb_height(vec2(uv.x + SAMPLE_STEP, uv.y - SAMPLE_STEP));
+ float b = get_rgb_height(vec2(uv.x, uv.y - SAMPLE_STEP));
+ float bl = get_rgb_height(vec2(uv.x -SAMPLE_STEP, uv.y - SAMPLE_STEP));
+ float l = get_rgb_height(vec2(uv.x - SAMPLE_STEP, uv.y));
+ float dX = (tr + 2.0 * r + br) - (tl + 2.0 * l + bl);
+ float dY = (bl + 2.0 * b + br) - (tl + 2.0 * t + tr);
+ bump = vec4(normalize(vec3 (dX, dY, NORMALMAPS_STRENGTH)), 1.0);
+ use_normalmap = true;
+ }
+#endif
+
+ vec4 base = texture2D(baseTexture, uv).rgba;
+
+#ifdef ENABLE_BUMPMAPPING
+ if (use_normalmap) {
+ vec3 L = normalize(lightVec);
+ vec3 E = normalize(eyeVec);
+ float specular = pow(clamp(dot(reflect(L, bump.xyz), E), 0.0, 1.0), 1.0);
+ float diffuse = dot(-E,bump.xyz);
+ color = (diffuse + 0.1 * specular) * base.rgb;
+ } else {
+ color = base.rgb;
+ }
+#else
+ color = base.rgb;
+#endif
+
+ vec4 col = vec4(color.rgb, base.a);
+
+ col.rgb *= emissiveColor.rgb * vIDiff;
+ // Due to a bug in some (older ?) graphics stacks (possibly in the glsl compiler ?),
+ // the fog will only be rendered correctly if the last operation before the
+ // clamp() is an addition. Else, the clamp() seems to be ignored.
+ // E.g. the following won't work:
+ // float clarity = clamp(fogShadingParameter
+ // * (fogDistance - length(eyeVec)) / fogDistance), 0.0, 1.0);
+ // As additions usually come for free following a multiplication, the new formula
+ // should be more efficient as well.
+ // Note: clarity = (1 - fogginess)
+ float clarity = clamp(fogShadingParameter
+ - fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0);
+ col = mix(skyBgColor, col, clarity);
+
+ gl_FragColor = vec4(col.rgb, base.a);
+}
diff --git a/client/shaders/object_shader/opengl_vertex.glsl b/client/shaders/object_shader/opengl_vertex.glsl
new file mode 100644
index 000000000..99b9b2709
--- /dev/null
+++ b/client/shaders/object_shader/opengl_vertex.glsl
@@ -0,0 +1,44 @@
+uniform mat4 mWorldViewProj;
+uniform mat4 mWorld;
+
+uniform vec3 eyePosition;
+uniform float animationTimer;
+
+varying vec3 vNormal;
+varying vec3 vPosition;
+varying vec3 worldPosition;
+
+varying vec3 eyeVec;
+varying vec3 lightVec;
+varying float vIDiff;
+
+const float e = 2.718281828459;
+const float BS = 10.0;
+
+float directional_ambient(vec3 normal)
+{
+ vec3 v = normal * normal;
+
+ if (normal.y < 0)
+ return dot(v, vec3(0.670820f, 0.447213f, 0.836660f));
+
+ return dot(v, vec3(0.670820f, 1.000000f, 0.836660f));
+}
+
+void main(void)
+{
+ gl_TexCoord[0] = gl_MultiTexCoord0;
+ gl_Position = mWorldViewProj * gl_Vertex;
+
+ vPosition = gl_Position.xyz;
+ vNormal = gl_Normal;
+ worldPosition = (mWorld * gl_Vertex).xyz;
+
+ vec3 sunPosition = vec3 (0.0, eyePosition.y * BS + 900.0, 0.0);
+
+ lightVec = sunPosition - worldPosition;
+ eyeVec = -(gl_ModelViewMatrix * gl_Vertex).xyz;
+ vIDiff = directional_ambient(normalize(gl_Normal));
+
+ gl_FrontColor = gl_BackColor = gl_Color;
+}
diff --git a/src/client/client.cpp b/src/client/client.cpp
index 6016f940e..c6d28ce80 100644
--- a/src/client/client.cpp
+++ b/src/client/client.cpp
@@ -1860,7 +1860,7 @@ ITextureSource* Client::getTextureSource()
{
return m_tsrc;
}
-IShaderSource* Client::getShaderSource()
+IWritableShaderSource* Client::getShaderSource()
{
return m_shsrc;
}
diff --git a/src/client/client.h b/src/client/client.h
index b9807a11e..2933a46e0 100644
--- a/src/client/client.h
+++ b/src/client/client.h
@@ -367,7 +367,7 @@ public:
const NodeDefManager* getNodeDefManager() override;
ICraftDefManager* getCraftDefManager() override;
ITextureSource* getTextureSource();
- virtual IShaderSource* getShaderSource();
+ virtual IWritableShaderSource* getShaderSource();
u16 allocateUnknownNodeId(const std::string &name) override;
virtual ISoundManager* getSoundManager();
MtEventManager* getEventManager();
diff --git a/src/client/clientenvironment.cpp b/src/client/clientenvironment.cpp
index 5eb033302..52d133781 100644
--- a/src/client/clientenvironment.cpp
+++ b/src/client/clientenvironment.cpp
@@ -32,11 +32,66 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "raycast.h"
#include "voxelalgorithms.h"
#include "settings.h"
+#include "shader.h"
#include "content_cao.h"
#include <algorithm>
#include "client/renderingengine.h"
/*
+ CAOShaderConstantSetter
+*/
+
+//! Shader constant setter for passing material emissive color to the CAO object_shader
+class CAOShaderConstantSetter : public IShaderConstantSetter
+{
+public:
+ CAOShaderConstantSetter():
+ m_emissive_color_setting("emissiveColor")
+ {}
+
+ ~CAOShaderConstantSetter() override = default;
+
+ void onSetConstants(video::IMaterialRendererServices *services,
+ bool is_highlevel) override
+ {
+ if (!is_highlevel)
+ return;
+
+ // Ambient color
+ video::SColorf emissive_color(m_emissive_color);
+
+ float as_array[4] = {
+ emissive_color.r,
+ emissive_color.g,
+ emissive_color.b,
+ emissive_color.a,
+ };
+ m_emissive_color_setting.set(as_array, services);
+ }
+
+ void onSetMaterial(const video::SMaterial& material) override
+ {
+ m_emissive_color = material.EmissiveColor;
+ }
+
+private:
+ video::SColor m_emissive_color;
+ CachedPixelShaderSetting<float, 4> m_emissive_color_setting;
+};
+
+class CAOShaderConstantSetterFactory : public IShaderConstantSetterFactory
+{
+public:
+ CAOShaderConstantSetterFactory()
+ {}
+
+ virtual IShaderConstantSetter* create()
+ {
+ return new CAOShaderConstantSetter();
+ }
+};
+
+/*
ClientEnvironment
*/
@@ -47,6 +102,8 @@ ClientEnvironment::ClientEnvironment(ClientMap *map,
m_texturesource(texturesource),
m_client(client)
{
+ auto *shdrsrc = m_client->getShaderSource();
+ shdrsrc->addShaderConstantSetterFactory(new CAOShaderConstantSetterFactory());
}
ClientEnvironment::~ClientEnvironment()
diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp
index c76f05bbb..3b203bc07 100644
--- a/src/client/content_cao.cpp
+++ b/src/client/content_cao.cpp
@@ -46,6 +46,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "wieldmesh.h"
#include <algorithm>
#include <cmath>
+#include "client/shader.h"
class Settings;
struct ToolCapabilities;
@@ -352,6 +353,8 @@ void GenericCAO::initialize(const std::string &data)
player->setCAO(this);
}
}
+
+ m_enable_shaders = g_settings->getBool("enable_shaders");
}
void GenericCAO::processInitData(const std::string &data)
@@ -577,8 +580,17 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
return;
}
- video::E_MATERIAL_TYPE material_type = (m_prop.use_texture_alpha) ?
- video::EMT_TRANSPARENT_ALPHA_CHANNEL : video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
+ if (m_enable_shaders) {
+ IShaderSource *shader_source = m_client->getShaderSource();
+ u32 shader_id = shader_source->getShader(
+ "object_shader",
+ TILE_MATERIAL_BASIC,
+ NDT_NORMAL);
+ m_material_type = shader_source->getShaderInfo(shader_id).material;
+ } else {
+ m_material_type = (m_prop.use_texture_alpha) ?
+ video::EMT_TRANSPARENT_ALPHA_CHANNEL : video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
+ }
auto grabMatrixNode = [this] {
infostream << "GenericCAO::addToScene(): " << m_prop.visual << std::endl;
@@ -587,6 +599,18 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
m_matrixnode->grab();
};
+ auto setSceneNodeMaterial = [this] (scene::ISceneNode *node) {
+ node->setMaterialFlag(video::EMF_LIGHTING, false);
+ node->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
+ node->setMaterialFlag(video::EMF_FOG_ENABLE, true);
+ node->setMaterialType(m_material_type);
+
+ if (m_enable_shaders) {
+ node->setMaterialFlag(video::EMF_GOURAUD_SHADING, false);
+ node->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true);
+ }
+ };
+
if (m_prop.visual == "sprite") {
grabMatrixNode();
m_spritenode = RenderingEngine::get_scene_manager()->addBillboardSceneNode(
@@ -594,10 +618,9 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
m_spritenode->grab();
m_spritenode->setMaterialTexture(0,
tsrc->getTextureForMesh("unknown_node.png"));
- m_spritenode->setMaterialFlag(video::EMF_LIGHTING, false);
- m_spritenode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
- m_spritenode->setMaterialType(material_type);
- m_spritenode->setMaterialFlag(video::EMF_FOG_ENABLE, true);
+
+ setSceneNodeMaterial(m_spritenode);
+
u8 li = m_last_light;
m_spritenode->setColor(video::SColor(255,li,li,li));
m_spritenode->setSize(v2f(m_prop.visual_size.X,
@@ -619,10 +642,10 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
{ // Front
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
video::S3DVertex vertices[4] = {
- video::S3DVertex(-dx, -dy, 0, 0,0,0, c, 1,1),
- video::S3DVertex( dx, -dy, 0, 0,0,0, c, 0,1),
- video::S3DVertex( dx, dy, 0, 0,0,0, c, 0,0),
- video::S3DVertex(-dx, dy, 0, 0,0,0, c, 1,0),
+ video::S3DVertex(-dx, -dy, 0, 0,0,1, c, 1,1),
+ video::S3DVertex( dx, -dy, 0, 0,0,1, c, 0,1),
+ video::S3DVertex( dx, dy, 0, 0,0,1, c, 0,0),
+ video::S3DVertex(-dx, dy, 0, 0,0,1, c, 1,0),
};
if (m_is_player) {
// Move minimal Y position to 0 (feet position)
@@ -635,7 +658,14 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
- buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
+ buf->getMaterial().MaterialType = m_material_type;
+
+ if (m_enable_shaders) {
+ buf->getMaterial().EmissiveColor = c;
+ buf->getMaterial().setFlag(video::EMF_GOURAUD_SHADING, false);
+ buf->getMaterial().setFlag(video::EMF_NORMALIZE_NORMALS, true);
+ }
+
// Add to mesh
mesh->addMeshBuffer(buf);
buf->drop();
@@ -643,10 +673,10 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
{ // Back
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
video::S3DVertex vertices[4] = {
- video::S3DVertex( dx,-dy, 0, 0,0,0, c, 1,1),
- video::S3DVertex(-dx,-dy, 0, 0,0,0, c, 0,1),
- video::S3DVertex(-dx, dy, 0, 0,0,0, c, 0,0),
- video::S3DVertex( dx, dy, 0, 0,0,0, c, 1,0),
+ video::S3DVertex( dx,-dy, 0, 0,0,-1, c, 1,1),
+ video::S3DVertex(-dx,-dy, 0, 0,0,-1, c, 0,1),
+ video::S3DVertex(-dx, dy, 0, 0,0,-1, c, 0,0),
+ video::S3DVertex( dx, dy, 0, 0,0,-1, c, 1,0),
};
if (m_is_player) {
// Move minimal Y position to 0 (feet position)
@@ -659,7 +689,14 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
- buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
+ buf->getMaterial().MaterialType = m_material_type;
+
+ if (m_enable_shaders) {
+ buf->getMaterial().EmissiveColor = c;
+ buf->getMaterial().setFlag(video::EMF_GOURAUD_SHADING, false);
+ buf->getMaterial().setFlag(video::EMF_NORMALIZE_NORMALS, true);
+ }
+
// Add to mesh
mesh->addMeshBuffer(buf);
buf->drop();
@@ -683,10 +720,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
u8 li = m_last_light;
setMeshColor(m_meshnode->getMesh(), video::SColor(255,li,li,li));
- m_meshnode->setMaterialFlag(video::EMF_LIGHTING, false);
- m_meshnode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
- m_meshnode->setMaterialType(material_type);
- m_meshnode->setMaterialFlag(video::EMF_FOG_ENABLE, true);
+ setSceneNodeMaterial(m_meshnode);
} else if (m_prop.visual == "mesh") {
grabMatrixNode();
scene::IAnimatedMesh *mesh = m_client->getMesh(m_prop.mesh, true);
@@ -704,10 +738,8 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
setAnimatedMeshColor(m_animated_meshnode, video::SColor(255,li,li,li));
- m_animated_meshnode->setMaterialFlag(video::EMF_LIGHTING, true);
- m_animated_meshnode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
- m_animated_meshnode->setMaterialType(material_type);
- m_animated_meshnode->setMaterialFlag(video::EMF_FOG_ENABLE, true);
+ setSceneNodeMaterial(m_animated_meshnode);
+
m_animated_meshnode->setMaterialFlag(video::EMF_BACK_FACE_CULLING,
m_prop.backface_culling);
} else
@@ -789,17 +821,41 @@ void GenericCAO::updateLightNoCheck(u8 light_at_pos)
return;
u8 li = decode_light(light_at_pos + m_glow);
+
if (li != m_last_light) {
m_last_light = li;
video::SColor color(255,li,li,li);
- if (m_meshnode) {
- setMeshColor(m_meshnode->getMesh(), color);
- } else if (m_animated_meshnode) {
- setAnimatedMeshColor(m_animated_meshnode, color);
- } else if (m_wield_meshnode) {
- m_wield_meshnode->setColor(color);
- } else if (m_spritenode) {
- m_spritenode->setColor(color);
+
+ if (m_enable_shaders) {
+ scene::ISceneNode *node = getSceneNode();
+
+ if (node == nullptr) {
+ return;
+ }
+
+ if (m_prop.visual == "upright_sprite") {
+ scene::IMesh *mesh = m_meshnode->getMesh();
+ for (u32 i = 0; i < mesh->getMeshBufferCount(); ++i) {
+ scene::IMeshBuffer* buf = mesh->getMeshBuffer(i);
+ video::SMaterial& material = buf->getMaterial();
+ material.EmissiveColor = color;
+ }
+ } else {
+ for (u32 i = 0; i < node->getMaterialCount(); ++i) {
+ video::SMaterial& material = node->getMaterial(i);
+ material.EmissiveColor = color;
+ }
+ }
+ } else {
+ if (m_meshnode) {
+ setMeshColor(m_meshnode->getMesh(), color);
+ } else if (m_animated_meshnode) {
+ setAnimatedMeshColor(m_animated_meshnode, color);
+ } else if (m_wield_meshnode) {
+ m_wield_meshnode->setColor(color);
+ } else if (m_spritenode) {
+ m_spritenode->setColor(color);
+ }
}
}
}
@@ -1101,16 +1157,13 @@ void GenericCAO::updateTextures(std::string mod)
m_current_texture_modifier = mod;
m_glow = m_prop.glow;
- video::E_MATERIAL_TYPE material_type = (m_prop.use_texture_alpha) ?
- video::EMT_TRANSPARENT_ALPHA_CHANNEL : video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
-
if (m_spritenode) {
if (m_prop.visual == "sprite") {
std::string texturestring = "unknown_node.png";
if (!m_prop.textures.empty())
texturestring = m_prop.textures[0];
texturestring += mod;
- m_spritenode->getMaterial(0).MaterialType = material_type;
+ m_spritenode->getMaterial(0).MaterialType = m_material_type;
m_spritenode->getMaterial(0).MaterialTypeParam = 0.5f;
m_spritenode->setMaterialTexture(0,
tsrc->getTextureForMesh(texturestring));
@@ -1146,7 +1199,7 @@ void GenericCAO::updateTextures(std::string mod)
// Set material flags and texture
video::SMaterial& material = m_animated_meshnode->getMaterial(i);
- material.MaterialType = material_type;
+ material.MaterialType = m_material_type;
material.MaterialTypeParam = 0.5f;
material.TextureLayer[0].Texture = texture;
material.setFlag(video::EMF_LIGHTING, true);
@@ -1193,7 +1246,7 @@ void GenericCAO::updateTextures(std::string mod)
// Set material flags and texture
video::SMaterial& material = m_meshnode->getMaterial(i);
- material.MaterialType = material_type;
+ material.MaterialType = m_material_type;
material.MaterialTypeParam = 0.5f;
material.setFlag(video::EMF_LIGHTING, false);
material.setFlag(video::EMF_BILINEAR_FILTER, false);
diff --git a/src/client/content_cao.h b/src/client/content_cao.h
index 6f3b2f06b..a1098305a 100644
--- a/src/client/content_cao.h
+++ b/src/client/content_cao.h
@@ -125,6 +125,10 @@ private:
u8 m_last_light = 255;
bool m_is_visible = false;
s8 m_glow = 0;
+ // Material
+ video::E_MATERIAL_TYPE m_material_type;
+ // Settings
+ bool m_enable_shaders = false;
public:
GenericCAO(Client *client, ClientEnvironment *env);
diff --git a/src/client/shader.cpp b/src/client/shader.cpp
index f36ff3d85..eda415ce6 100644
--- a/src/client/shader.cpp
+++ b/src/client/shader.cpp
@@ -188,7 +188,7 @@ public:
delete setter;
}
- virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData)
+ virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData) override
{
video::IVideoDriver *driver = services->getVideoDriver();
sanity_check(driver != NULL);
@@ -198,6 +198,12 @@ public:
for (IShaderConstantSetter *setter : m_setters)
setter->onSetConstants(services, is_highlevel);
}
+
+ virtual void OnSetMaterial(const video::SMaterial& material) override
+ {
+ for (IShaderConstantSetter *setter : m_setters)
+ setter->onSetMaterial(material);
+ }
};
diff --git a/src/client/shader.h b/src/client/shader.h
index 583c776f4..109d39336 100644
--- a/src/client/shader.h
+++ b/src/client/shader.h
@@ -67,6 +67,8 @@ public:
virtual ~IShaderConstantSetter() = default;
virtual void onSetConstants(video::IMaterialRendererServices *services,
bool is_highlevel) = 0;
+ virtual void onSetMaterial(const video::SMaterial& material)
+ { }
};