1#include "glsl_shader_compiler.h"
2
3#include <base/system.h>
4
5#include <engine/graphics.h>
6
7CGLSLCompiler::CGLSLCompiler(int OpenGLVersionMajor, int OpenGLVersionMinor, int OpenGLVersionPatch, bool IsOpenGLES, float TextureLODBias)
8{
9 m_OpenGLVersionMajor = OpenGLVersionMajor;
10 m_OpenGLVersionMinor = OpenGLVersionMinor;
11 m_OpenGLVersionPatch = OpenGLVersionPatch;
12
13 m_IsOpenGLES = IsOpenGLES;
14
15 m_TextureLODBias = TextureLODBias;
16
17 m_HasTextureArray = false;
18 m_TextureReplaceType = 0;
19}
20
21void CGLSLCompiler::AddDefine(const std::string &DefineName, const std::string &DefineValue)
22{
23 m_vDefines.emplace_back(args: DefineName, args: DefineValue);
24}
25
26void CGLSLCompiler::AddDefine(const char *pDefineName, const char *pDefineValue)
27{
28 AddDefine(DefineName: std::string(pDefineName), DefineValue: std::string(pDefineValue));
29}
30
31void CGLSLCompiler::ClearDefines()
32{
33 m_vDefines.clear();
34}
35
36void CGLSLCompiler::ParseLine(std::string &Line, const char *pReadLine, EGLSLShaderCompilerType Type)
37{
38 EBackendType BackendType = m_IsOpenGLES ? BACKEND_TYPE_OPENGL_ES : BACKEND_TYPE_OPENGL;
39 bool IsNewOpenGL = (BackendType == BACKEND_TYPE_OPENGL ? (m_OpenGLVersionMajor >= 4 || (m_OpenGLVersionMajor == 3 && m_OpenGLVersionMinor == 3)) : m_OpenGLVersionMajor >= 3);
40 if(!IsNewOpenGL)
41 {
42 const char *pBuff = pReadLine;
43 char aTmpStr[1024];
44 size_t TmpStrSize = 0;
45 while(*pBuff)
46 {
47 while(*pBuff && str_isspace(c: *pBuff))
48 {
49 Line.append(n: 1, c: *pBuff);
50 ++pBuff;
51 }
52
53 while(*pBuff && !str_isspace(c: *pBuff) && *pBuff != '(' && *pBuff != '.')
54 {
55 aTmpStr[TmpStrSize++] = *pBuff;
56 ++pBuff;
57 }
58
59 if(TmpStrSize > 0)
60 {
61 aTmpStr[TmpStrSize] = 0;
62 TmpStrSize = 0;
63 if(str_comp(a: aTmpStr, b: "layout") == 0)
64 {
65 //search for ' in'
66 while(*pBuff && (*pBuff != ' ' || (*(pBuff + 1) && *(pBuff + 1) != 'i') || *(pBuff + 2) != 'n'))
67 {
68 ++pBuff;
69 }
70
71 if(*pBuff == ' ' && *(pBuff + 1) == 'i' && *(pBuff + 2) == 'n')
72 {
73 pBuff += 3;
74 Line.append(s: "attribute");
75 Line.append(s: pBuff);
76 return;
77 }
78 else
79 {
80 dbg_msg(sys: "shadercompiler", fmt: "Fix shader for older OpenGL versions.");
81 }
82 }
83 else if(str_comp(a: aTmpStr, b: "noperspective") == 0 || str_comp(a: aTmpStr, b: "smooth") == 0 || str_comp(a: aTmpStr, b: "flat") == 0)
84 {
85 //search for 'in' or 'out'
86 while(*pBuff && ((*pBuff != 'i' || *(pBuff + 1) != 'n') && (*pBuff != 'o' || (*(pBuff + 1) && *(pBuff + 1) != 'u') || *(pBuff + 2) != 't')))
87 {
88 // append anything that is inbetween noperspective & in/out vars
89 Line.push_back(c: *pBuff);
90 ++pBuff;
91 }
92
93 bool Found = false;
94 if(*pBuff)
95 {
96 if(*pBuff == 'i' && *(pBuff + 1) == 'n')
97 {
98 pBuff += 2;
99 Found = true;
100 }
101 else if(*pBuff == 'o' && *(pBuff + 1) == 'u' && *(pBuff + 2) == 't')
102 {
103 pBuff += 3;
104 Found = true;
105 }
106 }
107
108 if(!Found)
109 {
110 dbg_msg(sys: "shadercompiler", fmt: "Fix shader for older OpenGL versions.");
111 }
112
113 Line.append(s: "varying");
114 Line.append(s: pBuff);
115 return;
116 }
117 else if(str_comp(a: aTmpStr, b: "out") == 0 || str_comp(a: aTmpStr, b: "in") == 0)
118 {
119 if(Type == GLSL_SHADER_COMPILER_TYPE_FRAGMENT && str_comp(a: aTmpStr, b: "out") == 0)
120 return;
121 Line.append(s: "varying");
122 Line.append(s: pBuff);
123 return;
124 }
125 else if(str_comp(a: aTmpStr, b: "FragClr") == 0)
126 {
127 Line.append(s: "gl_FragColor");
128 Line.append(s: pBuff);
129 return;
130 }
131 else if(str_comp(a: aTmpStr, b: "texture") == 0)
132 {
133 if(m_TextureReplaceType == GLSL_COMPILER_TEXTURE_REPLACE_TYPE_2D)
134 Line.append(s: "texture2D");
135 else if(m_TextureReplaceType == GLSL_COMPILER_TEXTURE_REPLACE_TYPE_3D)
136 Line.append(s: "texture3D");
137 else if(m_TextureReplaceType == GLSL_COMPILER_TEXTURE_REPLACE_TYPE_2D_ARRAY)
138 Line.append(s: "texture2DArray");
139 std::string RestLine;
140 ParseLine(Line&: RestLine, pReadLine: pBuff, Type);
141 Line.append(str: RestLine);
142 return;
143 }
144 else
145 {
146 Line.append(s: aTmpStr);
147 }
148 }
149
150 if(*pBuff)
151 {
152 Line.append(n: 1, c: *pBuff);
153 ++pBuff;
154 }
155 }
156 }
157 else
158 {
159 if(BackendType == BACKEND_TYPE_OPENGL_ES)
160 {
161 const char *pBuff = pReadLine;
162 char aTmpStr[1024];
163 size_t TmpStrSize = 0;
164 while(*pBuff)
165 {
166 while(*pBuff && str_isspace(c: *pBuff))
167 {
168 Line.append(n: 1, c: *pBuff);
169 ++pBuff;
170 }
171
172 while(*pBuff && !str_isspace(c: *pBuff) && *pBuff != '(' && *pBuff != '.')
173 {
174 aTmpStr[TmpStrSize++] = *pBuff;
175 ++pBuff;
176 }
177
178 if(TmpStrSize > 0)
179 {
180 aTmpStr[TmpStrSize] = 0;
181 TmpStrSize = 0;
182
183 if(str_comp(a: aTmpStr, b: "noperspective") == 0)
184 {
185 Line.append(s: "smooth");
186 Line.append(s: pBuff);
187 return;
188 }
189 // since GLES doesn't support texture LOD bias as global state, use the shader function instead(since GLES 3.0 uses shaders only anyway)
190 else if(str_comp(a: aTmpStr, b: "texture") == 0)
191 {
192 Line.append(s: "texture");
193 // check opening and closing brackets to find the end
194 int CurBrackets = 1;
195 while(*pBuff && *pBuff != '(')
196 {
197 Line.append(n: 1, c: *pBuff);
198
199 ++pBuff;
200 }
201
202 if(*pBuff)
203 {
204 Line.append(n: 1, c: *pBuff);
205 ++pBuff;
206 }
207
208 while(*pBuff)
209 {
210 if(*pBuff == '(')
211 ++CurBrackets;
212 if(*pBuff == ')')
213 --CurBrackets;
214
215 if(CurBrackets == 0)
216 {
217 // found end
218 Line.append(str: std::string(", ") + std::to_string(val: m_TextureLODBias) + ")");
219 ++pBuff;
220 break;
221 }
222 else
223 Line.append(n: 1, c: *pBuff);
224 ++pBuff;
225 }
226
227 Line.append(s: pBuff);
228
229 return;
230 }
231 else
232 {
233 Line.append(s: aTmpStr);
234 }
235 }
236
237 if(*pBuff)
238 {
239 Line.append(n: 1, c: *pBuff);
240 ++pBuff;
241 }
242 }
243 }
244 else
245 Line = pReadLine;
246 }
247}
248