Open source Star Ruler 2 source code!
This commit is contained in:
@@ -0,0 +1,925 @@
|
||||
#include "render/shader.h"
|
||||
#include "render/gl_shader.h"
|
||||
#include "compat/gl.h"
|
||||
#include "compat/misc.h"
|
||||
#include "str_util.h"
|
||||
#include "files.h"
|
||||
#include "main/logging.h"
|
||||
#include "main/references.h"
|
||||
|
||||
extern unsigned frameNumber;
|
||||
|
||||
namespace render {
|
||||
|
||||
void preProcessShader(std::string& shader) {
|
||||
std::string output;
|
||||
size_t start = 0;
|
||||
while(start < shader.size()) {
|
||||
size_t pos = shader.find('#', start);
|
||||
if(pos == std::string::npos)
|
||||
break;
|
||||
|
||||
if(pos != start)
|
||||
output += shader.substr(start, pos-start);
|
||||
|
||||
if(shader.size() - pos > 3 && shader[pos+1] == '{' && shader[pos+2] == '{') {
|
||||
size_t endpos = shader.find("}}", pos, 2);
|
||||
if(endpos == std::string::npos)
|
||||
break;
|
||||
|
||||
std::string value = shader.substr(pos+3, endpos-pos-3);
|
||||
std::string replace;
|
||||
|
||||
if(value == "level:extreme") {
|
||||
auto* sl = devices.settings.engine.getSetting("iShaderLevel");
|
||||
if(sl)
|
||||
output += (sl->getInteger() >= 4) ? "true" : "false";
|
||||
}
|
||||
else if(value == "level:high") {
|
||||
auto* sl = devices.settings.engine.getSetting("iShaderLevel");
|
||||
if(sl)
|
||||
output += (sl->getInteger() >= 3) ? "true" : "false";
|
||||
}
|
||||
else if(value == "level:medium") {
|
||||
auto* sl = devices.settings.engine.getSetting("iShaderLevel");
|
||||
if(sl)
|
||||
output += (sl->getInteger() >= 2) ? "true" : "false";
|
||||
}
|
||||
else if(value == "fallback") {
|
||||
auto* fallback = devices.settings.engine.getSetting("bShaderFallback");
|
||||
if(fallback)
|
||||
output += (fallback->getBool()) ? "true" : "false";
|
||||
}
|
||||
else {
|
||||
auto* setting = devices.settings.engine.getSetting(value.c_str());
|
||||
if(!setting)
|
||||
setting = devices.settings.mod.getSetting(value.c_str());
|
||||
|
||||
if(setting) {
|
||||
switch(setting->type) {
|
||||
case GT_Bool:
|
||||
output += (setting->getBool()) ? "true" : "false";
|
||||
break;
|
||||
case GT_Integer:
|
||||
case GT_Enum:
|
||||
output += toString<int>(setting->getInteger());
|
||||
break;
|
||||
case GT_Double:
|
||||
output += toString<double>(setting->getDouble());
|
||||
break;
|
||||
case GT_String:
|
||||
output += *setting->getString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
error("ERROR: Could not find shader variable %s.", value.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
start = endpos + 2;
|
||||
}
|
||||
else if(shader.size() - pos > 11 && shader.compare(pos, 10, "#include \"") == 0) {
|
||||
size_t endpos = shader.find("\"", pos+10, 1);
|
||||
if(endpos == std::string::npos)
|
||||
break;
|
||||
|
||||
std::string value = shader.substr(pos+10, endpos-pos-10);
|
||||
std::string fname = devices.mods.resolve(value);
|
||||
if(!fileExists(fname)) {
|
||||
error("ERROR COMPILING SHADER: Could not find include file %s. (Resolved to %s)", value.c_str(), fname.c_str());
|
||||
}
|
||||
else {
|
||||
std::string includeContents = getFileContents(fname);
|
||||
preProcessShader(includeContents);
|
||||
output += includeContents;
|
||||
}
|
||||
|
||||
start = endpos + 1;
|
||||
}
|
||||
else {
|
||||
output += "#";
|
||||
start = pos + 1;
|
||||
}
|
||||
}
|
||||
if(start < shader.size())
|
||||
output += shader.substr(start, shader.size()-start);
|
||||
shader = output;
|
||||
}
|
||||
|
||||
class GLShader;
|
||||
class GLShaderProgram : public ShaderProgram {
|
||||
public:
|
||||
GLuint vertex_shader, fragment_shader, program;
|
||||
std::string vertex_file, fragment_file;
|
||||
|
||||
std::unordered_map<GLuint, unsigned> cached_uniforms;
|
||||
std::vector<float> mem_buffer;
|
||||
|
||||
const GLShader* lastShader;
|
||||
|
||||
GLShaderProgram(const std::string& vFile, const std::string& fFile)
|
||||
: vertex_file(vFile), fragment_file(fFile), program(0), lastShader(0)
|
||||
{
|
||||
}
|
||||
|
||||
~GLShaderProgram() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
if(program != 0) {
|
||||
glDeleteProgram(program);
|
||||
program = 0;
|
||||
}
|
||||
|
||||
mem_buffer.clear();
|
||||
cached_uniforms.clear();
|
||||
}
|
||||
|
||||
unsigned cacheUniform(GLuint position, size_t size) {
|
||||
auto it = cached_uniforms.find(position);
|
||||
if(it != cached_uniforms.end())
|
||||
return it->second;
|
||||
|
||||
unsigned pos = (unsigned)mem_buffer.size();
|
||||
cached_uniforms[position] = pos;
|
||||
|
||||
for(size_t i = 0; i < size; ++i)
|
||||
mem_buffer.push_back(0);
|
||||
return pos;
|
||||
}
|
||||
|
||||
GLuint compileShader(GLenum type, const std::string& fname, const std::string& source) {
|
||||
GLuint shader;
|
||||
|
||||
//Compile
|
||||
const GLchar* str_ptr = (const GLchar*)source.c_str();
|
||||
GLint str_len = (GLint)source.size();
|
||||
shader = glCreateShader(type);
|
||||
glShaderSource(shader, 1, &str_ptr, &str_len);
|
||||
glCompileShader(shader);
|
||||
|
||||
//Check compile value
|
||||
GLint shader_ok;
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &shader_ok);
|
||||
|
||||
if(!shader_ok) {
|
||||
error("Failed to compile shader: %s", fname.c_str());
|
||||
|
||||
GLint log_length;
|
||||
char* log;
|
||||
|
||||
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
|
||||
log = (char*)malloc(log_length);
|
||||
|
||||
glGetShaderInfoLog(shader, log_length, NULL, log);
|
||||
error("%s", log);
|
||||
|
||||
free(log);
|
||||
|
||||
glDeleteShader(shader);
|
||||
return 0;
|
||||
}
|
||||
else if(getLogLevel() == LL_Info) {
|
||||
//Print warnings in verbose
|
||||
GLint log_length;
|
||||
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
|
||||
|
||||
//We're always provided at least an empty string, just ignore very small logs
|
||||
if(log_length > 8) {
|
||||
char* log;
|
||||
log = (char*)malloc(log_length);
|
||||
|
||||
glGetShaderInfoLog(shader, log_length, NULL, log);
|
||||
error("Shader '%s' has warnings:\n%s", fname.c_str(), log);
|
||||
|
||||
free(log);
|
||||
}
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
int compile() override {
|
||||
reset();
|
||||
//Compile vertex shader
|
||||
{
|
||||
auto contents = getFileContents(vertex_file);
|
||||
preProcessShader(contents);
|
||||
if(contents.empty()) {
|
||||
error("Could not open vertex shader, or the file was empty");
|
||||
return 1;
|
||||
}
|
||||
|
||||
vertex_shader = compileShader(GL_VERTEX_SHADER, vertex_file, contents);
|
||||
if(!vertex_shader)
|
||||
return 1;
|
||||
}
|
||||
|
||||
//Compile fragment shader
|
||||
{
|
||||
auto contents = getFileContents(fragment_file);
|
||||
preProcessShader(contents);
|
||||
fragment_shader = compileShader(GL_FRAGMENT_SHADER, fragment_file, contents);
|
||||
if(!fragment_shader) {
|
||||
if(contents.empty())
|
||||
error("Could not open fragment shader, or the file was empty");
|
||||
glDeleteShader(vertex_shader);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
//Link entire program
|
||||
program = glCreateProgram();
|
||||
|
||||
glBindAttribLocation(program, 0, "in_vertex");
|
||||
glBindAttribLocation(program, 2, "in_normal");
|
||||
glBindAttribLocation(program, 1, "in_uv");
|
||||
glBindAttribLocation(program, 3, "in_tangent");
|
||||
glBindAttribLocation(program, 4, "in_color");
|
||||
glBindAttribLocation(program, 5, "in_uv2");
|
||||
|
||||
glAttachShader(program, vertex_shader);
|
||||
glAttachShader(program, fragment_shader);
|
||||
glLinkProgram(program);
|
||||
|
||||
glDeleteShader(vertex_shader);
|
||||
glDeleteShader(fragment_shader);
|
||||
|
||||
//Make sure it linked correctly
|
||||
GLint status;
|
||||
glGetProgramiv(program,GL_LINK_STATUS,&status);
|
||||
if(status == GL_FALSE) {
|
||||
error("Linking failed:");
|
||||
GLint log_length;
|
||||
char* log;
|
||||
|
||||
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
|
||||
log = (char*)malloc(log_length);
|
||||
|
||||
glGetProgramInfoLog(program, log_length, NULL, log);
|
||||
error("%s", log);
|
||||
|
||||
free(log);
|
||||
|
||||
glDeleteProgram(program);
|
||||
program = 0;
|
||||
return 3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
class GLShader : public Shader {
|
||||
public:
|
||||
mutable unsigned lastBoundFrame;
|
||||
|
||||
std::vector<std::string> uniform_names;
|
||||
std::vector<GLuint> uniform_locations;
|
||||
std::vector<unsigned> uniform_vars;
|
||||
std::vector<unsigned> uniform_cache;
|
||||
|
||||
GLShader()
|
||||
{
|
||||
program = 0;
|
||||
constant = true;
|
||||
dynamicFloats = 0;
|
||||
lastBoundFrame = 0xffffffff;
|
||||
}
|
||||
|
||||
~GLShader() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
uniform_locations.clear();
|
||||
uniform_cache.clear();
|
||||
uniform_vars.clear();
|
||||
}
|
||||
|
||||
virtual int compile() {
|
||||
reset();
|
||||
|
||||
if(!program) {
|
||||
error("No associated program");
|
||||
return 4;
|
||||
}
|
||||
|
||||
auto glProgram = (GLShaderProgram*)program;
|
||||
if(glProgram->program == 0)
|
||||
return 4;
|
||||
|
||||
bool missingVars = false;
|
||||
for(unsigned i = 0; i < uniform_names.size(); ++i) {
|
||||
GLuint location = glGetUniformLocation(glProgram->program, uniform_names[i].c_str());
|
||||
|
||||
if(location == (GLuint)-1) {
|
||||
//NOTE: This is no longer considered an error, because dynamic shader levels
|
||||
//are going to be causing uniforms to be missing all the time.
|
||||
//
|
||||
//error("Unable to find uniform '%s'", uniform_names[i].c_str());
|
||||
//missingVars = true;
|
||||
}
|
||||
else {
|
||||
uniform_locations.push_back(location);
|
||||
uniform_vars.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned i = 0; i < uniform_locations.size(); ++i) {
|
||||
auto& v = vars[uniform_vars[i]];
|
||||
size_t size = 0;
|
||||
switch(v.type) {
|
||||
case VT_int: case VT_float: size = 1; break;
|
||||
case VT_int2: case VT_float2: size = 2; break;
|
||||
case VT_int3: case VT_float3: size = 3; break;
|
||||
case VT_int4: case VT_float4: size = 4; break;
|
||||
case VT_mat3: size = 9; break;
|
||||
}
|
||||
|
||||
size *= v.count;
|
||||
uniform_cache.push_back(glProgram->cacheUniform(uniform_locations[i], size));
|
||||
}
|
||||
|
||||
if(missingVars)
|
||||
return 4;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual void addVariable(const std::string& name, const Variable& var) {
|
||||
uniform_names.push_back(name);
|
||||
Shader::addVariable(name, var);
|
||||
}
|
||||
|
||||
virtual void bind(float* dynamic) const {
|
||||
if(!program) {
|
||||
glUseProgram(0);
|
||||
return;
|
||||
}
|
||||
|
||||
auto glProgram = (GLShaderProgram*)program;
|
||||
if(auto programID = glProgram->program) {
|
||||
glUseProgram(programID);
|
||||
}
|
||||
else {
|
||||
glUseProgram(0);
|
||||
return;
|
||||
}
|
||||
|
||||
const bool bindConst = lastBoundFrame != frameNumber || glProgram->lastShader != this;
|
||||
lastBoundFrame = frameNumber;
|
||||
glProgram->lastShader = this;
|
||||
|
||||
if(dynamic) {
|
||||
float* floats = dynamic;
|
||||
|
||||
for(size_t i = 0, cnt = uniform_locations.size(); i < cnt; ++i) {
|
||||
const Shader::Variable& var = vars[uniform_vars[i]];
|
||||
if(!bindConst && var.constant)
|
||||
continue;
|
||||
|
||||
GLuint uniform = uniform_locations[i];
|
||||
void* uniformMem = (void*)&glProgram->mem_buffer[uniform_cache[i]];
|
||||
|
||||
switch(var.type) {
|
||||
case VT_invalid:
|
||||
break;
|
||||
|
||||
case VT_int:
|
||||
if(var.constant) {
|
||||
if(var._intcall)
|
||||
var._intcall(var._ints, var.count, var._args);
|
||||
|
||||
if(memcmp(uniformMem, var._ints, var.count * 4) != 0) {
|
||||
glUniform1iv(uniform, var.count, var._ints);
|
||||
memcpy(uniformMem, var._ints, var.count * 4);
|
||||
}
|
||||
}
|
||||
else if(var._intcall) {
|
||||
if(memcmp(uniformMem, floats, var.count * 4) != 0) {
|
||||
glUniform1iv(uniform, var.count, (int*)floats);
|
||||
memcpy(uniformMem, floats, var.count * 4);
|
||||
}
|
||||
floats += var.count;
|
||||
}
|
||||
break;
|
||||
case VT_int2:
|
||||
if(var.constant) {
|
||||
if(var._intcall)
|
||||
var._intcall(var._ints, var.count, var._args);
|
||||
|
||||
if(memcmp(uniformMem, var._ints, var.count * 8) != 0) {
|
||||
glUniform2iv(uniform, var.count, var._ints);
|
||||
memcpy(uniformMem, var._ints, var.count * 8);
|
||||
}
|
||||
}
|
||||
else if(var._intcall) {
|
||||
if(memcmp(uniformMem, floats, var.count * 8) != 0) {
|
||||
glUniform2iv(uniform, var.count, (int*)floats);
|
||||
memcpy(uniformMem, floats, var.count * 8);
|
||||
}
|
||||
floats += var.count * 2;
|
||||
}
|
||||
break;
|
||||
case VT_int3:
|
||||
if(var.constant) {
|
||||
if(var._intcall)
|
||||
var._intcall(var._ints, var.count, var._args);
|
||||
|
||||
if(memcmp(uniformMem, var._ints, var.count * 12) != 0) {
|
||||
glUniform3iv(uniform, var.count, var._ints);
|
||||
memcpy(uniformMem, var._ints, var.count * 12);
|
||||
}
|
||||
}
|
||||
else if(var._intcall) {
|
||||
if(memcmp(uniformMem, floats, var.count * 12) != 0) {
|
||||
glUniform3iv(uniform, var.count, (int*)floats);
|
||||
memcpy(uniformMem, floats, var.count * 12);
|
||||
}
|
||||
floats += var.count * 3;
|
||||
}
|
||||
break;
|
||||
case VT_int4:
|
||||
if(var.constant) {
|
||||
if(var._intcall)
|
||||
var._intcall(var._ints, var.count, var._args);
|
||||
|
||||
if(memcmp(uniformMem, var._ints, var.count * 16) != 0) {
|
||||
glUniform4iv(uniform, var.count, var._ints);
|
||||
memcpy(uniformMem, var._ints, var.count * 16);
|
||||
}
|
||||
}
|
||||
else if(var._intcall) {
|
||||
if(memcmp(uniformMem, floats, var.count * 16) != 0) {
|
||||
glUniform4iv(uniform, var.count, (int*)floats);
|
||||
memcpy(uniformMem, floats, var.count * 16);
|
||||
}
|
||||
floats += var.count * 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_float:
|
||||
if(var.constant) {
|
||||
if(var._floatcall)
|
||||
var._floatcall(var._floats, var.count, var._args);
|
||||
|
||||
if(memcmp(uniformMem, var._floats, var.count * 4) != 0) {
|
||||
glUniform1fv(uniform, var.count, var._floats);
|
||||
memcpy(uniformMem, var._floats, var.count * 4);
|
||||
}
|
||||
}
|
||||
else if(var._intcall) {
|
||||
if(memcmp(uniformMem, floats, var.count * 4) != 0) {
|
||||
glUniform1fv(uniform, var.count, floats);
|
||||
memcpy(uniformMem, floats, var.count * 4);
|
||||
}
|
||||
floats += var.count;
|
||||
}
|
||||
break;
|
||||
case VT_float2:
|
||||
if(var.constant) {
|
||||
if(var._floatcall)
|
||||
var._floatcall(var._floats, var.count, var._args);
|
||||
|
||||
if(memcmp(uniformMem, var._floats, var.count * 8) != 0) {
|
||||
glUniform2fv(uniform, var.count, var._floats);
|
||||
memcpy(uniformMem, var._floats, var.count * 8);
|
||||
}
|
||||
}
|
||||
else if(var._intcall) {
|
||||
if(memcmp(uniformMem, floats, var.count * 8) != 0) {
|
||||
glUniform2fv(uniform, var.count, floats);
|
||||
memcpy(uniformMem, floats, var.count * 8);
|
||||
}
|
||||
floats += var.count * 2;
|
||||
}
|
||||
break;
|
||||
case VT_float3:
|
||||
if(var.constant) {
|
||||
if(var._floatcall)
|
||||
var._floatcall(var._floats, var.count, var._args);
|
||||
|
||||
if(memcmp(uniformMem, var._floats, var.count * 12) != 0) {
|
||||
glUniform3fv(uniform, var.count, var._floats);
|
||||
memcpy(uniformMem, var._floats, var.count * 12);
|
||||
}
|
||||
}
|
||||
else if(var._intcall) {
|
||||
if(memcmp(uniformMem, floats, var.count * 12) != 0) {
|
||||
glUniform3fv(uniform, var.count, floats);
|
||||
memcpy(uniformMem, floats, var.count * 12);
|
||||
}
|
||||
floats += var.count * 3;
|
||||
}
|
||||
break;
|
||||
case VT_float4:
|
||||
if(var.constant) {
|
||||
if(var._floatcall)
|
||||
var._floatcall(var._floats, var.count, var._args);
|
||||
|
||||
if(memcmp(uniformMem, var._floats, var.count * 16) != 0) {
|
||||
glUniform4fv(uniform, var.count, var._floats);
|
||||
memcpy(uniformMem, var._floats, var.count * 16);
|
||||
}
|
||||
}
|
||||
else if(var._intcall) {
|
||||
if(memcmp(uniformMem, floats, var.count * 16) != 0) {
|
||||
glUniform4fv(uniform, var.count, floats);
|
||||
memcpy(uniformMem, floats, var.count * 16);
|
||||
}
|
||||
floats += var.count * 4;
|
||||
}
|
||||
break;
|
||||
case VT_mat3:
|
||||
if(var.constant) {
|
||||
if(var._floatcall)
|
||||
var._floatcall(var._floats, var.count, var._args);
|
||||
|
||||
if(memcmp(uniformMem, var._floats, var.count * 36) != 0) {
|
||||
glUniformMatrix3fv(uniform, var.count, false, var._floats);
|
||||
memcpy(uniformMem, var._floats, var.count * 36);
|
||||
}
|
||||
}
|
||||
else if(var._intcall) {
|
||||
if(memcmp(uniformMem, floats, var.count * 36) != 0) {
|
||||
glUniformMatrix3fv(uniform, var.count, false, floats);
|
||||
memcpy(uniformMem, floats, var.count * 36);
|
||||
}
|
||||
floats += var.count * 9;
|
||||
}
|
||||
NO_DEFAULT
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for(size_t i = 0, cnt = uniform_locations.size(); i < cnt; ++i) {
|
||||
const Shader::Variable& var = vars[uniform_vars[i]];
|
||||
if(!bindConst && var.constant)
|
||||
continue;
|
||||
|
||||
GLuint uniform = uniform_locations[i];
|
||||
void* uniformMem = (void*)&glProgram->mem_buffer[uniform_cache[i]];
|
||||
|
||||
switch(var.type) {
|
||||
case VT_invalid:
|
||||
break;
|
||||
|
||||
case VT_int:
|
||||
if(var._intcall)
|
||||
var._intcall(var._ints,var.count,var._args);
|
||||
if(memcmp(uniformMem, var._ints, var.count * 4) != 0) {
|
||||
glUniform1iv(uniform, var.count, var._ints);
|
||||
memcpy(uniformMem, var._ints, var.count * 4);
|
||||
}
|
||||
break;
|
||||
case VT_int2:
|
||||
if(var._intcall)
|
||||
var._intcall(var._ints,var.count,var._args);
|
||||
if(memcmp(uniformMem, var._ints, var.count * 8) != 0) {
|
||||
glUniform2iv(uniform, var.count, var._ints);
|
||||
memcpy(uniformMem, var._ints, var.count * 8);
|
||||
}
|
||||
break;
|
||||
case VT_int3:
|
||||
if(var._intcall)
|
||||
var._intcall(var._ints,var.count,var._args);
|
||||
if(memcmp(uniformMem, var._ints, var.count * 12) != 0) {
|
||||
glUniform3iv(uniform, var.count, var._ints);
|
||||
memcpy(uniformMem, var._ints, var.count * 12);
|
||||
}
|
||||
break;
|
||||
case VT_int4:
|
||||
if(var._intcall)
|
||||
var._intcall(var._ints,var.count,var._args);
|
||||
if(memcmp(uniformMem, var._ints, var.count * 16) != 0) {
|
||||
glUniform4iv(uniform, var.count, var._ints);
|
||||
memcpy(uniformMem, var._ints, var.count * 16);
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_float:
|
||||
if(var._floatcall)
|
||||
var._floatcall(var._floats,var.count,var._args);
|
||||
if(memcmp(uniformMem, var._floats, var.count * 4) != 0) {
|
||||
glUniform1fv(uniform, var.count, var._floats);
|
||||
memcpy(uniformMem, var._floats, var.count * 4);
|
||||
}
|
||||
break;
|
||||
case VT_float2:
|
||||
if(var._floatcall)
|
||||
var._floatcall(var._floats,var.count,var._args);
|
||||
if(memcmp(uniformMem, var._floats, var.count * 8) != 0) {
|
||||
glUniform2fv(uniform, var.count, var._floats);
|
||||
memcpy(uniformMem, var._floats, var.count * 8);
|
||||
}
|
||||
break;
|
||||
case VT_float3:
|
||||
if(var._floatcall)
|
||||
var._floatcall(var._floats,var.count,var._args);
|
||||
if(memcmp(uniformMem, var._floats, var.count * 12) != 0) {
|
||||
glUniform3fv(uniform, var.count, var._floats);
|
||||
memcpy(uniformMem, var._floats, var.count * 12);
|
||||
}
|
||||
break;
|
||||
case VT_float4:
|
||||
if(var._floatcall)
|
||||
var._floatcall(var._floats,var.count,var._args);
|
||||
if(memcmp(uniformMem, var._floats, var.count * 16) != 0) {
|
||||
glUniform4fv(uniform, var.count, var._floats);
|
||||
memcpy(uniformMem, var._floats, var.count * 16);
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_mat3:
|
||||
if(var._floatcall)
|
||||
var._floatcall(var._floats,var.count,var._args);
|
||||
if(memcmp(uniformMem, var._floats, var.count * 36) != 0) {
|
||||
glUniformMatrix3fv(uniform, var.count, false, var._floats);
|
||||
memcpy(uniformMem, var._floats, var.count * 36);
|
||||
}
|
||||
break;
|
||||
NO_DEFAULT
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void updateDynamicVars() const {
|
||||
for(size_t i = 0, cnt = uniform_locations.size(); i < cnt; ++i) {
|
||||
const Shader::Variable& var = vars[uniform_vars[i]];
|
||||
if(var.constant)
|
||||
continue;
|
||||
GLuint uniform = uniform_locations[i];
|
||||
void* uniformMem = (void*)&((GLShaderProgram*)program)->mem_buffer[uniform_cache[i]];
|
||||
|
||||
switch(var.type) {
|
||||
case VT_invalid:
|
||||
break;
|
||||
|
||||
case VT_int:
|
||||
if(var._intcall)
|
||||
var._intcall(var._ints,var.count,var._args);
|
||||
if(memcmp(uniformMem, var._ints, var.count * 4) != 0) {
|
||||
glUniform1iv(uniform, var.count, var._ints);
|
||||
memcpy(uniformMem, var._ints, var.count * 4);
|
||||
}
|
||||
break;
|
||||
case VT_int2:
|
||||
if(var._intcall)
|
||||
var._intcall(var._ints,var.count,var._args);
|
||||
if(memcmp(uniformMem, var._ints, var.count * 8) != 0) {
|
||||
glUniform2iv(uniform, var.count, var._ints);
|
||||
memcpy(uniformMem, var._ints, var.count * 8);
|
||||
}
|
||||
break;
|
||||
case VT_int3:
|
||||
if(var._intcall)
|
||||
var._intcall(var._ints,var.count,var._args);
|
||||
if(memcmp(uniformMem, var._ints, var.count * 12) != 0) {
|
||||
glUniform3iv(uniform, var.count, var._ints);
|
||||
memcpy(uniformMem, var._ints, var.count * 12);
|
||||
}
|
||||
break;
|
||||
case VT_int4:
|
||||
if(var._intcall)
|
||||
var._intcall(var._ints,var.count,var._args);
|
||||
if(memcmp(uniformMem, var._ints, var.count * 16) != 0) {
|
||||
glUniform4iv(uniform, var.count, var._ints);
|
||||
memcpy(uniformMem, var._ints, var.count * 16);
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_float:
|
||||
if(var._floatcall)
|
||||
var._floatcall(var._floats,var.count,var._args);
|
||||
if(memcmp(uniformMem, var._floats, var.count * 4) != 0) {
|
||||
glUniform1fv(uniform, var.count, var._floats);
|
||||
memcpy(uniformMem, var._floats, var.count * 4);
|
||||
}
|
||||
break;
|
||||
case VT_float2:
|
||||
if(var._floatcall)
|
||||
var._floatcall(var._floats,var.count,var._args);
|
||||
if(memcmp(uniformMem, var._floats, var.count * 8) != 0) {
|
||||
glUniform2fv(uniform, var.count, var._floats);
|
||||
memcpy(uniformMem, var._floats, var.count * 8);
|
||||
}
|
||||
break;
|
||||
case VT_float3:
|
||||
if(var._floatcall)
|
||||
var._floatcall(var._floats,var.count,var._args);
|
||||
if(memcmp(uniformMem, var._floats, var.count * 12) != 0) {
|
||||
glUniform3fv(uniform, var.count, var._floats);
|
||||
memcpy(uniformMem, var._floats, var.count * 12);
|
||||
}
|
||||
break;
|
||||
case VT_float4:
|
||||
if(var._floatcall)
|
||||
var._floatcall(var._floats,var.count,var._args);
|
||||
if(memcmp(uniformMem, var._floats, var.count * 16) != 0) {
|
||||
glUniform4fv(uniform, var.count, var._floats);
|
||||
memcpy(uniformMem, var._floats, var.count * 16);
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_mat3:
|
||||
if(var._floatcall)
|
||||
var._floatcall(var._floats,var.count,var._args);
|
||||
if(memcmp(uniformMem, var._floats, var.count * 36) != 0) {
|
||||
glUniformMatrix3fv(uniform, var.count, false, var._floats);
|
||||
memcpy(uniformMem, var._floats, var.count * 36);
|
||||
}
|
||||
break;
|
||||
NO_DEFAULT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void saveDynamicVars(float* buffer) const {
|
||||
float* floats = buffer;
|
||||
|
||||
for(size_t i = 0, cnt = uniform_locations.size(); i < cnt; ++i) {
|
||||
const Shader::Variable& var = vars[uniform_vars[i]];
|
||||
if(var.constant)
|
||||
continue;
|
||||
|
||||
switch(var.type) {
|
||||
case VT_invalid:
|
||||
break;
|
||||
|
||||
case VT_int:
|
||||
if(var._intcall) {
|
||||
var._intcall((int*)floats,var.count,var._args);
|
||||
floats += var.count;
|
||||
}
|
||||
break;
|
||||
case VT_int2:
|
||||
if(var._intcall) {
|
||||
var._intcall((int*)floats,var.count,var._args);
|
||||
floats += var.count * 2;
|
||||
}
|
||||
break;
|
||||
case VT_int3:
|
||||
if(var._intcall) {
|
||||
var._intcall((int*)floats,var.count,var._args);
|
||||
floats += var.count * 3;
|
||||
}
|
||||
break;
|
||||
case VT_int4:
|
||||
if(var._intcall) {
|
||||
var._intcall((int*)floats,var.count,var._args);
|
||||
floats += var.count * 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_float:
|
||||
if(var._floatcall) {
|
||||
var._floatcall(floats,var.count,var._args);
|
||||
floats += var.count;
|
||||
}
|
||||
break;
|
||||
case VT_float2:
|
||||
if(var._floatcall) {
|
||||
var._floatcall(floats,var.count,var._args);
|
||||
floats += var.count * 2;
|
||||
}
|
||||
break;
|
||||
case VT_float3:
|
||||
if(var._floatcall) {
|
||||
var._floatcall(floats,var.count,var._args);
|
||||
floats += var.count * 3;
|
||||
}
|
||||
break;
|
||||
case VT_float4:
|
||||
if(var._floatcall) {
|
||||
var._floatcall(floats,var.count,var._args);
|
||||
floats += var.count * 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_mat3:
|
||||
if(var._floatcall) {
|
||||
var._floatcall(floats,var.constant,var._args);
|
||||
floats += var.constant * 9;
|
||||
}
|
||||
NO_DEFAULT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loadDynamicVars(float* buffer) const {
|
||||
float* floats = buffer;
|
||||
|
||||
for(size_t i = 0, cnt = uniform_locations.size(); i < cnt; ++i) {
|
||||
const Shader::Variable& var = vars[uniform_vars[i]];
|
||||
if(var.constant)
|
||||
continue;
|
||||
|
||||
GLuint uniform = uniform_locations[i];
|
||||
void* uniformMem = (void*)&((GLShaderProgram*)program)->mem_buffer[uniform_cache[i]];
|
||||
|
||||
switch(var.type) {
|
||||
case VT_invalid:
|
||||
break;
|
||||
|
||||
case VT_int:
|
||||
if(var._intcall) {
|
||||
if(memcmp(uniformMem, floats, var.count * 4) != 0) {
|
||||
glUniform1iv(uniform, var.count, (int*)floats);
|
||||
memcpy(uniformMem, floats, var.count * 4);
|
||||
}
|
||||
floats += var.count;
|
||||
}
|
||||
break;
|
||||
case VT_int2:
|
||||
if(var._intcall) {
|
||||
if(memcmp(uniformMem, floats, var.count * 8) != 0) {
|
||||
glUniform2iv(uniform, var.count, (int*)floats);
|
||||
memcpy(uniformMem, floats, var.count * 8);
|
||||
}
|
||||
floats += var.count * 2;
|
||||
}
|
||||
break;
|
||||
case VT_int3:
|
||||
if(var._intcall) {
|
||||
if(memcmp(uniformMem, floats, var.count * 12) != 0) {
|
||||
glUniform3iv(uniform, var.count, (int*)floats);
|
||||
memcpy(uniformMem, floats, var.count * 12);
|
||||
}
|
||||
floats += var.count * 3;
|
||||
}
|
||||
break;
|
||||
case VT_int4:
|
||||
if(var._intcall) {
|
||||
if(memcmp(uniformMem, floats, var.count * 16) != 0) {
|
||||
glUniform4iv(uniform, var.count, (int*)floats);
|
||||
memcpy(uniformMem, floats, var.count * 16);
|
||||
}
|
||||
floats += var.count * 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_float:
|
||||
if(var._floatcall) {
|
||||
if(memcmp(uniformMem, floats, var.count * 4) != 0) {
|
||||
glUniform1fv(uniform, var.count, floats);
|
||||
memcpy(uniformMem, floats, var.count * 4);
|
||||
}
|
||||
floats += var.count;
|
||||
}
|
||||
break;
|
||||
case VT_float2:
|
||||
if(var._floatcall) {
|
||||
if(memcmp(uniformMem, floats, var.count * 8) != 0) {
|
||||
glUniform2fv(uniform, var.count, floats);
|
||||
memcpy(uniformMem, floats, var.count * 8);
|
||||
}
|
||||
floats += var.count * 2;
|
||||
}
|
||||
break;
|
||||
case VT_float3:
|
||||
if(var._floatcall) {
|
||||
if(memcmp(uniformMem, floats, var.count * 12) != 0) {
|
||||
glUniform3fv(uniform, var.count, floats);
|
||||
memcpy(uniformMem, floats, var.count * 12);
|
||||
}
|
||||
floats += var.count * 3;
|
||||
}
|
||||
break;
|
||||
case VT_float4:
|
||||
if(var._floatcall) {
|
||||
if(memcmp(uniformMem, floats, var.count * 16) != 0) {
|
||||
glUniform4fv(uniform, var.count, floats);
|
||||
memcpy(uniformMem, floats, var.count * 16);
|
||||
}
|
||||
floats += var.count * 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_mat3:
|
||||
if(var._floatcall) {
|
||||
if(memcmp(uniformMem, floats, var.count * 36) != 0) {
|
||||
glUniformMatrix3fv(uniform, var.count, false, floats);
|
||||
memcpy(uniformMem, floats, var.count * 36);
|
||||
}
|
||||
floats += var.count * 9;
|
||||
}
|
||||
break;
|
||||
NO_DEFAULT
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Shader* createGLShader() {
|
||||
return new GLShader();
|
||||
}
|
||||
|
||||
ShaderProgram* createGLShaderProgram(const char* vertex_shader, const char* fragment_shader) {
|
||||
return new GLShaderProgram(vertex_shader, fragment_shader);
|
||||
}
|
||||
|
||||
};
|
||||
Reference in New Issue
Block a user