|
@@ -36,6 +36,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
#include "log.h"
|
|
|
#include "gamedef.h"
|
|
|
#include "strfnd.h" // trim()
|
|
|
+#include "tile.h"
|
|
|
|
|
|
/*
|
|
|
A cache from shader name to shader path
|
|
@@ -210,7 +211,8 @@ public:
|
|
|
class MainShaderConstantSetter : public IShaderConstantSetter
|
|
|
{
|
|
|
public:
|
|
|
- MainShaderConstantSetter(IrrlichtDevice *device)
|
|
|
+ MainShaderConstantSetter(IrrlichtDevice *device):
|
|
|
+ m_device(device)
|
|
|
{}
|
|
|
~MainShaderConstantSetter() {}
|
|
|
|
|
@@ -254,6 +256,9 @@ public:
|
|
|
services->setVertexShaderConstant(world.pointer(), 8, 4);
|
|
|
|
|
|
}
|
|
|
+
|
|
|
+private:
|
|
|
+ IrrlichtDevice *m_device;
|
|
|
};
|
|
|
|
|
|
/*
|
|
@@ -266,13 +271,6 @@ public:
|
|
|
ShaderSource(IrrlichtDevice *device);
|
|
|
~ShaderSource();
|
|
|
|
|
|
- /*
|
|
|
- Gets a shader material id from cache or
|
|
|
- - if main thread, from getShaderIdDirect
|
|
|
- - if other thread, adds to request queue and waits for main thread
|
|
|
- */
|
|
|
- u32 getShaderId(const std::string &name);
|
|
|
-
|
|
|
/*
|
|
|
- If shader material specified by name is found from cache,
|
|
|
return the cached id.
|
|
@@ -280,26 +278,23 @@ public:
|
|
|
|
|
|
The id 0 points to a null shader. Its material is EMT_SOLID.
|
|
|
*/
|
|
|
- u32 getShaderIdDirect(const std::string &name);
|
|
|
-
|
|
|
- // Finds out the name of a cached shader.
|
|
|
- std::string getShaderName(u32 id);
|
|
|
+ u32 getShaderIdDirect(const std::string &name,
|
|
|
+ const u8 material_type, const u8 drawtype);
|
|
|
|
|
|
/*
|
|
|
If shader specified by the name pointed by the id doesn't
|
|
|
- exist, create it, then return the cached shader.
|
|
|
+ exist, create it, then return id.
|
|
|
|
|
|
Can be called from any thread. If called from some other thread
|
|
|
and not found in cache, the call is queued to the main thread
|
|
|
for processing.
|
|
|
*/
|
|
|
- ShaderInfo getShader(u32 id);
|
|
|
-
|
|
|
- ShaderInfo getShader(const std::string &name)
|
|
|
- {
|
|
|
- return getShader(getShaderId(name));
|
|
|
- }
|
|
|
-
|
|
|
+
|
|
|
+ u32 getShader(const std::string &name,
|
|
|
+ const u8 material_type, const u8 drawtype);
|
|
|
+
|
|
|
+ ShaderInfo getShaderInfo(u32 id);
|
|
|
+
|
|
|
// Processes queued shader requests from other threads.
|
|
|
// Shall be called from the main thread.
|
|
|
void processQueue();
|
|
@@ -337,9 +332,7 @@ private:
|
|
|
// A shader id is index in this array.
|
|
|
// The first position contains a dummy shader.
|
|
|
std::vector<ShaderInfo> m_shaderinfo_cache;
|
|
|
- // Maps a shader name to an index in the former.
|
|
|
- std::map<std::string, u32> m_name_to_id;
|
|
|
- // The two former containers are behind this mutex
|
|
|
+ // The former container is behind this mutex
|
|
|
JMutex m_shaderinfo_cache_mutex;
|
|
|
|
|
|
// Queued shader fetches (to be processed by the main thread)
|
|
@@ -358,7 +351,9 @@ IWritableShaderSource* createShaderSource(IrrlichtDevice *device)
|
|
|
/*
|
|
|
Generate shader given the shader name.
|
|
|
*/
|
|
|
-ShaderInfo generate_shader(std::string name, IrrlichtDevice *device,
|
|
|
+ShaderInfo generate_shader(std::string name,
|
|
|
+ u8 material_type, u8 drawtype,
|
|
|
+ IrrlichtDevice *device,
|
|
|
video::IShaderConstantSetCallBack *callback,
|
|
|
SourceShaderCache *sourcecache);
|
|
|
|
|
@@ -381,7 +376,6 @@ ShaderSource::ShaderSource(IrrlichtDevice *device):
|
|
|
|
|
|
// 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));
|
|
@@ -398,28 +392,17 @@ ShaderSource::~ShaderSource()
|
|
|
m_global_setters.clear();
|
|
|
}
|
|
|
|
|
|
-u32 ShaderSource::getShaderId(const std::string &name)
|
|
|
+u32 ShaderSource::getShader(const std::string &name,
|
|
|
+ const u8 material_type, const u8 drawtype)
|
|
|
{
|
|
|
- //infostream<<"getShaderId(): \""<<name<<"\""<<std::endl;
|
|
|
-
|
|
|
- {
|
|
|
- /*
|
|
|
- See if shader already exists
|
|
|
- */
|
|
|
- JMutexAutoLock lock(m_shaderinfo_cache_mutex);
|
|
|
- std::map<std::string, u32>::iterator n;
|
|
|
- n = m_name_to_id.find(name);
|
|
|
- if(n != m_name_to_id.end())
|
|
|
- return n->second;
|
|
|
- }
|
|
|
-
|
|
|
/*
|
|
|
Get shader
|
|
|
*/
|
|
|
+
|
|
|
if(get_current_thread_id() == m_main_thread){
|
|
|
- return getShaderIdDirect(name);
|
|
|
+ return getShaderIdDirect(name, material_type, drawtype);
|
|
|
} else {
|
|
|
- /*errorstream<<"getShaderId(): Queued: name=\""<<name<<"\""<<std::endl;*/
|
|
|
+ /*errorstream<<"getShader(): Queued: name=\""<<name<<"\""<<std::endl;*/
|
|
|
|
|
|
// We're gonna ask the result to be put into here
|
|
|
|
|
@@ -445,7 +428,7 @@ u32 ShaderSource::getShaderId(const std::string &name)
|
|
|
|
|
|
}
|
|
|
|
|
|
- infostream<<"getShaderId(): Failed"<<std::endl;
|
|
|
+ infostream<<"getShader(): Failed"<<std::endl;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -453,7 +436,8 @@ u32 ShaderSource::getShaderId(const std::string &name)
|
|
|
/*
|
|
|
This method generates all the shaders
|
|
|
*/
|
|
|
-u32 ShaderSource::getShaderIdDirect(const std::string &name)
|
|
|
+u32 ShaderSource::getShaderIdDirect(const std::string &name,
|
|
|
+ const u8 material_type, const u8 drawtype)
|
|
|
{
|
|
|
//infostream<<"getShaderIdDirect(): name=\""<<name<<"\""<<std::endl;
|
|
|
|
|
@@ -463,6 +447,14 @@ u32 ShaderSource::getShaderIdDirect(const std::string &name)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+ // Check if already have such instance
|
|
|
+ for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
|
|
|
+ ShaderInfo *info = &m_shaderinfo_cache[i];
|
|
|
+ if(info->name == name && info->material_type == material_type &&
|
|
|
+ info->drawtype == drawtype)
|
|
|
+ return i;
|
|
|
+ }
|
|
|
+
|
|
|
/*
|
|
|
Calling only allowed from main thread
|
|
|
*/
|
|
@@ -472,25 +464,7 @@ u32 ShaderSource::getShaderIdDirect(const std::string &name)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
- /*
|
|
|
- See if shader already exists
|
|
|
- */
|
|
|
- {
|
|
|
- JMutexAutoLock lock(m_shaderinfo_cache_mutex);
|
|
|
-
|
|
|
- std::map<std::string, u32>::iterator n;
|
|
|
- n = m_name_to_id.find(name);
|
|
|
- if(n != m_name_to_id.end()){
|
|
|
- /*infostream<<"getShaderIdDirect(): \""<<name
|
|
|
- <<"\" found in cache"<<std::endl;*/
|
|
|
- return n->second;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /*infostream<<"getShaderIdDirect(): \""<<name
|
|
|
- <<"\" NOT found in cache. Creating it."<<std::endl;*/
|
|
|
-
|
|
|
- ShaderInfo info = generate_shader(name, m_device,
|
|
|
+ ShaderInfo info = generate_shader(name, material_type, drawtype, m_device,
|
|
|
m_shader_callback, &m_sourcecache);
|
|
|
|
|
|
/*
|
|
@@ -501,29 +475,15 @@ u32 ShaderSource::getShaderIdDirect(const std::string &name)
|
|
|
|
|
|
u32 id = m_shaderinfo_cache.size();
|
|
|
m_shaderinfo_cache.push_back(info);
|
|
|
- m_name_to_id[name] = id;
|
|
|
|
|
|
- /*infostream<<"getShaderIdDirect(): "
|
|
|
- <<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;*/
|
|
|
+ infostream<<"getShaderIdDirect(): "
|
|
|
+ <<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;
|
|
|
|
|
|
return id;
|
|
|
}
|
|
|
|
|
|
-std::string ShaderSource::getShaderName(u32 id)
|
|
|
-{
|
|
|
- JMutexAutoLock lock(m_shaderinfo_cache_mutex);
|
|
|
-
|
|
|
- if(id >= m_shaderinfo_cache.size()){
|
|
|
- errorstream<<"ShaderSource::getShaderName(): id="<<id
|
|
|
- <<" >= m_shaderinfo_cache.size()="
|
|
|
- <<m_shaderinfo_cache.size()<<std::endl;
|
|
|
- return "";
|
|
|
- }
|
|
|
|
|
|
- return m_shaderinfo_cache[id].name;
|
|
|
-}
|
|
|
-
|
|
|
-ShaderInfo ShaderSource::getShader(u32 id)
|
|
|
+ShaderInfo ShaderSource::getShaderInfo(u32 id)
|
|
|
{
|
|
|
JMutexAutoLock lock(m_shaderinfo_cache_mutex);
|
|
|
|
|
@@ -535,21 +495,8 @@ ShaderInfo ShaderSource::getShader(u32 id)
|
|
|
|
|
|
void ShaderSource::processQueue()
|
|
|
{
|
|
|
- /*
|
|
|
- Fetch shaders
|
|
|
- */
|
|
|
- //NOTE this is only thread safe for ONE consumer thread!
|
|
|
- if(!m_get_shader_queue.empty()){
|
|
|
- GetRequest<std::string, u32, u8, u8>
|
|
|
- request = m_get_shader_queue.pop();
|
|
|
+
|
|
|
|
|
|
- /**errorstream<<"ShaderSource::processQueue(): "
|
|
|
- <<"got shader request with "
|
|
|
- <<"name=\""<<request.key<<"\""
|
|
|
- <<std::endl;**/
|
|
|
-
|
|
|
- m_get_shader_queue.pushResult(request,getShaderIdDirect(request.key));
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
void ShaderSource::insertSourceShader(const std::string &name_of_shader,
|
|
@@ -582,8 +529,8 @@ void ShaderSource::rebuildShaders()
|
|
|
for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
|
|
|
ShaderInfo *info = &m_shaderinfo_cache[i];
|
|
|
if(info->name != ""){
|
|
|
- *info = generate_shader(info->name, m_device,
|
|
|
- m_shader_callback, &m_sourcecache);
|
|
|
+ *info = generate_shader(info->name, info->material_type,
|
|
|
+ info->drawtype, m_device, m_shader_callback, &m_sourcecache);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -597,29 +544,36 @@ void ShaderSource::onSetConstants(video::IMaterialRendererServices *services,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-ShaderInfo generate_shader(std::string name, IrrlichtDevice *device,
|
|
|
- video::IShaderConstantSetCallBack *callback,
|
|
|
+ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
|
|
|
+ IrrlichtDevice *device, video::IShaderConstantSetCallBack *callback,
|
|
|
SourceShaderCache *sourcecache)
|
|
|
{
|
|
|
- /*infostream<<"generate_shader(): "
|
|
|
- "\""<<name<<"\""<<std::endl;*/
|
|
|
-
|
|
|
ShaderInfo shaderinfo;
|
|
|
shaderinfo.name = name;
|
|
|
+ shaderinfo.material_type = material_type;
|
|
|
+ shaderinfo.drawtype = drawtype;
|
|
|
shaderinfo.material = video::EMT_SOLID;
|
|
|
-
|
|
|
- /*
|
|
|
- Get the base material
|
|
|
- */
|
|
|
- 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;
|
|
|
+ switch(material_type){
|
|
|
+ case TILE_MATERIAL_BASIC:
|
|
|
+ shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
|
|
break;
|
|
|
- }
|
|
|
+ case TILE_MATERIAL_ALPHA:
|
|
|
+ shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
|
|
+ break;
|
|
|
+ case TILE_MATERIAL_LIQUID_TRANSPARENT:
|
|
|
+ shaderinfo.base_material = video::EMT_TRANSPARENT_VERTEX_ALPHA;
|
|
|
+ break;
|
|
|
+ case TILE_MATERIAL_LIQUID_OPAQUE:
|
|
|
+ shaderinfo.base_material = video::EMT_SOLID;
|
|
|
+ break;
|
|
|
+ case TILE_MATERIAL_WAVING_LEAVES:
|
|
|
+ shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
|
|
+ break;
|
|
|
+ case TILE_MATERIAL_WAVING_PLANTS:
|
|
|
+ shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
|
|
+ break;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
bool enable_shaders = g_settings->getBool("enable_shaders");
|
|
|
if(!enable_shaders)
|
|
|
return shaderinfo;
|
|
@@ -645,7 +599,6 @@ ShaderInfo generate_shader(std::string name, IrrlichtDevice *device,
|
|
|
load_shaders(name, sourcecache, driver->getDriverType(),
|
|
|
enable_shaders, vertex_program, pixel_program,
|
|
|
geometry_program, is_highlevel);
|
|
|
-
|
|
|
// Check hardware/driver support
|
|
|
if(vertex_program != "" &&
|
|
|
!driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
|
|
@@ -678,6 +631,55 @@ ShaderInfo generate_shader(std::string name, IrrlichtDevice *device,
|
|
|
// Create shaders header
|
|
|
std::string shaders_header = "#version 120\n";
|
|
|
|
|
|
+ static const char* drawTypes[] = {
|
|
|
+ "NDT_NORMAL",
|
|
|
+ "NDT_AIRLIKE",
|
|
|
+ "NDT_LIQUID",
|
|
|
+ "NDT_FLOWINGLIQUID",
|
|
|
+ "NDT_GLASSLIKE",
|
|
|
+ "NDT_ALLFACES",
|
|
|
+ "NDT_ALLFACES_OPTIONAL",
|
|
|
+ "NDT_TORCHLIKE",
|
|
|
+ "NDT_SIGNLIKE",
|
|
|
+ "NDT_PLANTLIKE",
|
|
|
+ "NDT_FENCELIKE",
|
|
|
+ "NDT_RAILLIKE",
|
|
|
+ "NDT_NODEBOX",
|
|
|
+ "NDT_GLASSLIKE_FRAMED"
|
|
|
+ };
|
|
|
+
|
|
|
+ for (int i = 0; i < 14; i++){
|
|
|
+ shaders_header += "#define ";
|
|
|
+ shaders_header += drawTypes[i];
|
|
|
+ shaders_header += " ";
|
|
|
+ shaders_header += itos(i);
|
|
|
+ shaders_header += "\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ static const char* materialTypes[] = {
|
|
|
+ "TILE_MATERIAL_BASIC",
|
|
|
+ "TILE_MATERIAL_ALPHA",
|
|
|
+ "TILE_MATERIAL_LIQUID_TRANSPARENT",
|
|
|
+ "TILE_MATERIAL_LIQUID_OPAQUE",
|
|
|
+ "TILE_MATERIAL_WAVING_LEAVES",
|
|
|
+ "TILE_MATERIAL_WAVING_PLANTS"
|
|
|
+ };
|
|
|
+
|
|
|
+ for (int i = 0; i < 6; i++){
|
|
|
+ shaders_header += "#define ";
|
|
|
+ shaders_header += materialTypes[i];
|
|
|
+ shaders_header += " ";
|
|
|
+ shaders_header += itos(i);
|
|
|
+ shaders_header += "\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ shaders_header += "#define MATERIAL_TYPE ";
|
|
|
+ shaders_header += itos(material_type);
|
|
|
+ shaders_header += "\n";
|
|
|
+ shaders_header += "#define DRAW_TYPE ";
|
|
|
+ shaders_header += itos(drawtype);
|
|
|
+ shaders_header += "\n";
|
|
|
+
|
|
|
if (g_settings->getBool("generate_normalmaps")){
|
|
|
shaders_header += "#define GENERATE_NORMALMAPS\n";
|
|
|
shaders_header += "#define NORMALMAPS_STRENGTH ";
|
|
@@ -721,7 +723,7 @@ ShaderInfo generate_shader(std::string name, IrrlichtDevice *device,
|
|
|
shaders_header += "#define USE_NORMALMAPS\n";
|
|
|
|
|
|
if (g_settings->getBool("enable_waving_water")){
|
|
|
- shaders_header += "#define ENABLE_WAVING_WATER\n";
|
|
|
+ shaders_header += "#define ENABLE_WAVING_WATER 1\n";
|
|
|
shaders_header += "#define WATER_WAVE_HEIGHT ";
|
|
|
shaders_header += ftos(g_settings->getFloat("water_wave_height"));
|
|
|
shaders_header += "\n";
|
|
@@ -731,13 +733,21 @@ ShaderInfo generate_shader(std::string name, IrrlichtDevice *device,
|
|
|
shaders_header += "#define WATER_WAVE_SPEED ";
|
|
|
shaders_header += ftos(g_settings->getFloat("water_wave_speed"));
|
|
|
shaders_header += "\n";
|
|
|
+ } else{
|
|
|
+ shaders_header += "#define ENABLE_WAVING_WATER 0\n";
|
|
|
}
|
|
|
|
|
|
+ shaders_header += "#define ENABLE_WAVING_LEAVES ";
|
|
|
if (g_settings->getBool("enable_waving_leaves"))
|
|
|
- shaders_header += "#define ENABLE_WAVING_LEAVES\n";
|
|
|
+ shaders_header += "1\n";
|
|
|
+ else
|
|
|
+ shaders_header += "0\n";
|
|
|
|
|
|
+ shaders_header += "#define ENABLE_WAVING_PLANTS ";
|
|
|
if (g_settings->getBool("enable_waving_plants"))
|
|
|
- shaders_header += "#define ENABLE_WAVING_PLANTS\n";
|
|
|
+ shaders_header += "1\n";
|
|
|
+ else
|
|
|
+ shaders_header += "0\n";
|
|
|
|
|
|
if(pixel_program != "")
|
|
|
pixel_program = shaders_header + pixel_program;
|
|
@@ -772,11 +782,10 @@ ShaderInfo generate_shader(std::string name, IrrlichtDevice *device,
|
|
|
scene::EPT_TRIANGLES, // Geometry shader input
|
|
|
scene::EPT_TRIANGLE_STRIP, // Geometry shader output
|
|
|
0, // Support maximum number of vertices
|
|
|
- callback, // Set-constant callback
|
|
|
- shaderinfo.material, // Base material
|
|
|
- 1 // Userdata passed to callback
|
|
|
+ callback, // Set-constant callback
|
|
|
+ shaderinfo.base_material, // Base material
|
|
|
+ 1 // Userdata passed to callback
|
|
|
);
|
|
|
-
|
|
|
if(shadermat == -1){
|
|
|
errorstream<<"generate_shader(): "
|
|
|
"failed to generate \""<<name<<"\", "
|
|
@@ -791,7 +800,7 @@ ShaderInfo generate_shader(std::string name, IrrlichtDevice *device,
|
|
|
vertex_program_ptr, // Vertex shader program
|
|
|
pixel_program_ptr, // Pixel shader program
|
|
|
callback, // Set-constant callback
|
|
|
- shaderinfo.material, // Base material
|
|
|
+ shaderinfo.base_material, // Base material
|
|
|
0 // Userdata passed to callback
|
|
|
);
|
|
|
|