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