diff options
author | chai <chaifix@163.com> | 2019-01-12 21:48:33 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2019-01-12 21:48:33 +0800 |
commit | 8b00d67febf133e89f6a0bfabc41feed555dc4a9 (patch) | |
tree | fe48ef17c250afa40c2588300fcdb5920dba6951 /src/libjin/graphics/shaders/shader.cpp | |
parent | a907c39756ef6b368d06643afa491c49a9044a8e (diff) |
*去掉文件前缀je_
Diffstat (limited to 'src/libjin/graphics/shaders/shader.cpp')
-rw-r--r-- | src/libjin/graphics/shaders/shader.cpp | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/src/libjin/graphics/shaders/shader.cpp b/src/libjin/graphics/shaders/shader.cpp new file mode 100644 index 0000000..c7f6f11 --- /dev/null +++ b/src/libjin/graphics/shaders/shader.cpp @@ -0,0 +1,321 @@ +#include "../../core/configuration.h" +#if defined(jin_graphics) && (jin_graphics & jin_graphics_shader) + +#include <iostream> + +#include "../../time/timer.h" +#include "../../filesystem/buffer.h" +#include "../../utils/log.h" +#include "../../utils/macros.h" + +#include "../gl.h" +#include "../window.h" + +#include "jsl_compiler.h" +#include "shader.h" + +using namespace std; +using namespace JinEngine::Filesystem; +using namespace JinEngine::Time; + +namespace JinEngine +{ + namespace Graphics + { + namespace Shaders + { + + // + // default_texture + // base_shader + // SHADER_FORMAT_SIZE + // formatShader + // + #include "built-in/default.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 MAIN_TEXTURE_UNIT = 0; + + static GLint textureUnit = 0; + + GLint Shader::mAttributeIndex = 0; + + Shader::Shader(const string& program) + { + if (!compile(program)) + { + jin_log_error("Compile jsl shader failed."); + throw Exception("Compile jsl shader failed"); + } + } + + Shader::~Shader() + { + if (gl.getShader() == this) + gl.unuseShader(); + // Delete shader program. + glDeleteShader(mPID); + } + + Shader& Shader::begin() + { + + textureUnit = MAIN_TEXTURE_UNIT; + + // Send uniforms. + sendInt(SHADER_MAIN_TEXTURE, MAIN_TEXTURE_UNIT); + sendVec2(SHADER_TIME, Time::getSecond(), Time::getDeltaTime()); + Canvas* rt = gl.getCanvas(); + if (rt == OpenGL::SCREEN) + { + sendVec2(SHADER_RENDERTARGET_SIZE, Window::get()->getW(), Window::get()->getH()); + } + else if(rt != nullptr) + { + sendVec2(SHADER_RENDERTARGET_SIZE, rt->getWidth(), rt->getHeight()); + } + + gl.activeTextureUnit(MAIN_TEXTURE_UNIT); + + return *this; + } + + void Shader::end() + { + // Reset attribute index. + for (; mAttributeIndex > 0; --mAttributeIndex) + glDisableVertexAttribArray(mAttributeIndex); + } + + bool Shader::compile(const string& program) + { + string vertex_shader, fragment_shader; + // Compile JSL shader source into GLSL shader source. + JSLCompiler* compiler = JSLCompiler::get(); + if (!compiler->compile(program, &vertex_shader, &fragment_shader)) + { + return false; + } + + #define glsl(SHADER_MODE, SHADER, SRC) \ + do{ \ + const GLchar* src = SRC.c_str(); \ + glShaderSource(SHADER, 1, &src, NULL); \ + glCompileShader(SHADER); \ + GLint success; \ + glGetShaderiv(SHADER, GL_COMPILE_STATUS, &success); \ + if (success == GL_FALSE) \ + return false; \ + }while(0) + + // Compile vertex shader. + GLuint vid = glCreateShader(GL_VERTEX_SHADER); + glsl(GL_VERTEX_SHADER, vid, vertex_shader); + // Compile fragment shader. + GLuint fid = glCreateShader(GL_FRAGMENT_SHADER); + glsl(GL_FRAGMENT_SHADER, fid, fragment_shader); + + #undef glsl + // Create OpenGL shader program. + mPID = glCreateProgram(); + glAttachShader(mPID, vid); + glAttachShader(mPID, fid); + glLinkProgram(mPID); + GLint success; + glGetProgramiv(mPID, GL_LINK_STATUS, &success); + if (success == GL_FALSE) + return false; + } + + static inline GLint getMaxTextureUnits() + { + GLint maxTextureUnits = 0; + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits); + return maxTextureUnits; + } + + GLint Shader::claimTextureUnit(/*const std::string& name*/) + { + return textureUnit++; + } + + GLint Shader::getUniformLocation(const char* uniform) + { + map<std::string, GLint>::iterator it = mUniformsLocation.find(uniform); + if (it != mUniformsLocation.end()) + return it->second; + GLint loc = glGetUniformLocation(mPID, uniform); + mUniformsLocation.insert(pair<std::string, GLint>(uniform, loc)); + return loc; + } + + #define check_jsl() \ + if (gl.getShader() != this) \ + return *this + + Shader & Shader::sendInt(const char* name, int value) + { + check_jsl(); + int loc = getUniformLocation(name); + glUniform1i(loc, value); + return *this; + } + + Shader& Shader::sendFloat(const char* variable, float number) + { + check_jsl(); + int loc = getUniformLocation(variable); + glUniform1f(loc, number); + return *this; + } + + // + // https://www.douban.com/note/627332677/ + // struct TextureUnit + // { + // GLuint targetTexture1D; + // GLuint targetTexture2D; + // GLuint targetTexture3D; + // GLuint targetTextureCube; + // ... + // }; + // + // TextureUnit mTextureUnits[GL_MAX_TEXTURE_IMAGE_UNITS] + // GLuint mCurrentTextureUnit = 0; + // + Shader& Shader::sendTexture(const char* variable, const Texture* tex) + { + check_jsl(); + GLint location = getUniformLocation(variable); + if (location == -1) + return *this; + GLint unit = claimTextureUnit(/*variable*/); + if (unit == 0) + { + // TODO: 쳣 + return *this; + } + gl.activeTextureUnit(unit); + glUniform1i(location, unit); + gl.bindTexture2D(tex->getGLTexture()); + gl.activeTextureUnit(MAIN_TEXTURE_UNIT); + return *this; + } + + Shader& Shader::sendCanvas(const char* variable, const Canvas* canvas) + { + check_jsl(); + GLint location = getUniformLocation(variable); + if (location == -1) + return *this; + GLint unit = claimTextureUnit(/*variable*/); + if (unit == 0) + { + // TODO: 쳣 + return *this; + } + glUniform1i(location, unit); + glActiveTexture(GL_TEXTURE0 + unit); + gl.bindTexture2D(canvas->getGLTexture()); + + glActiveTexture(GL_TEXTURE0); + return *this; + } + + Shader& Shader::sendVec2(const char* name, float x, float y) + { + check_jsl(); + int loc = getUniformLocation(name); + glUniform2f(loc, x, y); + return *this; + } + + Shader& Shader::sendVec3(const char* name, float x, float y, float z) + { + check_jsl(); + int loc = getUniformLocation(name); + glUniform3f(loc, x, y, z); + return *this; + } + + Shader& Shader::sendVec4(const char* name, float x, float y, float z, float w) + { + check_jsl(); + int loc = getUniformLocation(name); + glUniform4f(loc, x, y, z, w); + return *this; + } + + Shader& Shader::sendColor(const char* name, const Color* col) + { + check_jsl(); + int loc = getUniformLocation(name); + glUniform4f(loc, + col->r / 255.f, + col->g / 255.f, + col->b / 255.f, + col->a / 255.f + ); + return *this; + } + + Shader& Shader::sendMatrix4(const char* name, const Math::Matrix* mat4) + { + int loc = getUniformLocation(name); + glUniformMatrix4fv(loc, 1, GL_FALSE, mat4->getElements()); + return *this; + } + + Shader& Shader::uploadVertices(int n, GLenum type, GLsizei stride, const GLvoid * pointers, GLboolean normalized) + { + uploadAttribute(SHADER_VERTEX_COORDS, n, type, stride, pointers, normalized); + return *this; + } + + Shader& Shader::uploadUV(int n, GLenum type, GLsizei stride, const GLvoid * pointers, GLboolean normalized) + { + uploadAttribute(SHADER_TEXTURE_COORDS, n, type, stride, pointers, normalized); + return *this; + } + + Shader& Shader::uploadColor(int n, GLenum type, GLsizei stride, const GLvoid * pointers, GLboolean normalized) + { + uploadAttribute(SHADER_VERTEX_COLOR, n, type, stride, pointers, normalized); + return *this; + } + + Shader& Shader::uploadAttribute(const String& name, int n, GLenum type, GLsizei stride, const GLvoid * pointers, GLboolean normalized) + { + GLint loc = glGetAttribLocation(mPID, name); + glEnableVertexAttribArray(mAttributeIndex++); + glVertexAttribPointer(loc, n, type, normalized, stride, pointers); + return *this; + } + + } // namespace Shaders + } // namespace Graphics +} // namespace JinEngine + +#endif // (jin_graphics) && (jin_graphics & jin_graphics_shader)
\ No newline at end of file |