]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/output.cpp
Redesign the way shader programs are loaded
[libs/gl.git] / source / glsl / output.cpp
1 #include <msp/core/raii.h>
2 #include <msp/strings/format.h>
3 #include "output.h"
4
5 using namespace std;
6
7 namespace Msp {
8 namespace GL {
9 namespace SL {
10
11 Formatter::Formatter():
12         stage(0),
13         mode(Compiler::PROGRAM),
14         source_index(0),
15         source_line(1),
16         indent(0),
17         parameter_list(false)
18 { }
19
20 const string &Formatter::apply(Stage &s, Compiler::Mode m)
21 {
22         mode = m;
23         stage = &s;
24
25         GLApi api = get_gl_api();
26         const Version &ver = s.required_version;
27
28         if(ver)
29         {
30                 append(format("#version %d%02d", ver.major, ver.minor));
31                 if(api==OPENGL_ES2 && ver>=Version(3, 0))
32                         append(" es");
33                 formatted += '\n';
34         }
35
36         for(vector<const Extension *>::const_iterator i=s.required_extensions.begin(); i!=s.required_extensions.end(); ++i)
37                 append(format("#extension %s: require\n", (*i)->get_name()));
38         if(!s.required_extensions.empty())
39                 formatted += '\n';
40
41         visit(s.content);
42
43         return formatted;
44 }
45
46 void Formatter::append(const string &text)
47 {
48         formatted += text;
49         for(string::const_iterator i=text.begin(); i!=text.end(); ++i)
50                 if(*i=='\n')
51                         ++source_line;
52 }
53
54 void Formatter::append(char c)
55 {
56         formatted += c;
57         if(c=='\n')
58                 ++source_line;
59 }
60
61 void Formatter::set_source(unsigned index, unsigned line)
62 {
63         if(index!=source_index || (index && line!=source_line))
64         {
65                 if(index==source_index && line==source_line+1)
66                         formatted += '\n';
67                 else
68                 {
69                         unsigned l = line;
70                         if(mode==Compiler::PROGRAM && stage && stage->required_version<Version(3, 30))
71                                 --l;
72                         formatted += format("#line %d %d\n", l, index);
73                 }
74         }
75         source_index = index;
76         source_line = line;
77 }
78
79 void Formatter::visit(Literal &literal)
80 {
81         append(literal.token);
82 }
83
84 void Formatter::visit(ParenthesizedExpression &parexpr)
85 {
86         append('(');
87         parexpr.expression->visit(*this);
88         append(')');
89 }
90
91 void Formatter::visit(VariableReference &var)
92 {
93         append(var.name);
94 }
95
96 void Formatter::visit(MemberAccess &memacc)
97 {
98         memacc.left->visit(*this);
99         append(format(".%s", memacc.member));
100 }
101
102 void Formatter::visit(UnaryExpression &unary)
103 {
104         if(unary.prefix)
105                 append(unary.oper);
106         unary.expression->visit(*this);
107         if(!unary.prefix)
108                 append(unary.oper);
109 }
110
111 void Formatter::visit(BinaryExpression &binary)
112 {
113         binary.left->visit(*this);
114         append(binary.oper);
115         binary.right->visit(*this);
116         append(binary.after);
117 }
118
119 void Formatter::visit(Assignment &assign)
120 {
121         assign.left->visit(*this);
122         append(format(" %s ", assign.oper));
123         assign.right->visit(*this);
124 }
125
126 void Formatter::visit(FunctionCall &call)
127 {
128         append(format("%s(", call.name));
129         for(NodeArray<Expression>::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i)
130         {
131                 if(i!=call.arguments.begin())
132                         append(", ");
133                 (*i)->visit(*this);
134         }
135         append(')');
136 }
137
138 void Formatter::visit(ExpressionStatement &expr)
139 {
140         expr.expression->visit(*this);
141         append(';');
142 }
143
144 void Formatter::visit(Block &block)
145 {
146         unsigned brace_indent = indent;
147         bool use_braces = (block.use_braces || (indent && block.body.size()!=1));
148         if(use_braces)
149                 append(format("%s{\n", string(brace_indent*2, ' ')));
150
151         SetForScope<unsigned> set(indent, indent+(indent>0 || use_braces));
152         string spaces(indent*2, ' ');
153         for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
154         {
155                 if(i!=block.body.begin())
156                         append('\n');
157                 set_source((*i)->source, (*i)->line);
158                 append(spaces);
159                 (*i)->visit(*this);
160         }
161
162         if(use_braces)
163                 append(format("\n%s}", string(brace_indent*2, ' ')));
164 }
165
166 void Formatter::visit(Import &import)
167 {
168         append(format("import %s;", import.module));
169 }
170
171 void Formatter::visit(Precision &prec)
172 {
173         append(format("precision %s %s;", prec.precision, prec.type));
174 }
175
176 void Formatter::visit(Layout &layout)
177 {
178         append("layout(");
179         for(vector<Layout::Qualifier>::const_iterator i=layout.qualifiers.begin(); i!=layout.qualifiers.end(); ++i)
180         {
181                 if(i!=layout.qualifiers.begin())
182                         append(", ");
183                 append(i->identifier);
184                 if(!i->value.empty())
185                         append(format("=%s", i->value));
186         }
187         append(')');
188 }
189
190 void Formatter::visit(InterfaceLayout &layout)
191 {
192         layout.layout.visit(*this);
193         append(format(" %s;", layout.interface));
194 }
195
196 void Formatter::visit(StructDeclaration &strct)
197 {
198         append(format("struct %s\n", strct.name));
199         strct.members.visit(*this);
200         append(';');
201 }
202
203 void Formatter::visit(VariableDeclaration &var)
204 {
205         if(var.layout)
206         {
207                 var.layout->visit(*this);
208                 append(' ');
209         }
210         if(var.constant)
211                 append("const ");
212         if(!var.interpolation.empty())
213                 append(format("%s ", var.interpolation));
214         if(!var.sampling.empty())
215                 append(format("%s ", var.sampling));
216         if(!var.interface.empty() && var.interface!=block_interface)
217         {
218                 string interface = var.interface;
219                 if(mode==Compiler::PROGRAM && stage && stage->required_version<Version(1, 30))
220                 {
221                         if(stage->type==Stage::VERTEX && var.interface=="in")
222                                 interface = "attribute";
223                         else if((stage->type==Stage::VERTEX && var.interface=="out") || (stage->type==Stage::FRAGMENT && var.interface=="in"))
224                                 interface = "varying";
225                 }
226                 append(format("%s ", interface));
227         }
228         if(!var.precision.empty())
229                 append(format("%s ", var.precision));
230         append(format("%s %s", var.type, var.name));
231         if(var.array)
232         {
233                 append('[');
234                 if(var.array_size)
235                         var.array_size->visit(*this);
236                 append(']');
237         }
238         if(var.init_expression)
239         {
240                 append(" = ");
241                 var.init_expression->visit(*this);
242         }
243         if(!parameter_list)
244                 append(';');
245 }
246
247 void Formatter::visit(InterfaceBlock &iface)
248 {
249         SetForScope<string> set(block_interface, iface.interface);
250         append(format("%s %s\n", iface.interface, iface.name));
251         iface.members.visit(*this);
252         append(';');
253 }
254
255 void Formatter::visit(FunctionDeclaration &func)
256 {
257         append(format("%s %s(", func.return_type, func.name));
258         for(NodeArray<VariableDeclaration>::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i)
259         {
260                 if(i!=func.parameters.begin())
261                         append(", ");
262                 SetFlag set(parameter_list);
263                 (*i)->visit(*this);
264         }
265         append(')');
266         if(func.definition==&func)
267         {
268                 append('\n');
269                 func.body.visit(*this);
270         }
271         else
272                 append(';');
273 }
274
275 void Formatter::visit(Conditional &cond)
276 {
277         append("if(");
278         cond.condition->visit(*this);
279         append(")\n");
280
281         cond.body.visit(*this);
282         if(!cond.else_body.body.empty())
283         {
284                 Conditional *else_cond = dynamic_cast<Conditional *>(cond.else_body.body.front().get());
285                 if(cond.else_body.body.size()==1 && else_cond)
286                 {
287                         append('\n');
288                         set_source(else_cond->source, else_cond->line);
289                         append(format("%selse ", string(indent*2, ' ')));
290                         else_cond->visit(*this);
291                 }
292                 else
293                 {
294                         append(format("\n%selse\n", string(indent*2, ' ')));
295                         cond.else_body.visit(*this);
296                 }
297         }
298 }
299
300 void Formatter::visit(Iteration &iter)
301 {
302         if(!iter.init_statement && iter.condition && !iter.loop_expression)
303         {
304                 append("while(");
305                 iter.condition->visit(*this);
306                 append(')');
307         }
308         else
309         {
310                 append("for(");
311                 if(iter.init_statement)
312                         iter.init_statement->visit(*this);
313                 else
314                         append(';');
315                 if(iter.condition)
316                 {
317                         append(' ');
318                         iter.condition->visit(*this);
319                 }
320                 append(';');
321                 if(iter.loop_expression)
322                 {
323                         append(' ');
324                         iter.loop_expression->visit(*this);
325                 }
326                 append(')');
327         }
328
329         if(iter.body.body.empty())
330                 append(" { }");
331         else
332         {
333                 append('\n');
334                 iter.body.visit(*this);
335         }
336 }
337
338 void Formatter::visit(Return &ret)
339 {
340         append("return");
341         if(ret.expression)
342         {
343                 append(' ');
344                 ret.expression->visit(*this);
345         }
346         append(';');
347 }
348
349 void Formatter::visit(Jump &jump)
350 {
351         append(jump.keyword);
352         append(';');
353 }
354
355 } // namespace SL
356 } // namespace GL
357 } // namespace Msp