aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2018-09-06 09:43:47 +0800
committerchai <chaifix@163.com>2018-09-06 09:43:47 +0800
commit05ebedc397432f054cdc367d35f86fd610fbfee6 (patch)
treed58bf6a52b7d201f19b0d1de6422e2071914c8d6 /src
parentea88790b539f80e1d41bba268136d78357aa87d1 (diff)
*update
Diffstat (limited to 'src')
-rw-r--r--src/libjin/Graphics/Shader.cpp199
-rw-r--r--src/libjin/Graphics/Shader.h54
-rw-r--r--src/libjin/Graphics/base.shader.h26
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