#include "EShaderTypes.h"
#include "log.h"
#include "gamedef.h"
-#include "strfnd.h" // trim()
#include "client/tile.h"
/*
}
};
+
/*
ShaderCallback: Sets constants that can be used in shaders
*/
-class IShaderConstantSetterRegistry
-{
-public:
- virtual ~IShaderConstantSetterRegistry(){};
- virtual void onSetConstants(video::IMaterialRendererServices *services,
- bool is_highlevel, const std::string &name) = 0;
-};
-
class ShaderCallback : public video::IShaderConstantSetCallBack
{
- IShaderConstantSetterRegistry *m_scsr;
- std::string m_name;
+ std::vector<IShaderConstantSetter*> m_setters;
public:
- ShaderCallback(IShaderConstantSetterRegistry *scsr, const std::string &name):
- m_scsr(scsr),
- m_name(name)
- {}
- ~ShaderCallback() {}
+ ShaderCallback(const std::vector<IShaderConstantSetterFactory*> &factories)
+ {
+ for (u32 i = 0; i < factories.size(); ++i)
+ m_setters.push_back(factories[i]->create());
+ }
+
+ ~ShaderCallback()
+ {
+ for (u32 i = 0; i < m_setters.size(); ++i)
+ delete m_setters[i];
+ }
virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData)
{
bool is_highlevel = userData;
- m_scsr->onSetConstants(services, is_highlevel, m_name);
+ for (u32 i = 0; i < m_setters.size(); ++i)
+ m_setters[i]->onSetConstants(services, is_highlevel);
}
};
+
/*
MainShaderConstantSetter: Set basic constants required for almost everything
*/
class MainShaderConstantSetter : public IShaderConstantSetter
{
+ CachedVertexShaderSetting<float, 16> m_world_view_proj;
+ CachedVertexShaderSetting<float, 16> m_world;
+
public:
- MainShaderConstantSetter(IrrlichtDevice *device)
+ MainShaderConstantSetter() :
+ m_world_view_proj("mWorldViewProj"),
+ m_world("mWorld")
{}
~MainShaderConstantSetter() {}
video::IVideoDriver *driver = services->getVideoDriver();
sanity_check(driver);
- // set inverted world matrix
- core::matrix4 invWorld = driver->getTransform(video::ETS_WORLD);
- invWorld.makeInverse();
- if(is_highlevel)
- services->setVertexShaderConstant("mInvWorld", invWorld.pointer(), 16);
- else
- services->setVertexShaderConstant(invWorld.pointer(), 0, 4);
-
- // set clip matrix
+ // Set clip matrix
core::matrix4 worldViewProj;
worldViewProj = driver->getTransform(video::ETS_PROJECTION);
worldViewProj *= driver->getTransform(video::ETS_VIEW);
worldViewProj *= driver->getTransform(video::ETS_WORLD);
- if(is_highlevel)
- services->setVertexShaderConstant("mWorldViewProj", worldViewProj.pointer(), 16);
+ if (is_highlevel)
+ m_world_view_proj.set(*reinterpret_cast<float(*)[16]>(worldViewProj.pointer()), services);
else
- services->setVertexShaderConstant(worldViewProj.pointer(), 4, 4);
+ services->setVertexShaderConstant(worldViewProj.pointer(), 0, 4);
- // set transposed world matrix
- core::matrix4 transWorld = driver->getTransform(video::ETS_WORLD);
- transWorld = transWorld.getTransposed();
- if(is_highlevel)
- services->setVertexShaderConstant("mTransWorld", transWorld.pointer(), 16);
- else
- services->setVertexShaderConstant(transWorld.pointer(), 8, 4);
-
- // set world matrix
+ // Set world matrix
core::matrix4 world = driver->getTransform(video::ETS_WORLD);
- if(is_highlevel)
- services->setVertexShaderConstant("mWorld", world.pointer(), 16);
+ if (is_highlevel)
+ m_world.set(*reinterpret_cast<float(*)[16]>(world.pointer()), services);
else
- services->setVertexShaderConstant(world.pointer(), 8, 4);
+ services->setVertexShaderConstant(world.pointer(), 4, 4);
}
};
+
+class MainShaderConstantSetterFactory : public IShaderConstantSetterFactory
+{
+public:
+ virtual IShaderConstantSetter* create()
+ { return new MainShaderConstantSetter(); }
+};
+
+
/*
ShaderSource
*/
-class ShaderSource : public IWritableShaderSource, public IShaderConstantSetterRegistry
+class ShaderSource : public IWritableShaderSource
{
public:
ShaderSource(IrrlichtDevice *device);
// Shall be called from the main thread.
void rebuildShaders();
- void addGlobalConstantSetter(IShaderConstantSetter *setter)
+ void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter)
{
- m_global_setters.push_back(setter);
+ m_setter_factories.push_back(setter);
}
- void onSetConstants(video::IMaterialRendererServices *services,
- bool is_highlevel, const std::string &name);
-
private:
// The id of the thread that is allowed to use irrlicht directly
threadid_t m_main_thread;
// The irrlicht device
IrrlichtDevice *m_device;
- // The set-constants callback
- ShaderCallback *m_shader_callback;
// Cache of source shaders
// This should be only accessed from the main thread
// Queued shader fetches (to be processed by the main thread)
RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
- // Global constant setters
- // TODO: Delete these in the destructor
- std::vector<IShaderConstantSetter*> m_global_setters;
+ // Global constant setter factories
+ std::vector<IShaderConstantSetterFactory *> m_setter_factories;
+
+ // Shader callbacks
+ std::vector<ShaderCallback *> m_callbacks;
};
IWritableShaderSource* createShaderSource(IrrlichtDevice *device)
/*
Generate shader given the shader name.
*/
-ShaderInfo generate_shader(std::string name,
+ShaderInfo generate_shader(const std::string &name,
u8 material_type, u8 drawtype,
- IrrlichtDevice *device,
- video::IShaderConstantSetCallBack *callback,
+ IrrlichtDevice *device, std::vector<ShaderCallback *> &callbacks,
+ const std::vector<IShaderConstantSetterFactory*> &setter_factories,
SourceShaderCache *sourcecache);
/*
{
assert(m_device); // Pre-condition
- m_shader_callback = new ShaderCallback(this, "default");
-
- m_main_thread = get_current_thread_id();
+ m_main_thread = thr_get_current_thread_id();
// Add a dummy ShaderInfo as the first index, named ""
m_shaderinfo_cache.push_back(ShaderInfo());
// Add main global constant setter
- addGlobalConstantSetter(new MainShaderConstantSetter(device));
+ addShaderConstantSetterFactory(new MainShaderConstantSetterFactory());
}
ShaderSource::~ShaderSource()
{
- for (std::vector<IShaderConstantSetter*>::iterator iter = m_global_setters.begin();
- iter != m_global_setters.end(); iter++) {
+ for (std::vector<ShaderCallback *>::iterator iter = m_callbacks.begin();
+ iter != m_callbacks.end(); ++iter) {
delete *iter;
}
- m_global_setters.clear();
-
- if (m_shader_callback) {
- m_shader_callback->drop();
- m_shader_callback = NULL;
+ for (std::vector<IShaderConstantSetterFactory *>::iterator iter = m_setter_factories.begin();
+ iter != m_setter_factories.end(); ++iter) {
+ delete *iter;
}
}
Get shader
*/
- if(get_current_thread_id() == m_main_thread){
+ if (thr_is_current_thread(m_main_thread)) {
return getShaderIdDirect(name, material_type, drawtype);
} else {
/*errorstream<<"getShader(): Queued: name=\""<<name<<"\""<<std::endl;*/
/*
Calling only allowed from main thread
*/
- if(get_current_thread_id() != m_main_thread){
+ if (!thr_is_current_thread(m_main_thread)) {
errorstream<<"ShaderSource::getShaderIdDirect() "
"called not from main thread"<<std::endl;
return 0;
}
- ShaderInfo info = generate_shader(name, material_type, drawtype, m_device,
- m_shader_callback, &m_sourcecache);
+ ShaderInfo info = generate_shader(name, material_type, drawtype,
+ m_device, m_callbacks, m_setter_factories, &m_sourcecache);
/*
Add shader to caches (add dummy shaders too)
"name_of_shader=\""<<name_of_shader<<"\", "
"filename=\""<<filename<<"\""<<std::endl;*/
- sanity_check(get_current_thread_id() == m_main_thread);
+ sanity_check(thr_is_current_thread(m_main_thread));
m_sourcecache.insert(name_of_shader, filename, program, true);
}
ShaderInfo *info = &m_shaderinfo_cache[i];
if(info->name != ""){
*info = generate_shader(info->name, info->material_type,
- info->drawtype, m_device, m_shader_callback, &m_sourcecache);
+ info->drawtype, m_device, m_callbacks,
+ m_setter_factories, &m_sourcecache);
}
}
}
-void ShaderSource::onSetConstants(video::IMaterialRendererServices *services,
- bool is_highlevel, const std::string &name)
-{
- for(u32 i=0; i<m_global_setters.size(); i++){
- IShaderConstantSetter *setter = m_global_setters[i];
- setter->onSetConstants(services, is_highlevel);
- }
-}
-ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
- IrrlichtDevice *device, video::IShaderConstantSetCallBack *callback,
+ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtype,
+ IrrlichtDevice *device, std::vector<ShaderCallback *> &callbacks,
+ const std::vector<IShaderConstantSetterFactory*> &setter_factories,
SourceShaderCache *sourcecache)
{
ShaderInfo shaderinfo;
shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
break;
case TILE_MATERIAL_LIQUID_TRANSPARENT:
- shaderinfo.base_material = video::EMT_TRANSPARENT_VERTEX_ALPHA;
+ shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
break;
case TILE_MATERIAL_LIQUID_OPAQUE:
shaderinfo.base_material = video::EMT_SOLID;
}
bool enable_shaders = g_settings->getBool("enable_shaders");
- if(!enable_shaders)
+ if (!enable_shaders)
return shaderinfo;
video::IVideoDriver* driver = device->getVideoDriver();
else
shaders_header += "0\n";
- if(pixel_program != "")
- pixel_program = shaders_header + pixel_program;
- if(vertex_program != "")
- vertex_program = shaders_header + vertex_program;
- if(geometry_program != "")
- geometry_program = shaders_header + geometry_program;
+ if (g_settings->getBool("tone_mapping"))
+ shaders_header += "#define ENABLE_TONE_MAPPING\n";
+
+ shaders_header += "#define FOG_START ";
+ shaders_header += ftos(rangelim(g_settings->getFloat("fog_start"), 0.0f, 0.99f));
+ shaders_header += "\n";
+
// Call addHighLevelShaderMaterial() or addShaderMaterial()
const c8* vertex_program_ptr = 0;
const c8* pixel_program_ptr = 0;
const c8* geometry_program_ptr = 0;
- if(vertex_program != "")
+ if (!vertex_program.empty()) {
+ vertex_program = shaders_header + vertex_program;
vertex_program_ptr = vertex_program.c_str();
- if(pixel_program != "")
+ }
+ if (!pixel_program.empty()) {
+ pixel_program = shaders_header + pixel_program;
pixel_program_ptr = pixel_program.c_str();
- if(geometry_program != "")
+ }
+ if (!geometry_program.empty()) {
+ geometry_program = shaders_header + geometry_program;
geometry_program_ptr = geometry_program.c_str();
+ }
+ ShaderCallback *cb = new ShaderCallback(setter_factories);
s32 shadermat = -1;
if(is_highlevel){
infostream<<"Compiling high level shaders for "<<name<<std::endl;
video::EVST_VS_1_1, // Vertex shader version
pixel_program_ptr, // Pixel shader program
"pixelMain", // Pixel shader entry point
- video::EPST_PS_1_1, // Pixel shader version
+ video::EPST_PS_1_2, // Pixel shader version
geometry_program_ptr, // Geometry shader program
"geometryMain", // Geometry shader entry point
video::EGST_GS_4_0, // Geometry shader version
scene::EPT_TRIANGLES, // Geometry shader input
scene::EPT_TRIANGLE_STRIP, // Geometry shader output
0, // Support maximum number of vertices
- callback, // Set-constant callback
+ cb, // Set-constant callback
shaderinfo.base_material, // Base material
1 // Userdata passed to callback
);
"failed to generate \""<<name<<"\", "
"addHighLevelShaderMaterial failed."
<<std::endl;
+ dumpShaderProgram(warningstream, "Vertex", vertex_program);
+ dumpShaderProgram(warningstream, "Pixel", pixel_program);
+ dumpShaderProgram(warningstream, "Geometry", geometry_program);
+ delete cb;
return shaderinfo;
}
}
shadermat = gpu->addShaderMaterial(
vertex_program_ptr, // Vertex shader program
pixel_program_ptr, // Pixel shader program
- callback, // Set-constant callback
+ cb, // Set-constant callback
shaderinfo.base_material, // Base material
0 // Userdata passed to callback
);
"failed to generate \""<<name<<"\", "
"addShaderMaterial failed."
<<std::endl;
+ dumpShaderProgram(warningstream, "Vertex", vertex_program);
+ dumpShaderProgram(warningstream,"Pixel", pixel_program);
+ delete cb;
return shaderinfo;
}
}
+ callbacks.push_back(cb);
// HACK, TODO: investigate this better
// Grab the material renderer once more so minetest doesn't crash on exit
}
}
+
+void dumpShaderProgram(std::ostream &output_stream,
+ const std::string &program_type, const std::string &program)
+{
+ output_stream << program_type << " shader program:" << std::endl <<
+ "----------------------------------" << std::endl;
+ size_t pos = 0;
+ size_t prev = 0;
+ s16 line = 1;
+ while ((pos = program.find("\n", prev)) != std::string::npos) {
+ output_stream << line++ << ": "<< program.substr(prev, pos - prev) <<
+ std::endl;
+ prev = pos + 1;
+ }
+ output_stream << line << ": " << program.substr(prev) << std::endl <<
+ "End of " << program_type << " shader program." << std::endl <<
+ " " << std::endl;
+}