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