}
};
+
+// before 1.8 there isn't a "integer interface", only float
+#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
+typedef f32 SamplerLayer_t;
+#else
+typedef s32 SamplerLayer_t;
+#endif
+
+
class GameGlobalShaderConstantSetter : public IShaderConstantSetter
{
Sky *m_sky;
bool *m_force_fog_off;
f32 *m_fog_range;
+ bool m_fog_enabled;
+ CachedPixelShaderSetting<float, 4> m_sky_bg_color;
+ CachedPixelShaderSetting<float> m_fog_distance;
+ CachedVertexShaderSetting<float> m_animation_timer_vertex;
+ CachedPixelShaderSetting<float> m_animation_timer_pixel;
+ CachedPixelShaderSetting<float> m_day_night_ratio;
+ CachedPixelShaderSetting<float, 3> m_eye_position_pixel;
+ CachedVertexShaderSetting<float, 3> m_eye_position_vertex;
+ CachedPixelShaderSetting<float, 3> m_minimap_yaw;
+ CachedPixelShaderSetting<SamplerLayer_t> m_base_texture;
+ CachedPixelShaderSetting<SamplerLayer_t> m_normal_texture;
+ CachedPixelShaderSetting<SamplerLayer_t> m_texture_flags;
Client *m_client;
- bool m_fogEnabled;
public:
void onSettingsChange(const std::string &name)
{
if (name == "enable_fog")
- m_fogEnabled = g_settings->getBool("enable_fog");
+ m_fog_enabled = g_settings->getBool("enable_fog");
}
- static void SettingsCallback(const std::string &name, void *userdata)
+ static void settingsCallback(const std::string &name, void *userdata)
{
reinterpret_cast<GameGlobalShaderConstantSetter*>(userdata)->onSettingsChange(name);
}
+ void setSky(Sky *sky) { m_sky = sky; }
+
GameGlobalShaderConstantSetter(Sky *sky, bool *force_fog_off,
f32 *fog_range, Client *client) :
m_sky(sky),
m_force_fog_off(force_fog_off),
m_fog_range(fog_range),
+ m_sky_bg_color("skyBgColor"),
+ m_fog_distance("fogDistance"),
+ m_animation_timer_vertex("animationTimer"),
+ m_animation_timer_pixel("animationTimer"),
+ m_day_night_ratio("dayNightRatio"),
+ m_eye_position_pixel("eyePosition"),
+ m_eye_position_vertex("eyePosition"),
+ m_minimap_yaw("yawVec"),
+ m_base_texture("baseTexture"),
+ m_normal_texture("normalTexture"),
+ m_texture_flags("textureFlags"),
m_client(client)
{
- g_settings->registerChangedCallback("enable_fog", SettingsCallback, this);
- m_fogEnabled = g_settings->getBool("enable_fog");
+ g_settings->registerChangedCallback("enable_fog", settingsCallback, this);
+ m_fog_enabled = g_settings->getBool("enable_fog");
}
~GameGlobalShaderConstantSetter()
{
- g_settings->deregisterChangedCallback("enable_fog", SettingsCallback, this);
+ g_settings->deregisterChangedCallback("enable_fog", settingsCallback, this);
}
virtual void onSetConstants(video::IMaterialRendererServices *services,
bgcolorf.b,
bgcolorf.a,
};
- services->setPixelShaderConstant("skyBgColor", bgcolorfa, 4);
+ m_sky_bg_color.set(bgcolorfa, services);
// Fog distance
float fog_distance = 10000 * BS;
- if (m_fogEnabled && !*m_force_fog_off)
+ if (m_fog_enabled && !*m_force_fog_off)
fog_distance = *m_fog_range;
- services->setPixelShaderConstant("fogDistance", &fog_distance, 1);
+ m_fog_distance.set(&fog_distance, services);
- // Day-night ratio
- u32 daynight_ratio = m_client->getEnv().getDayNightRatio();
- float daynight_ratio_f = (float)daynight_ratio / 1000.0;
- services->setPixelShaderConstant("dayNightRatio", &daynight_ratio_f, 1);
+ float daynight_ratio = (float)m_client->getEnv().getDayNightRatio() / 1000.f;
+ m_day_night_ratio.set(&daynight_ratio, services);
u32 animation_timer = porting::getTimeMs() % 100000;
- float animation_timer_f = (float)animation_timer / 100000.0;
- services->setPixelShaderConstant("animationTimer", &animation_timer_f, 1);
- services->setVertexShaderConstant("animationTimer", &animation_timer_f, 1);
+ float animation_timer_f = (float)animation_timer / 100000.f;
+ m_animation_timer_vertex.set(&animation_timer_f, services);
+ m_animation_timer_pixel.set(&animation_timer_f, services);
- LocalPlayer *player = m_client->getEnv().getLocalPlayer();
- v3f eye_position = player->getEyePosition();
- services->setPixelShaderConstant("eyePosition", (irr::f32 *)&eye_position, 3);
- services->setVertexShaderConstant("eyePosition", (irr::f32 *)&eye_position, 3);
-
- v3f minimap_yaw_vec = m_client->getMapper()->getYawVec();
- services->setPixelShaderConstant("yawVec", (irr::f32 *)&minimap_yaw_vec, 3);
+ float eye_position_array[3];
+ v3f epos = m_client->getEnv().getLocalPlayer()->getEyePosition();
+#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
+ eye_position_array[0] = epos.X;
+ eye_position_array[1] = epos.Y;
+ eye_position_array[2] = epos.Z;
+#else
+ epos.getAs3Values(eye_position_array);
+#endif
+ m_eye_position_pixel.set(eye_position_array, services);
+ m_eye_position_vertex.set(eye_position_array, services);
- // Uniform sampler layers
- // before 1.8 there isn't a "integer interface", only float
+ float minimap_yaw_array[3];
+ v3f minimap_yaw = m_client->getMapper()->getYawVec();
#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
- f32 layer0 = 0;
- f32 layer1 = 1;
- f32 layer2 = 2;
- services->setPixelShaderConstant("baseTexture" , (irr::f32 *)&layer0, 1);
- services->setPixelShaderConstant("normalTexture" , (irr::f32 *)&layer1, 1);
- services->setPixelShaderConstant("textureFlags" , (irr::f32 *)&layer2, 1);
+ minimap_yaw_array[0] = minimap_yaw.X;
+ minimap_yaw_array[1] = minimap_yaw.Y;
+ minimap_yaw_array[2] = minimap_yaw.Z;
#else
- s32 layer0 = 0;
- s32 layer1 = 1;
- s32 layer2 = 2;
- services->setPixelShaderConstant("baseTexture" , (irr::s32 *)&layer0, 1);
- services->setPixelShaderConstant("normalTexture" , (irr::s32 *)&layer1, 1);
- services->setPixelShaderConstant("textureFlags" , (irr::s32 *)&layer2, 1);
+ minimap_yaw.getAs3Values(minimap_yaw_array);
#endif
+ m_minimap_yaw.set(minimap_yaw_array, services);
+
+ SamplerLayer_t base_tex = 0,
+ normal_tex = 1,
+ flags_tex = 2;
+ m_base_texture.set(&base_tex, services);
+ m_normal_texture.set(&normal_tex, services);
+ m_texture_flags.set(&flags_tex, services);
}
};
+
+class GameGlobalShaderConstantSetterFactory : public IShaderConstantSetterFactory
+{
+ Sky *m_sky;
+ bool *m_force_fog_off;
+ f32 *m_fog_range;
+ Client *m_client;
+ std::vector<GameGlobalShaderConstantSetter *> created_nosky;
+public:
+ GameGlobalShaderConstantSetterFactory(bool *force_fog_off,
+ f32 *fog_range, Client *client) :
+ m_sky(NULL),
+ m_force_fog_off(force_fog_off),
+ m_fog_range(fog_range),
+ m_client(client)
+ {}
+
+ void setSky(Sky *sky) {
+ m_sky = sky;
+ for (size_t i = 0; i < created_nosky.size(); ++i) {
+ created_nosky[i]->setSky(m_sky);
+ }
+ created_nosky.clear();
+ }
+
+ virtual IShaderConstantSetter* create()
+ {
+ GameGlobalShaderConstantSetter *scs = new GameGlobalShaderConstantSetter(
+ m_sky, m_force_fog_off, m_fog_range, m_client);
+ if (!m_sky)
+ created_nosky.push_back(scs);
+ return scs;
+ }
+};
+
+
bool nodePlacementPrediction(Client &client,
const ItemDefinition &playeritem_def, v3s16 nodepos, v3s16 neighbourpos)
{
Hud *hud;
Mapper *mapper;
+ GameRunData runData;
+ VolatileRunFlags flags;
+
/* 'cache'
This class does take ownership/responsibily for cleaning up etc of any of
these items (e.g. device)
smgr->getParameters()->setAttribute(scene::OBJ_LOADER_IGNORE_MATERIAL_FILES, true);
+ memset(&runData, 0, sizeof(runData));
+ runData.time_from_last_punch = 10.0;
+ runData.profiler_max_page = 3;
+ runData.update_wielded_item_trigger = true;
+
+ memset(&flags, 0, sizeof(flags));
+ flags.show_chat = true;
+ flags.show_hud = true;
+ flags.show_debug = g_settings->getBool("show_debug");
+ flags.invert_mouse = g_settings->getBool("invert_mouse");
+ flags.first_loop_after_window_activation = true;
+
if (!init(map_dir, address, port, gamespec))
return false;
RunStats stats = { 0 };
CameraOrientation cam_view_target = { 0 };
CameraOrientation cam_view = { 0 };
- GameRunData runData = { 0 };
FpsControl draw_times = { 0 };
- VolatileRunFlags flags = { 0 };
f32 dtime; // in seconds
- runData.time_from_last_punch = 10.0;
- runData.profiler_max_page = 3;
- runData.update_wielded_item_trigger = true;
-
- flags.show_chat = true;
- flags.show_hud = true;
- flags.show_minimap = g_settings->getBool("enable_minimap");
- flags.show_debug = g_settings->getBool("show_debug");
- flags.invert_mouse = g_settings->getBool("invert_mouse");
- flags.first_loop_after_window_activation = true;
-
/* Clear the profiler */
Profiler::GraphValues dummyvalues;
g_profiler->graphGet(dummyvalues);
draw_times.last_time = device->getTimer()->getTime();
- shader_src->addGlobalConstantSetter(new GameGlobalShaderConstantSetter(
- sky,
- &flags.force_fog_off,
- &runData.fog_range,
- client));
-
set_light_table(g_settings->getFloat("display_gamma"));
#ifdef __ANDROID__
return false;
}
+ GameGlobalShaderConstantSetterFactory *scsf = new GameGlobalShaderConstantSetterFactory(
+ &flags.force_fog_off, &runData.fog_range, client);
+ shader_src->addShaderConstantSetterFactory(scsf);
+
// Update cached textures, meshes and materials
client->afterContentReceived(device);
/* Skybox
*/
sky = new Sky(smgr->getRootSceneNode(), smgr, -1, texture_src);
+ scsf->setSky(sky);
skybox = NULL; // This is used/set later on in the main run loop
local_inventory = new Inventory(itemdef_manager);
}
};
+
/*
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 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 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)
*/
ShaderInfo generate_shader(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 = 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;
}
}
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)
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,
+ IrrlichtDevice *device, std::vector<ShaderCallback *> &callbacks,
+ const std::vector<IShaderConstantSetterFactory*> &setter_factories,
SourceShaderCache *sourcecache)
{
ShaderInfo shaderinfo;
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;
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
);
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
);
<<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
#ifndef SHADER_HEADER
#define SHADER_HEADER
+#include <IMaterialRendererServices.h>
#include "irrlichttypes_extrabloated.h"
#include "threads.h"
#include <string>
std::string getShaderPath(const std::string &name_of_shader,
const std::string &filename);
-struct ShaderInfo
-{
+struct ShaderInfo {
std::string name;
video::E_MATERIAL_TYPE base_material;
video::E_MATERIAL_TYPE material;
class IMaterialRendererServices;
} }
-class IShaderConstantSetter
-{
+
+class IShaderConstantSetter {
public:
virtual ~IShaderConstantSetter(){};
virtual void onSetConstants(video::IMaterialRendererServices *services,
bool is_highlevel) = 0;
};
+
+class IShaderConstantSetterFactory {
+public:
+ virtual ~IShaderConstantSetterFactory() {};
+ virtual IShaderConstantSetter* create() = 0;
+};
+
+
+template <typename T, std::size_t count=1>
+class CachedShaderSetting {
+ const char *m_name;
+ T m_sent[count];
+ bool has_been_set;
+ bool is_pixel;
+protected:
+ CachedShaderSetting(const char *name, bool is_pixel) :
+ m_name(name), has_been_set(false), is_pixel(is_pixel)
+ {}
+public:
+ void set(const T value[count], video::IMaterialRendererServices *services)
+ {
+ if (has_been_set && std::equal(m_sent, m_sent + count, value))
+ return;
+ if (is_pixel)
+ services->setPixelShaderConstant(m_name, value, count);
+ else
+ services->setVertexShaderConstant(m_name, value, count);
+ std::copy(value, value + count, m_sent);
+ has_been_set = true;
+ }
+};
+
+template <typename T, std::size_t count = 1>
+class CachedPixelShaderSetting : public CachedShaderSetting<T, count> {
+public:
+ CachedPixelShaderSetting(const char *name) :
+ CachedShaderSetting<T, count>(name, true){}
+};
+
+template <typename T, std::size_t count = 1>
+class CachedVertexShaderSetting : public CachedShaderSetting<T, count> {
+public:
+ CachedVertexShaderSetting(const char *name) :
+ CachedShaderSetting<T, count>(name, false){}
+};
+
+
/*
ShaderSource creates and caches shaders.
*/
-class IShaderSource
-{
+class IShaderSource {
public:
IShaderSource(){}
virtual ~IShaderSource(){}
const u8 material_type, const u8 drawtype){return 0;}
};
-class IWritableShaderSource : public IShaderSource
-{
+class IWritableShaderSource : public IShaderSource {
public:
IWritableShaderSource(){}
virtual ~IWritableShaderSource(){}
virtual void insertSourceShader(const std::string &name_of_shader,
const std::string &filename, const std::string &program)=0;
virtual void rebuildShaders()=0;
- virtual void addGlobalConstantSetter(IShaderConstantSetter *setter)=0;
+ virtual void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter) = 0;
};
IWritableShaderSource* createShaderSource(IrrlichtDevice *device);