diff options
author | chai <chaifix@163.com> | 2018-09-06 09:43:47 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2018-09-06 09:43:47 +0800 |
commit | 05ebedc397432f054cdc367d35f86fd610fbfee6 (patch) | |
tree | d58bf6a52b7d201f19b0d1de6422e2071914c8d6 /src | |
parent | ea88790b539f80e1d41bba268136d78357aa87d1 (diff) |
*update
Diffstat (limited to 'src')
-rw-r--r-- | src/libjin/Graphics/Shader.cpp | 199 | ||||
-rw-r--r-- | src/libjin/Graphics/Shader.h | 54 | ||||
-rw-r--r-- | src/libjin/Graphics/base.shader.h | 26 |
3 files changed, 279 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 diff --git a/src/libjin/Graphics/Shader.h b/src/libjin/Graphics/Shader.h new file mode 100644 index 0000000..24c889d --- /dev/null +++ b/src/libjin/Graphics/Shader.h @@ -0,0 +1,54 @@ +#ifndef __JIN_JSL_H +#define __JIN_JSL_H +#include "../modules.h" +#if JIN_MODULES_RENDER + +#include <string> +#include <map> +#include "color.h" +#include "texture.h" +#include "canvas.h" +#include "../3rdparty/GLee/GLee.h" + +namespace jin +{ +namespace graphics +{ + + /* Jin Shader Language Program*/ + class JSLProgram + { + public: + static JSLProgram* createJSLProgram(const char* program); + static inline JSLProgram* getCurrentJSL() { return currentJSLProgram; } + static void unuse(); + + virtual ~JSLProgram(); + + void use(); + void sendFloat(const char* name, float number); + void sendTexture(const char* name, const Texture* image); + void sendVec2(const char* name, float x, float y); + void sendVec3(const char* name, float x, float y, float z); + void sendVec4(const char* name, float x, float y, float z, float w); + void sendCanvas(const char* name, const Canvas* canvas); + void sendColor(const char* name, const color* col); + + protected: + GLint claimTextureUnit(const std::string& name); + JSLProgram(const char* program); + void bindDefaultTex(); + + static JSLProgram* currentJSLProgram; + + GLuint pid; + GLint currentTextureUnit; + std::map<std::string, GLint> textureUnits; + + }; + +} // graphics +} // jin + +#endif // JIN_MODULES_RENDER +#endif // __JIN_JSL_H
\ No newline at end of file diff --git a/src/libjin/Graphics/base.shader.h b/src/libjin/Graphics/base.shader.h new file mode 100644 index 0000000..6efb710 --- /dev/null +++ b/src/libjin/Graphics/base.shader.h @@ -0,0 +1,26 @@ + +const static char* default_tex = "_tex0_"; + +const static char* base_shader = R"( +#define number float +#define Texture sampler2D +#define Canvas sampler2D +#define Color vec4 +#define Texel texture2D +#define extern uniform + +extern Texture %s; +%s +void main() +{ + gl_FragColor = effect(gl_Color, %s, gl_TexCoord[0].xy, gl_FragCoord.xy); +} +)"; +#define formatShader(buf, program)\ + sprintf(buf, base_shader, default_tex, program, default_tex) +/* + * https://stackoverflow.com/questions/10868958/what-does-sampler2d-store + * The sampler2D is bound to a texture unit. The glUniform call binds it to texture + * unit zero. The glActiveTexture call is only needed if you are going to use multiple + * texture units (because GL_TEXTURE0 is the default anyway). +*/
\ No newline at end of file |