diff options
Diffstat (limited to 'src/libjin/Graphics/Shader.cpp')
-rw-r--r-- | src/libjin/Graphics/Shader.cpp | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/src/libjin/Graphics/Shader.cpp b/src/libjin/Graphics/Shader.cpp new file mode 100644 index 0000000..a40f78d --- /dev/null +++ b/src/libjin/Graphics/Shader.cpp @@ -0,0 +1,199 @@ +#include "../modules.h" +#if JIN_MODULES_RENDER + +#include "../utils/macros.h" +#include "Shader.h" +namespace jin +{ +namespace graphics +{ + + #include "base.shader.h" + + /* + * https://stackoverflow.com/questions/27941496/use-sampler-without-passing-through-value + * The default value of a sampler variable is 0. From the GLSL 3.30 spec, + * section "4.3.5 Uniforms": + * + * The link time initial value is either the value of the variable's + * initializer, if present, or 0 if no initializer is present.Sampler + * types cannot have initializers. + * + * Since a value of 0 means that it's sampling from texture unit 0, it will + * work without ever setting the value as long as you bind your textures to + * unit 0. This is well defined behavior. + * + * Since texture unit 0 is also the default until you call glActiveTexture() + * with a value other than GL_TEXTURE0, it's very common to always use unit + * 0 as long as shaders do not need more than one texture.Which means that + * often times, setting the sampler uniforms is redundant for simple + * applications. + * + * I would still prefer to always set the values.If nothing else, it makes + * it clear to anybody reading your code that you really mean to sample from + * texture unit 0, and did not just forget to set the value. + */ + const int DEFAULT_TEX_UNIT = 0; + + /*static*/ JSLProgram* JSLProgram::currentJSLProgram = nullptr; + + JSLProgram* JSLProgram::createJSLProgram(const char* program) + { + return new JSLProgram(program); + } + + JSLProgram::JSLProgram(const char* program) + : currentTextureUnit(DEFAULT_TEX_UNIT) + { + char* fs = (char*)alloca(strlen(program) + strlen(base_shader)); + formatShader(fs, program); + GLuint shader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(shader, 1, (const GLchar**)&fs, NULL); + glCompileShader(shader); + pid = glCreateProgram(); + glAttachShader(pid, shader); + glLinkProgram(pid); + } + + JSLProgram::~JSLProgram() + { + if (currentJSLProgram == this) + unuse(); + } + + static inline GLint getMaxTextureUnits() + { + GLint maxTextureUnits = 0; + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits); + return maxTextureUnits; + } + + void JSLProgram::use() + { + glUseProgram(pid); + currentJSLProgram = this; + bindDefaultTex(); + } + + /*static*/ void JSLProgram::unuse() + { + glUseProgram(0); + currentJSLProgram = nullptr; + } + + void JSLProgram::bindDefaultTex() + { + int loc = glGetUniformLocation(pid, default_tex); + glUniform1i(loc, DEFAULT_TEX_UNIT); + } + + GLint JSLProgram::claimTextureUnit(const std::string& name) + { + std::map<std::string, GLint>::iterator unit = textureUnits.find(name); + if (unit != textureUnits.end()) + return unit->second; + static GLint MAX_TEXTURE_UNITS = getMaxTextureUnits(); + if (++currentTextureUnit >= MAX_TEXTURE_UNITS) + return 0; + textureUnits[name] = currentTextureUnit; + return currentTextureUnit; + } + +#define checkJSL() \ + if (currentJSLProgram != this) \ + return + + void JSLProgram::sendFloat(const char* variable, float number) + { + checkJSL(); + int loc = glGetUniformLocation(pid, variable); + glUniform1f(loc, number); + } + + /** + * https://www.douban.com/note/627332677/ + * struct TextureUnit + * { + * GLuint targetTexture1D; + * GLuint targetTexture2D; + * GLuint targetTexture3D; + * GLuint targetTextureCube; + * ... + * }; + * + * TextureUnit textureUnits[GL_MAX_TEXTURE_IMAGE_UNITS] + * GLuint currentTextureUnit = 0; + */ + void JSLProgram::sendTexture(const char* variable, const Texture* tex) + { + checkJSL(); + GLint location = glGetUniformLocation(pid, variable); + if (location == -1) + return; + GLint unit = claimTextureUnit(variable); + if (unit == 0) + { + // TODO: 쳣 + return; + } + glUniform1i(location, unit); + glActiveTexture(GL_TEXTURE0 + unit); + glBindTexture(GL_TEXTURE_2D, tex->getTexture()); + glActiveTexture(GL_TEXTURE0); + } + + void JSLProgram::sendCanvas(const char* variable, const Canvas* canvas) + { + checkJSL(); + GLint location = glGetUniformLocation(pid, variable); + if (location == -1) + return; + GLint unit = claimTextureUnit(variable); + if (unit == 0) + { + // TODO: 쳣 + return; + } + glUniform1i(location, unit); + glActiveTexture(GL_TEXTURE0 + unit); + glBindTexture(GL_TEXTURE_2D, canvas->getTexture()); + glActiveTexture(GL_TEXTURE0); + } + + void JSLProgram::sendVec2(const char* name, float x, float y) + { + checkJSL(); + int loc = glGetUniformLocation(pid, name); + glUniform2f(loc, x, y); + } + + void JSLProgram::sendVec3(const char* name, float x, float y, float z) + { + checkJSL(); + int loc = glGetUniformLocation(pid, name); + glUniform3f(loc, x, y, z); + } + + void JSLProgram::sendVec4(const char* name, float x, float y, float z, float w) + { + checkJSL(); + int loc = glGetUniformLocation(pid, name); + glUniform4f(loc, x, y, z, w); + } + + void JSLProgram::sendColor(const char* name, const color* col) + { + checkJSL(); + int loc = glGetUniformLocation(pid, name); + glUniform4f(loc, + col->rgba.r / 255.f, + col->rgba.g / 255.f, + col->rgba.b / 255.f, + col->rgba.a / 255.f + ); + } + +} // graphics +} // jin + +#endif // JIN_MODULES_RENDER
\ No newline at end of file |