diff options
Diffstat (limited to 'src/libjin/graphics/shaders')
-rw-r--r-- | src/libjin/graphics/shaders/built-in/je_default.shader.h | 21 | ||||
-rw-r--r-- | src/libjin/graphics/shaders/built-in/je_font.shader.h | 21 | ||||
-rw-r--r-- | src/libjin/graphics/shaders/built-in/je_texture.shader.h | 21 | ||||
-rw-r--r-- | src/libjin/graphics/shaders/je_base.shader.h | 89 | ||||
-rw-r--r-- | src/libjin/graphics/shaders/je_jsl_compiler.cpp | 57 | ||||
-rw-r--r-- | src/libjin/graphics/shaders/je_jsl_compiler.h | 45 | ||||
-rw-r--r-- | src/libjin/graphics/shaders/je_shader.cpp | 281 | ||||
-rw-r--r-- | src/libjin/graphics/shaders/je_shader.h | 201 |
8 files changed, 736 insertions, 0 deletions
diff --git a/src/libjin/graphics/shaders/built-in/je_default.shader.h b/src/libjin/graphics/shaders/built-in/je_default.shader.h new file mode 100644 index 0000000..3f57c44 --- /dev/null +++ b/src/libjin/graphics/shaders/built-in/je_default.shader.h @@ -0,0 +1,21 @@ +// Ĭshader +static const char* default_shader = R"( + +#VERTEX_SHADER + +Vertex vert(Vertex v) +{ + return v; +} + +#END_VERTEX_SHADER + +#FRAGMENT_SHADER + +Color frag(Color col, Texture tex, Vertex v) +{ + return col * texel(tex, v.uv); +} + +#END_FRAGMENT_SHADER +)";
\ No newline at end of file diff --git a/src/libjin/graphics/shaders/built-in/je_font.shader.h b/src/libjin/graphics/shaders/built-in/je_font.shader.h new file mode 100644 index 0000000..e04c225 --- /dev/null +++ b/src/libjin/graphics/shaders/built-in/je_font.shader.h @@ -0,0 +1,21 @@ +// shader +static const char* font_shader = R"( + +#VERTEX_SHADER + +Vertex vert(Vertex v) +{ + return v; +} + +#END_VERTEX_SHADER + +#FRAGMENT_SHADER + +Color frag(Color col, Texture tex, Vertex v) +{ + return Color(col.rgb, texel(tex, v.uv).a); +} + +#END_FRAGMENT_SHADER +)";
\ No newline at end of file diff --git a/src/libjin/graphics/shaders/built-in/je_texture.shader.h b/src/libjin/graphics/shaders/built-in/je_texture.shader.h new file mode 100644 index 0000000..d1fc86f --- /dev/null +++ b/src/libjin/graphics/shaders/built-in/je_texture.shader.h @@ -0,0 +1,21 @@ +// ͼshader +static const char* texture_shader = R"( + +#VERTEX_SHADER + +Vertex vert(Vertex v) +{ + return v; +} + +#END_VERTEX_SHADER + +#FRAGMENT_SHADER + +Color frag(Color col, Texture tex, Vertex v) +{ + return col * texel(tex, v.uv); +} + +#END_FRAGMENT_SHADER +)";
\ No newline at end of file diff --git a/src/libjin/graphics/shaders/je_base.shader.h b/src/libjin/graphics/shaders/je_base.shader.h new file mode 100644 index 0000000..34996bc --- /dev/null +++ b/src/libjin/graphics/shaders/je_base.shader.h @@ -0,0 +1,89 @@ +#ifndef __JE_BASE_SHADER_H__ +#define __JE_BASE_SHADER_H__ + +static const char* base_shared = R"( +#define Number float +#define Texture sampler2D +#define Canvas sampler2D +#define Color vec4 +#define Vec2 vec2 +#define Vec3 vec3 +#define Vec4 vec4 + +#define texel texture2D + +struct Vertex +{ + vec2 xy; + vec2 uv; +}; + +)"; + +static const int BASE_SHARED_SIZE = strlen(base_shared); + +static const char* base_vertex = R"( +#version 130 core + +%s +// Projection matrix +uniform mat4 jin_ProjectionMatrix; +// Model view matrix +uniform mat4 jin_ModelViewMatrix; + +in vec2 jin_VertexCoords; +in vec2 jin_TextureCoords; + +out vec4 jin_Color; +out vec2 jin_XY; +out vec2 jin_UV; + +%s + +void main() +{ + vec4 v = jin_ModelViewMatrix * vec4(jin_VertexCoords, 0, 1.0); + Vertex _v = vert(Vertex(v.xy, jin_TextureCoords)); + gl_Position = jin_ProjectionMatrix * vec4(_v.xy, 0, 1.0f); + jin_Color = gl_Color; + jin_XY = _v.xy; + jin_UV = _v.uv; +} +)"; + +static const int BASE_VERTEX_SHADER_SIZE = strlen(base_vertex) + BASE_SHARED_SIZE; + +#define formatVertexShader(buf, program) sprintf(buf,base_vertex, base_shared, program) + +static const char* base_fragment = R"( +#version 130 core + +%s + +uniform Texture jin_MainTexture; + +in vec4 jin_Color; +in vec2 jin_XY; +in vec2 jin_UV; + +out vec4 jin_OutColor; + +%s + +void main() +{ + jin_OutColor = frag(jin_Color, jin_MainTexture, Vertex(jin_XY, jin_UV)); +} +)"; + +static const int BASE_FRAGMENT_SHADER_SIZE = strlen(base_fragment) + BASE_SHARED_SIZE; + +#define formatFragmentShader(buf, program) sprintf(buf, base_fragment, base_shared, program) + +static const char* SHADER_PROJECTION_MATRIX = "jin_ProjectionMatrix"; +static const char* SHADER_MODELVIEW_MATRIX = "jin_ModelViewMatrix"; +static const char* SHADER_MAIN_TEXTURE = "jin_MainTexture"; +static const char* SHADER_VERTEX_COORDS = "jin_VertexCoords"; +static const char* SHADER_TEXTURE_COORDS = "jin_TextureCoords"; + +#endif // __JE_BASE_SHADER_H__ diff --git a/src/libjin/graphics/shaders/je_jsl_compiler.cpp b/src/libjin/graphics/shaders/je_jsl_compiler.cpp new file mode 100644 index 0000000..feb88d4 --- /dev/null +++ b/src/libjin/graphics/shaders/je_jsl_compiler.cpp @@ -0,0 +1,57 @@ +#include "../../core/je_configuration.h" +#if defined(jin_graphics) && (jin_graphics & jin_graphics_shader) + +#include "../../Filesystem/je_buffer.h" + +#include "je_jsl_compiler.h" + +using namespace std; +using namespace JinEngine::Filesystem; + +namespace JinEngine +{ + namespace Graphics + { + namespace Shaders + { + + #include "je_base.shader.h" + + bool JSLCompiler::compile(const string& jsl, string* vertex_shader, string* fragment_shader) + { + // parse shader source, need some optimizations + int loc_VERTEX_SHADER = jsl.find("#VERTEX_SHADER"); + int loc_END_VERTEX_SHADER = jsl.find("#END_VERTEX_SHADER"); + int loc_FRAGMENT_SHADER = jsl.find("#FRAGMENT_SHADER"); + int loc_END_FRAGMENT_SHADER = jsl.find("#END_FRAGMENT_SHADER"); + if (loc_VERTEX_SHADER == string::npos + || loc_END_VERTEX_SHADER == string::npos + || loc_FRAGMENT_SHADER == string::npos + || loc_END_FRAGMENT_SHADER == string::npos + ) + return false; + // Load vertex and fragment shader source into buffers. + { + // Compile JSL vertex program. + int start = loc_VERTEX_SHADER + strlen("#VERTEX_SHADER"); + *vertex_shader = jsl.substr(start, loc_END_VERTEX_SHADER - start); + Buffer vbuffer = Buffer(vertex_shader->length() + BASE_VERTEX_SHADER_SIZE); + formatVertexShader((char*)&vbuffer, vertex_shader->c_str()); + vertex_shader->assign((char*)&vbuffer); + } + { + // Compile JSL fragment program. + int start = loc_FRAGMENT_SHADER + strlen("#FRAGMENT_SHADER"); + *fragment_shader = jsl.substr(start, loc_END_FRAGMENT_SHADER - start); + Buffer fbuffer = Buffer(fragment_shader->length() + BASE_FRAGMENT_SHADER_SIZE); + formatFragmentShader((char*)&fbuffer, fragment_shader->c_str()); + fragment_shader->assign((char*)&fbuffer); + } + return true; + } + + } // namespace Shaders + } // namespace Graphics +} // namespace JinEngine + +#endif // (jin_graphics) && (jin_graphics & jin_graphics_shader)
\ No newline at end of file diff --git a/src/libjin/graphics/shaders/je_jsl_compiler.h b/src/libjin/graphics/shaders/je_jsl_compiler.h new file mode 100644 index 0000000..df1e827 --- /dev/null +++ b/src/libjin/graphics/shaders/je_jsl_compiler.h @@ -0,0 +1,45 @@ +#ifndef __JE_JSL_COMPILER_H__ +#define __JE_JSL_COMPILER_H__ + +#include "../../core/je_configuration.h" +#if defined(jin_graphics) && (jin_graphics & jin_graphics_shader) + +#include <string> + +#include "../../common/je_singleton.hpp" + +namespace JinEngine +{ + namespace Graphics + { + namespace Shaders + { + + /// + /// Compile JSL into GLSL. + /// + class JSLCompiler : public Singleton<JSLCompiler> + { + public: + /// + /// Compile JSL shader source into GLSL. + /// + /// @param jsl JSL shader source. + /// @param glsl_vertex Output of vertex glsl shader source. + /// @param glsl_fragment Output of fragment glsl shader source. + /// @return True if compile successful, otherwise return false. + /// + bool compile(const std::string& jsl, std::string* glsl_vertex, std::string* glsl_fragment); + + private: + singleton(JSLCompiler); + + }; + + } // namespace Shaders + } // namespace Graphics +} // namespace JinEngine + +#endif // (jin_graphics) && (jin_graphics & jin_graphics_shader) + +#endif // __JE_JSL_COMPILER_H__ diff --git a/src/libjin/graphics/shaders/je_shader.cpp b/src/libjin/graphics/shaders/je_shader.cpp new file mode 100644 index 0000000..c1abbf0 --- /dev/null +++ b/src/libjin/graphics/shaders/je_shader.cpp @@ -0,0 +1,281 @@ +#include "../../core/je_configuration.h" +#if defined(jin_graphics) && (jin_graphics & jin_graphics_shader) + +#include <iostream> + +#include "../../filesystem/je_buffer.h" +#include "../../utils/je_macros.h" + +#include "je_jsl_compiler.h" +#include "je_shader.h" + +using namespace std; +using namespace JinEngine::Filesystem; + +namespace JinEngine +{ + namespace Graphics + { + namespace Shaders + { + + // + // default_texture + // base_shader + // SHADER_FORMAT_SIZE + // formatShader + // +#include "built-in/je_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 DEFAULT_TEXTURE_UNIT = 0; + + /*static*/ Shader* Shader::CurrentShader = nullptr; + + Shader* Shader::createShader(const string& program) + { + Shader* shader = nullptr; + try + { + shader = new Shader(program); + } + catch (...) + { + return nullptr; + } + return shader; + } + + Shader::Shader(const string& program) + : mCurrentTextureUnit(DEFAULT_TEXTURE_UNIT) + { + if (!compile(program)) + throw 0; + } + + Shader::~Shader() + { + if (CurrentShader == this) + unuse(); + // delete shader program + glDeleteShader(mPID); + } + + 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; + } + + void Shader::use() + { + glUseProgram(mPID); + CurrentShader = this; + sendInt(SHADER_MAIN_TEXTURE, DEFAULT_TEXTURE_UNIT); + } + + /*static*/ void Shader::unuse() + { + glUseProgram(0); + CurrentShader = nullptr; + } + + GLint Shader::claimTextureUnit(const std::string& name) + { + std::map<std::string, GLint>::iterator unit = mTextureUnits.find(name); + if (unit != mTextureUnits.end()) + return unit->second; + static GLint MAX_TEXTURE_UNITS = getMaxTextureUnits(); + if (++mCurrentTextureUnit >= MAX_TEXTURE_UNITS) + return 0; + mTextureUnits[name] = mCurrentTextureUnit; + return mCurrentTextureUnit; + } + +#define checkJSL() \ + if (CurrentShader != this) \ + return + + void Shader::sendInt(const char* name, int value) + { + checkJSL(); + int loc = glGetUniformLocation(mPID, name); + glUniform1i(loc, value); + } + + void Shader::sendFloat(const char* variable, float number) + { + checkJSL(); + int loc = glGetUniformLocation(mPID, variable); + glUniform1f(loc, number); + } + + // + // 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; + // + void Shader::sendTexture(const char* variable, const Texture* tex) + { + checkJSL(); + GLint location = glGetUniformLocation(mPID, variable); + if (location == -1) + return; + GLint unit = claimTextureUnit(variable); + if (unit == 0) + { + // TODO: 쳣 + return; + } + gl.activeTexUnit(unit); + glUniform1i(location, unit); + gl.bindTexture(tex->getGLTexture()); + gl.activeTexUnit(0); + } + + void Shader::sendCanvas(const char* variable, const Canvas* canvas) + { + checkJSL(); + GLint location = glGetUniformLocation(mPID, variable); + if (location == -1) + return; + GLint unit = claimTextureUnit(variable); + if (unit == 0) + { + // TODO: 쳣 + return; + } + glUniform1i(location, unit); + glActiveTexture(GL_TEXTURE0 + unit); + gl.bindTexture(canvas->getGLTexture()); + + glActiveTexture(GL_TEXTURE0); + } + + void Shader::sendVec2(const char* name, float x, float y) + { + checkJSL(); + int loc = glGetUniformLocation(mPID, name); + glUniform2f(loc, x, y); + } + + void Shader::sendVec3(const char* name, float x, float y, float z) + { + checkJSL(); + int loc = glGetUniformLocation(mPID, name); + glUniform3f(loc, x, y, z); + } + + void Shader::sendVec4(const char* name, float x, float y, float z, float w) + { + checkJSL(); + int loc = glGetUniformLocation(mPID, name); + glUniform4f(loc, x, y, z, w); + } + + void Shader::sendColor(const char* name, const Color* col) + { + checkJSL(); + int loc = glGetUniformLocation(mPID, name); + glUniform4f(loc, + col->r / 255.f, + col->g / 255.f, + col->b / 255.f, + col->a / 255.f + ); + } + + void Shader::sendMatrix4(const char* name, const Math::Matrix* mat4) + { + int loc = glGetUniformLocation(mPID, name); + glUniformMatrix4fv(loc, 1, GL_FALSE, mat4->getElements()); + } + + void Shader::setVertexPointer(int n, GLenum type, GLsizei stride, const GLvoid * pointers) + { + GLint loc = glGetAttribLocation(mPID, SHADER_VERTEX_COORDS); + glEnableVertexAttribArray(0); + glVertexAttribPointer(loc, n, type, GL_FALSE, stride, pointers); + } + + void Shader::setUVPointer(int n, GLenum type, GLsizei stride, const GLvoid * pointers) + { + GLint loc = glGetAttribLocation(mPID, SHADER_TEXTURE_COORDS); + glEnableVertexAttribArray(1); + glVertexAttribPointer(loc, n, type, GL_FALSE, stride, pointers); + } + + } // namespace Shaders + } // namespace Graphics +} // namespace JinEngine + +#endif // (jin_graphics) && (jin_graphics & jin_graphics_shader)
\ No newline at end of file diff --git a/src/libjin/graphics/shaders/je_shader.h b/src/libjin/graphics/shaders/je_shader.h new file mode 100644 index 0000000..2009e79 --- /dev/null +++ b/src/libjin/graphics/shaders/je_shader.h @@ -0,0 +1,201 @@ +#ifndef __JE_SHADER_H__ +#define __JE_SHADER_H__ + +#include "../../core/je_configuration.h" +#if defined(jin_graphics) && (jin_graphics & jin_graphics_shader) + +#include <string> +#include <map> + +#include "GLee/GLee.h" + +#include "../je_color.h" +#include "../je_texture.h" +#include "../je_canvas.h" + +#include "je_base.shader.h" + +namespace JinEngine +{ + namespace Graphics + { + namespace Shaders + { + + /// + /// Built in shader program. + /// + /// Built in shader program written with custom shading language called JSL (jin shading language). A + /// JSL program is compiled into glsl, so most glsl built in functions and structs are available in + /// JSL. + /// + class Shader + { + public: + /// + /// Create shader program from source code. + /// + /// @param source The shader source code. + /// + static Shader* createShader(const std::string& source); + + /// + /// Get current shader. + /// + /// @return Current used shader program. + /// + static inline Shader* getCurrentShader() { return CurrentShader; } + + /// + /// Unuse current shader. + /// + static void unuse(); + + /// + /// Destructor of shader. + /// + virtual ~Shader(); + + /// + /// Use specific shader. + /// + void use(); + + /// + /// Send float value to shader. + /// + /// @param name Name of the uniform variable to be assigned. + /// @param number Value of uniform variable to be sent. + /// + void sendFloat(const char* name, float number); + + /// + /// Send texture to shader. + /// + /// @param name Name of the uniform variable to be assigned. + /// @param texture Texture to be sent. + /// + void sendTexture(const char* name, const Texture* texture); + + /// + /// Send integer value to shader + /// + /// @param name Name of the uniform variable to be assigned. + /// @param value Value to be sent. + /// + void sendInt(const char* name, int value); + + /// + /// Send 2D vector to shader. + /// + /// @param name Name of the uniform variable to be assigned. + /// @param x X value of the vector to be sent. + /// @param y Y value of the vector to be sent. + /// + void sendVec2(const char* name, float x, float y); + + /// + /// Send 3D vector to shader. + /// + /// @param name Name of the uniform variable to be assigned. + /// @param x X value of the vector to be sent. + /// @param y Y value of the vector to be sent. + /// @param z Z value of the vector to be sent. + /// + void sendVec3(const char* name, float x, float y, float z); + + /// + /// Send 4D vector to shader. + /// + /// @param name Name of the uniform variable to be assigned. + /// @param x X value of the vector to be sent. + /// @param y Y value of the vector to be sent. + /// @param z Z value of the vector to be sent. + /// @param w W value of the vector to be sent. + /// + void sendVec4(const char* name, float x, float y, float z, float w); + + /// + /// Send canvas to shader. + /// + /// @param name Name of the uniform variable to be assigned. + /// @param canvas Canvas to be sent. + /// + void sendCanvas(const char* name, const Canvas* canvas); + + /// + /// Send color to shader. + /// + /// @param name Name of the uniform variable to be assigned. + /// @param color Color to be sent. + /// + void sendColor(const char* name, const Color* color); + + /// + /// Send 4 by 4 matrix to shader. + /// + /// @param name Name of the uniform variable to be assigned. + /// @param mat4 Matrix to be sent. + /// + void sendMatrix4(const char* name, const Math::Matrix* mat4); + + /// + /// Set vertices value. + /// + /// @param n Number of vertices. + /// @param type Data type of each component in the array. + /// @param stride Byte offset between consecutive generic vertex attributes. + /// @param pointers Pointer to the first component of the first generic vertex attribute in the array. + /// + void setVertexPointer(int n, GLenum type, GLsizei stride, const GLvoid * pointers); + + /// + /// Set texture UV coordinates. + /// + /// @param n Number of vertices. + /// @param type Data type of each component in the array. + /// @param stride Byte offset between consecutive generic vertex attributes. + /// @param pointers Pointer to the first component of the first generic vertex attribute in the array. + /// + void setUVPointer(int n, GLenum type, GLsizei stride, const GLvoid * pointers); + + protected: + /// + /// Reference of current used shader. + /// + static Shader* CurrentShader; + + /// + /// Get texture unit of the uniform texture. If not, assign one. + /// + /// @param name Name of the texture uniform variable. + /// @return Texture unit which texture variable be assigned. + /// + GLint claimTextureUnit(const std::string& name); + + /// + /// Shader constructor. + /// + Shader(const std::string& program); + + /// + /// Compile JSL program into GLSL source. + /// + /// @param program JSL source code. + /// @return Return true if compile successed, otherwise return false. + /// + bool compile(const std::string& program); + + GLuint mPID; + GLint mCurrentTextureUnit; + std::map<std::string, GLint> mTextureUnits; + + }; + + } // namespace Shaders + } // namespace Graphics +} // namespace JinEngine + +#endif // (jin_graphics) && (jin_graphics & jin_graphics_shader) + +#endif // __JE_SHADER_H__
\ No newline at end of file |