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