aboutsummaryrefslogtreecommitdiff
path: root/src/libjin/graphics/shaders/jsl_compiler.cpp
blob: ea247c0e3c17fc812c8e3f8283eb076f70f6e34b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#include "../../core/configuration.h"
#if defined(jin_graphics) && (jin_graphics & jin_graphics_shader)

#include "../../common/string.h"
#include "../../Filesystem/buffer.h"

#include "jsl_compiler.h"

using namespace std;
using namespace JinEngine::Filesystem;

namespace JinEngine
{
	namespace Graphics
	{
		namespace Shaders
		{

			///
			/// Uniforms:
			///	 jin_ProjectionMatrix --+
			///	 jin_ModelViewMatrix	|- Uniforms
			///	 jin_MainTexture		|
			///	 jin_RenderTargetSize   |
			///	 jin_Time			 --+
			///
			/// Built-in variables in vertex shader:
			///	 jin_VertexCoords	 --+
			///	 jin_TextureCoords	  |- Attributes
			///	 jin_VertexColor	  --+
			///	 jin_Color			---- GLSL built in
			///
			/// Built-in variables in fragment shader:
			///	 jin_Color			--+
			///	 jin_XY				 |- Inputs
			///	 jin_UV				 |
			///	 jin_COLOR			--+
			///

			JinEngine::String SHADER_PROJECTION_MATRIX = "jin_ProjectionMatrix";
			JinEngine::String SHADER_MODELVIEW_MATRIX = "jin_ModelViewMatrix";
			JinEngine::String SHADER_MAIN_TEXTURE = "jin_MainTexture";
			JinEngine::String SHADER_VERTEX_COORDS = "jin_VertexCoords";
			JinEngine::String SHADER_TEXTURE_COORDS = "jin_TextureCoords";
			JinEngine::String SHADER_VERTEX_COLOR = "jin_VertexColor";
			JinEngine::String SHADER_TIME = "jin_Time";
			JinEngine::String SHADER_RENDERTARGET_SIZE = "jin_RenderTargetSize";
			JinEngine::String SHADER_VERSION = "#version 130 core \n";
			JinEngine::String SHADER_DEFINITIONS =
				// Types
				"#define Number  float	 \n"
				"#define Texture sampler2D \n"
				"#define Canvas  sampler2D \n"
				"#define Color   vec4	  \n"
				"#define Vec2	vec2	  \n"
				"#define Vec3	vec3	  \n"
				"#define Vec4	vec4	  \n"
				// Functions
				"#define texel   texture2D \n"
				// Structs
				"struct Vertex			 \n"
				"{						 \n"
				"	vec2 xy;			  \n"
				"	vec2 uv;			  \n"
				"	vec4 color;		   \n"
				"};						\n"
				"\n";
			JinEngine::String SHADER_UNIFORMS =
				"uniform Texture " + SHADER_MAIN_TEXTURE + "; \n" // Main texture goes first.
				"uniform mat4 " + SHADER_PROJECTION_MATRIX + "; \n"
				"uniform mat4 " + SHADER_MODELVIEW_MATRIX + "; \n"
				"uniform vec2 " + SHADER_TIME + "; \n"
				"uniform vec2 " + SHADER_RENDERTARGET_SIZE + "; \n";

			JinEngine::String JSLCompiler::formatVertexShader(const JinEngine::String& vert)
			{
				static JinEngine::String vert_part1 =
					SHADER_VERSION +
					SHADER_DEFINITIONS +
					SHADER_UNIFORMS + 
					"in vec2 " + SHADER_VERTEX_COORDS + "; \n"
					"in vec2 " + SHADER_TEXTURE_COORDS + "; \n"
					"in vec4 " + SHADER_VERTEX_COLOR + "; \n"; // Color data in unsigned byte.
				static JinEngine::String vert_part2 =
					"\n"
					"out vec4 jin_Color; \n"
					"out vec2 jin_XY; \n"
					"out vec2 jin_UV; \n"
					"out vec4 jin_COLOR; \n"
					"void main()\n"
					"{\n"
					"	vec4 v = " + SHADER_MODELVIEW_MATRIX + " * vec4(" + SHADER_VERTEX_COORDS + ", 0, 1.0); \n"
					"	Vertex _v = vert(Vertex(v.xy, " + SHADER_TEXTURE_COORDS + ", " + SHADER_VERTEX_COLOR + ")); \n"
					"	gl_Position = " + SHADER_PROJECTION_MATRIX + " * vec4(_v.xy, 0, 1.0f); \n"
					"	jin_Color = gl_Color; \n"
					"	jin_XY = _v.xy; \n"
					"	jin_UV = _v.uv; \n"
					"	jin_COLOR = _v.color; \n"
					"}";
				return vert_part1 + vert + vert_part2;
			}

			JinEngine::String JSLCompiler::formatFragmentShader(const JinEngine::String& frag)
			{
				static JinEngine::String frag_part1 =
					SHADER_VERSION +
					SHADER_DEFINITIONS +
					SHADER_UNIFORMS + 
					"in vec4 jin_Color; \n"
					"in vec2 jin_XY; \n"
					"in vec2 jin_UV; \n"
					"in vec4 jin_COLOR; \n";
				static JinEngine::String frag_part2 =
					"\n"
					"out vec4 jin_OutColor; \n"
					"void main() \n"
					"{ \n"
					"	jin_OutColor = frag(jin_Color, " + SHADER_MAIN_TEXTURE + ", Vertex(jin_XY, jin_UV, jin_COLOR)); \n"
					"} \n";
				return frag_part1 + frag + frag_part2;
			}

			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);
					vertex_shader->assign(formatVertexShader(*vertex_shader));
				}
				{
					// Compile JSL fragment program.
					int start = loc_FRAGMENT_SHADER + strlen("#FRAGMENT_SHADER");
					*fragment_shader = jsl.substr(start, loc_END_FRAGMENT_SHADER - start);
					fragment_shader->assign(formatFragmentShader(*fragment_shader));
				}
				return true;
			}

		} // namespace Shaders
	} // namespace Graphics
} // namespace JinEngine

#endif // (jin_graphics) && (jin_graphics & jin_graphics_shader)