/*
-Minetest-c55
-Copyright (C) 2012 celeron55, Perttu Ahola <celeron55@gmail.com>
-Copyright (C) 2012 Kahrl <kahrl@gmx.net>
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2013 Kahrl <kahrl@gmx.net>
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 2 of the License, or
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 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.
+GNU Lesser General Public License for more details.
-You should have received a copy of the GNU General Public License along
+You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "EShaderTypes.h"
#include "log.h"
#include "gamedef.h"
+#include "strfnd.h" // trim()
/*
A cache from shader name to shader path
const std::string &filename)
{
std::string combined = name_of_shader + DIR_DELIM + filename;
- core::map<std::string, std::string>::Node *n;
+ std::map<std::string, std::string>::iterator n;
n = m_programs.find(combined);
- if(n)
- return n->getValue();
+ if(n != m_programs.end())
+ return n->second;
return "";
}
// Primarily fetches from cache, secondarily tries to read from filesystem
const std::string &filename)
{
std::string combined = name_of_shader + DIR_DELIM + filename;
- core::map<std::string, std::string>::Node *n;
+ std::map<std::string, std::string>::iterator n;
n = m_programs.find(combined);
- if(n)
- return n->getValue();
+ if(n != m_programs.end())
+ return n->second;
std::string path = getShaderPath(name_of_shader, filename);
if(path == ""){
infostream<<"SourceShaderCache::getOrLoad(): No path found for \""
return "";
}
private:
- core::map<std::string, std::string> m_programs;
+ std::map<std::string, std::string> m_programs;
std::string readFile(const std::string &path)
{
std::ifstream is(path.c_str(), std::ios::binary);
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;
+
public:
- ShaderCallback(IrrlichtDevice *device): m_device(device) {}
+ ShaderCallback(IShaderConstantSetterRegistry *scsr, const std::string &name):
+ m_scsr(scsr),
+ m_name(name)
+ {}
~ShaderCallback() {}
virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData)
bool is_highlevel = userData;
+ m_scsr->onSetConstants(services, is_highlevel, m_name);
+ }
+};
+
+/*
+ MainShaderConstantSetter: Set basic constants required for almost everything
+*/
+
+class MainShaderConstantSetter : public IShaderConstantSetter
+{
+public:
+ MainShaderConstantSetter(IrrlichtDevice *device):
+ m_device(device)
+ {}
+ ~MainShaderConstantSetter() {}
+
+ virtual void onSetConstants(video::IMaterialRendererServices *services,
+ bool is_highlevel)
+ {
+ video::IVideoDriver *driver = services->getVideoDriver();
+ assert(driver);
+
// set inverted world matrix
core::matrix4 invWorld = driver->getTransform(video::ETS_WORLD);
invWorld.makeInverse();
ShaderSource
*/
-class ShaderSource : public IWritableShaderSource
+class ShaderSource : public IWritableShaderSource, public IShaderConstantSetterRegistry
{
public:
ShaderSource(IrrlichtDevice *device);
// Shall be called from the main thread.
void rebuildShaders();
+ void addGlobalConstantSetter(IShaderConstantSetter *setter)
+ {
+ m_global_setters.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
// A shader id is index in this array.
// The first position contains a dummy shader.
- core::array<ShaderInfo> m_shaderinfo_cache;
+ std::vector<ShaderInfo> m_shaderinfo_cache;
// Maps a shader name to an index in the former.
- core::map<std::string, u32> m_name_to_id;
+ std::map<std::string, u32> m_name_to_id;
// The two former containers are behind this mutex
JMutex m_shaderinfo_cache_mutex;
// 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;
};
IWritableShaderSource* createShaderSource(IrrlichtDevice *device)
Load shader programs
*/
void load_shaders(std::string name, SourceShaderCache *sourcecache,
- video::E_DRIVER_TYPE drivertype, s32 enable_shaders,
+ video::E_DRIVER_TYPE drivertype, bool enable_shaders,
std::string &vertex_program, std::string &pixel_program,
std::string &geometry_program, bool &is_highlevel);
{
assert(m_device);
- m_shader_callback = new ShaderCallback(device);
+ m_shader_callback = new ShaderCallback(this, "default");
m_shaderinfo_cache_mutex.Init();
// Add a dummy ShaderInfo as the first index, named ""
m_shaderinfo_cache.push_back(ShaderInfo());
m_name_to_id[""] = 0;
+
+ // Add main global constant setter
+ addGlobalConstantSetter(new MainShaderConstantSetter(device));
}
ShaderSource::~ShaderSource()
{
//m_shader_callback->drop();
+
+ for (std::vector<IShaderConstantSetter*>::iterator iter = m_global_setters.begin();
+ iter != m_global_setters.end(); iter++) {
+ delete *iter;
+ }
+ m_global_setters.clear();
}
u32 ShaderSource::getShaderId(const std::string &name)
See if shader already exists
*/
JMutexAutoLock lock(m_shaderinfo_cache_mutex);
- core::map<std::string, u32>::Node *n;
+ std::map<std::string, u32>::iterator n;
n = m_name_to_id.find(name);
- if(n != NULL)
- return n->getValue();
+ if(n != m_name_to_id.end())
+ return n->second;
}
/*
if(get_current_thread_id() == m_main_thread){
return getShaderIdDirect(name);
} else {
- infostream<<"getShaderId(): Queued: name=\""<<name<<"\""<<std::endl;
+ /*errorstream<<"getShaderId(): Queued: name=\""<<name<<"\""<<std::endl;*/
// We're gonna ask the result to be put into here
- ResultQueue<std::string, u32, u8, u8> result_queue;
+
+ static ResultQueue<std::string, u32, u8, u8> result_queue;
// Throw a request in
m_get_shader_queue.add(name, 0, 0, &result_queue);
- infostream<<"Waiting for shader from main thread, name=\""
- <<name<<"\""<<std::endl;
+ /* infostream<<"Waiting for shader from main thread, name=\""
+ <<name<<"\""<<std::endl;*/
try{
- // Wait result for a second
- GetResult<std::string, u32, u8, u8>
+ while(true) {
+ // Wait result for a second
+ GetResult<std::string, u32, u8, u8>
result = result_queue.pop_front(1000);
- // Check that at least something worked OK
- assert(result.key == name);
-
- return result.item;
+ if (result.key == name) {
+ return result.item;
+ }
+ }
}
catch(ItemNotFoundException &e){
- infostream<<"Waiting for shader timed out."<<std::endl;
+ errorstream<<"Waiting for shader " << name << " timed out."<<std::endl;
return 0;
}
}
{
JMutexAutoLock lock(m_shaderinfo_cache_mutex);
- core::map<std::string, u32>::Node *n;
+ std::map<std::string, u32>::iterator n;
n = m_name_to_id.find(name);
- if(n != NULL){
+ if(n != m_name_to_id.end()){
/*infostream<<"getShaderIdDirect(): \""<<name
<<"\" found in cache"<<std::endl;*/
- return n->getValue();
+ return n->second;
}
}
u32 id = m_shaderinfo_cache.size();
m_shaderinfo_cache.push_back(info);
- m_name_to_id.insert(name, id);
+ m_name_to_id[name] = id;
/*infostream<<"getShaderIdDirect(): "
<<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;*/
/*
Fetch shaders
*/
- if(m_get_shader_queue.size() > 0){
+ if(!m_get_shader_queue.empty()){
GetRequest<std::string, u32, u8, u8>
request = m_get_shader_queue.pop();
- /*infostream<<"ShaderSource::processQueue(): "
+ /**errorstream<<"ShaderSource::processQueue(): "
<<"got shader request with "
<<"name=\""<<request.key<<"\""
- <<std::endl;*/
+ <<std::endl;**/
- GetResult<std::string, u32, u8, u8>
- result;
- result.key = request.key;
- result.callers = request.callers;
- result.item = getShaderIdDirect(request.key);
-
- request.dest->push_back(result);
+ m_get_shader_queue.pushResult(request,getShaderIdDirect(request.key));
}
}
// Recreate shaders
for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
ShaderInfo *info = &m_shaderinfo_cache[i];
- *info = generate_shader(info->name, m_device,
- m_shader_callback, &m_sourcecache);
+ if(info->name != ""){
+ *info = generate_shader(info->name, m_device,
+ m_shader_callback, &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, IrrlichtDevice *device,
video::IShaderConstantSetCallBack *callback,
SourceShaderCache *sourcecache)
/*
Get the base material
*/
- std::string base_material_name = sourcecache->getOrLoad(name, "base.txt");
+ std::string base_material_name =
+ trim(sourcecache->getOrLoad(name, "base.txt"));
for(s32 i = 0; video::sBuiltInMaterialTypeNames[i] != 0; i++){
if(video::sBuiltInMaterialTypeNames[i] == base_material_name){
shaderinfo.material = (video::E_MATERIAL_TYPE) i;
}
}
- // 0 = off, 1 = assembly shaders only, 2 = highlevel or assembly
- s32 enable_shaders = g_settings->getS32("enable_shaders");
- if(enable_shaders <= 0)
+ bool enable_shaders = g_settings->getBool("enable_shaders");
+ if(!enable_shaders)
return shaderinfo;
video::IVideoDriver* driver = device->getVideoDriver();
}
void load_shaders(std::string name, SourceShaderCache *sourcecache,
- video::E_DRIVER_TYPE drivertype, s32 enable_shaders,
+ video::E_DRIVER_TYPE drivertype, bool enable_shaders,
std::string &vertex_program, std::string &pixel_program,
std::string &geometry_program, bool &is_highlevel)
{
geometry_program = "";
is_highlevel = false;
- if(enable_shaders >= 2){
+ if(enable_shaders){
// Look for high level shaders
if(drivertype == video::EDT_DIRECT3D9){
// Direct3D 9: HLSL
}
}
- if(enable_shaders >= 1){
- // Look for assembly shaders
- if(drivertype == video::EDT_DIRECT3D8){
- // Direct3D 8 assembly shaders
- vertex_program = sourcecache->getOrLoad(name, "d3d8_vertex.asm");
- pixel_program = sourcecache->getOrLoad(name, "d3d8_pixel.asm");
- }
- else if(drivertype == video::EDT_DIRECT3D9){
- // Direct3D 9 assembly shaders
- vertex_program = sourcecache->getOrLoad(name, "d3d9_vertex.asm");
- pixel_program = sourcecache->getOrLoad(name, "d3d9_pixel.asm");
- }
- else if(drivertype == video::EDT_OPENGL){
- // OpenGL assembly shaders
- vertex_program = sourcecache->getOrLoad(name, "opengl_vertex.asm");
- pixel_program = sourcecache->getOrLoad(name, "opengl_fragment.asm");
- }
- if(vertex_program != "" || pixel_program != "")
- return;
- }
}