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