2011-06-20 Zhenyao Mo <zmo@google.com>
[WebKit-https.git] / Source / ThirdParty / ANGLE / src / compiler / OutputHLSL.cpp
1 //
2 // Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 #include "compiler/OutputHLSL.h"
8
9 #include "compiler/debug.h"
10 #include "compiler/InfoSink.h"
11 #include "compiler/UnfoldSelect.h"
12 #include "compiler/SearchSymbol.h"
13
14 #include <stdio.h>
15 #include <algorithm>
16
17 namespace sh
18 {
19 // Integer to TString conversion
20 TString str(int i)
21 {
22     char buffer[20];
23     sprintf(buffer, "%d", i);
24     return buffer;
25 }
26
27 OutputHLSL::OutputHLSL(TParseContext &context) : TIntermTraverser(true, true, true), mContext(context)
28 {
29     mUnfoldSelect = new UnfoldSelect(context, this);
30     mInsideFunction = false;
31
32     mUsesTexture2D = false;
33     mUsesTexture2D_bias = false;
34     mUsesTexture2DProj = false;
35     mUsesTexture2DProj_bias = false;
36     mUsesTexture2DProjLod = false;
37     mUsesTexture2DLod = false;
38     mUsesTextureCube = false;
39     mUsesTextureCube_bias = false;
40     mUsesTextureCubeLod = false;
41     mUsesDepthRange = false;
42     mUsesFragCoord = false;
43     mUsesPointCoord = false;
44     mUsesFrontFacing = false;
45     mUsesPointSize = false;
46     mUsesXor = false;
47     mUsesMod1 = false;
48     mUsesMod2 = false;
49     mUsesMod3 = false;
50     mUsesMod4 = false;
51     mUsesFaceforward1 = false;
52     mUsesFaceforward2 = false;
53     mUsesFaceforward3 = false;
54     mUsesFaceforward4 = false;
55     mUsesEqualMat2 = false;
56     mUsesEqualMat3 = false;
57     mUsesEqualMat4 = false;
58     mUsesEqualVec2 = false;
59     mUsesEqualVec3 = false;
60     mUsesEqualVec4 = false;
61     mUsesEqualIVec2 = false;
62     mUsesEqualIVec3 = false;
63     mUsesEqualIVec4 = false;
64     mUsesEqualBVec2 = false;
65     mUsesEqualBVec3 = false;
66     mUsesEqualBVec4 = false;
67     mUsesAtan2 = false;
68
69     mScopeDepth = 0;
70
71     mUniqueIndex = 0;
72 }
73
74 OutputHLSL::~OutputHLSL()
75 {
76     delete mUnfoldSelect;
77 }
78
79 void OutputHLSL::output()
80 {
81     mContext.treeRoot->traverse(this);   // Output the body first to determine what has to go in the header
82     header();
83
84     mContext.infoSink.obj << mHeader.c_str();
85     mContext.infoSink.obj << mBody.c_str();
86 }
87
88 TInfoSinkBase &OutputHLSL::getBodyStream()
89 {
90     return mBody;
91 }
92
93 int OutputHLSL::vectorSize(const TType &type) const
94 {
95     int elementSize = type.isMatrix() ? type.getNominalSize() : 1;
96     int arraySize = type.isArray() ? type.getArraySize() : 1;
97
98     return elementSize * arraySize;
99 }
100
101 void OutputHLSL::header()
102 {
103     ShShaderType shaderType = mContext.shaderType;
104     TInfoSinkBase &out = mHeader;
105
106     for (StructDeclarations::iterator structDeclaration = mStructDeclarations.begin(); structDeclaration != mStructDeclarations.end(); structDeclaration++)
107     {
108         out << *structDeclaration;
109     }
110
111     for (Constructors::iterator constructor = mConstructors.begin(); constructor != mConstructors.end(); constructor++)
112     {
113         out << *constructor;
114     }
115
116     if (shaderType == SH_FRAGMENT_SHADER)
117     {
118         TString uniforms;
119         TString varyings;
120
121         TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
122         int semanticIndex = 0;
123
124         for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
125         {
126             const TSymbol *symbol = (*namedSymbol).second;
127             const TString &name = symbol->getName();
128
129             if (symbol->isVariable())
130             {
131                 const TVariable *variable = static_cast<const TVariable*>(symbol);
132                 const TType &type = variable->getType();
133                 TQualifier qualifier = type.getQualifier();
134
135                 if (qualifier == EvqUniform)
136                 {
137                     if (mReferencedUniforms.find(name.c_str()) != mReferencedUniforms.end())
138                     {
139                         uniforms += "uniform " + typeString(type) + " " + decorate(name) + arrayString(type) + ";\n";
140                     }
141                 }
142                 else if (qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
143                 {
144                     if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
145                     {
146                         // Program linking depends on this exact format
147                         varyings += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
148
149                         semanticIndex += type.isArray() ? type.getArraySize() : 1;
150                     }
151                 }
152                 else if (qualifier == EvqGlobal || qualifier == EvqTemporary)
153                 {
154                     // Globals are declared and intialized as an aggregate node
155                 }
156                 else if (qualifier == EvqConst)
157                 {
158                     // Constants are repeated as literals where used
159                 }
160                 else UNREACHABLE();
161             }
162         }
163
164         out << "// Varyings\n";
165         out <<  varyings;
166         out << "\n"
167                "static float4 gl_Color[1] = {float4(0, 0, 0, 0)};\n";
168
169         if (mUsesFragCoord)
170         {
171             out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
172         }
173
174         if (mUsesPointCoord)
175         {
176             out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
177         }
178
179         if (mUsesFrontFacing)
180         {
181             out << "static bool gl_FrontFacing = false;\n";
182         }
183
184         out << "\n";
185
186         if (mUsesFragCoord)
187         {
188             out << "uniform float4 dx_Viewport;\n"
189                    "uniform float2 dx_Depth;\n";
190         }
191
192         if (mUsesFrontFacing)
193         {
194             out << "uniform bool dx_PointsOrLines;\n"
195                    "uniform bool dx_FrontCCW;\n";
196         }
197         
198         out << "\n";
199         out <<  uniforms;
200         out << "\n";
201
202         // The texture fetch functions "flip" the Y coordinate in one way or another. This is because textures are stored
203         // according to the OpenGL convention, i.e. (0, 0) is "bottom left", rather than the D3D convention where (0, 0)
204         // is "top left". Since the HLSL texture fetch functions expect textures to be stored according to the D3D
205         // convention, the Y coordinate passed to these functions is adjusted to compensate.
206         //
207         // The simplest case is texture2D where the mapping is Y -> 1-Y, which maps [0, 1] -> [1, 0].
208         //
209         // The texture2DProj functions are more complicated because the projection divides by either Z or W. For the vec3
210         // case, the mapping is Y -> Z-Y or Y/Z -> 1-Y/Z, which again maps [0, 1] -> [1, 0].
211         //
212         // For cube textures the mapping is Y -> -Y, which maps [-1, 1] -> [1, -1]. This is not sufficient on its own for the
213         // +Y and -Y faces, which are now on the "wrong sides" of the cube. This is compensated for by exchanging the
214         // +Y and -Y faces everywhere else throughout the code.
215         
216         if (mUsesTexture2D)
217         {
218             out << "float4 gl_texture2D(sampler2D s, float2 t)\n"
219                    "{\n"
220                    "    return tex2D(s, float2(t.x, 1 - t.y));\n"
221                    "}\n"
222                    "\n";
223         }
224
225         if (mUsesTexture2D_bias)
226         {
227             out << "float4 gl_texture2D(sampler2D s, float2 t, float bias)\n"
228                    "{\n"
229                    "    return tex2Dbias(s, float4(t.x, 1 - t.y, 0, bias));\n"
230                    "}\n"
231                    "\n";
232         }
233
234         if (mUsesTexture2DProj)
235         {
236             out << "float4 gl_texture2DProj(sampler2D s, float3 t)\n"
237                    "{\n"
238                    "    return tex2Dproj(s, float4(t.x, t.z - t.y, 0, t.z));\n"
239                    "}\n"
240                    "\n"
241                    "float4 gl_texture2DProj(sampler2D s, float4 t)\n"
242                    "{\n"
243                    "    return tex2Dproj(s, float4(t.x, t.w - t.y, t.z, t.w));\n"
244                    "}\n"
245                    "\n";
246         }
247
248         if (mUsesTexture2DProj_bias)
249         {
250             out << "float4 gl_texture2DProj(sampler2D s, float3 t, float bias)\n"
251                    "{\n"
252                    "    return tex2Dbias(s, float4(t.x / t.z, 1 - (t.y / t.z), 0, bias));\n"
253                    "}\n"
254                    "\n"
255                    "float4 gl_texture2DProj(sampler2D s, float4 t, float bias)\n"
256                    "{\n"
257                    "    return tex2Dbias(s, float4(t.x / t.w, 1 - (t.y / t.w), 0, bias));\n"
258                    "}\n"
259                    "\n";
260         }
261
262         if (mUsesTextureCube)
263         {
264             out << "float4 gl_textureCube(samplerCUBE s, float3 t)\n"
265                    "{\n"
266                    "    return texCUBE(s, float3(t.x, -t.y, t.z));\n"
267                    "}\n"
268                    "\n";
269         }
270
271         if (mUsesTextureCube_bias)
272         {
273             out << "float4 gl_textureCube(samplerCUBE s, float3 t, float bias)\n"
274                    "{\n"
275                    "    return texCUBEbias(s, float4(t.x, -t.y, t.z, bias));\n"
276                    "}\n"
277                    "\n";
278         }
279     }
280     else   // Vertex shader
281     {
282         TString uniforms;
283         TString attributes;
284         TString varyings;
285
286         TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
287
288         for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
289         {
290             const TSymbol *symbol = (*namedSymbol).second;
291             const TString &name = symbol->getName();
292
293             if (symbol->isVariable())
294             {
295                 const TVariable *variable = static_cast<const TVariable*>(symbol);
296                 const TType &type = variable->getType();
297                 TQualifier qualifier = type.getQualifier();
298
299                 if (qualifier == EvqUniform)
300                 {
301                     if (mReferencedUniforms.find(name.c_str()) != mReferencedUniforms.end())
302                     {
303                         uniforms += "uniform " + typeString(type) + " " + decorate(name) + arrayString(type) + ";\n";
304                     }
305                 }
306                 else if (qualifier == EvqAttribute)
307                 {
308                     if (mReferencedAttributes.find(name.c_str()) != mReferencedAttributes.end())
309                     {
310                         attributes += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
311                     }
312                 }
313                 else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut)
314                 {
315                     if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
316                     {
317                         // Program linking depends on this exact format
318                         varyings += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
319                     }
320                 }
321                 else if (qualifier == EvqGlobal || qualifier == EvqTemporary)
322                 {
323                     // Globals are declared and intialized as an aggregate node
324                 }
325                 else if (qualifier == EvqConst)
326                 {
327                     // Constants are repeated as literals where used
328                 }
329                 else UNREACHABLE();
330             }
331         }
332
333         out << "// Attributes\n";
334         out <<  attributes;
335         out << "\n"
336                "static float4 gl_Position = float4(0, 0, 0, 0);\n";
337         
338         if (mUsesPointSize)
339         {
340             out << "static float gl_PointSize = float(1);\n";
341         }
342
343         out << "\n"
344                "// Varyings\n";
345         out <<  varyings;
346         out << "\n"
347                "uniform float2 dx_HalfPixelSize;\n"
348                "\n";
349         out <<  uniforms;
350         out << "\n";
351
352         // The texture fetch functions "flip" the Y coordinate in one way or another. This is because textures are stored
353         // according to the OpenGL convention, i.e. (0, 0) is "bottom left", rather than the D3D convention where (0, 0)
354         // is "top left". Since the HLSL texture fetch functions expect textures to be stored according to the D3D
355         // convention, the Y coordinate passed to these functions is adjusted to compensate.
356         //
357         // The simplest case is texture2D where the mapping is Y -> 1-Y, which maps [0, 1] -> [1, 0].
358         //
359         // The texture2DProj functions are more complicated because the projection divides by either Z or W. For the vec3
360         // case, the mapping is Y -> Z-Y or Y/Z -> 1-Y/Z, which again maps [0, 1] -> [1, 0].
361         //
362         // For cube textures the mapping is Y -> -Y, which maps [-1, 1] -> [1, -1]. This is not sufficient on its own for the
363         // +Y and -Y faces, which are now on the "wrong sides" of the cube. This is compensated for by exchanging the
364         // +Y and -Y faces everywhere else throughout the code.
365         
366         if (mUsesTexture2D)
367         {
368             out << "float4 gl_texture2D(sampler2D s, float2 t)\n"
369                    "{\n"
370                    "    return tex2Dlod(s, float4(t.x, 1 - t.y, 0, 0));\n"
371                    "}\n"
372                    "\n";
373         }
374
375         if (mUsesTexture2DLod)
376         {
377             out << "float4 gl_texture2DLod(sampler2D s, float2 t, float lod)\n"
378                    "{\n"
379                    "    return tex2Dlod(s, float4(t.x, 1 - t.y, 0, lod));\n"
380                    "}\n"
381                    "\n";
382         }
383
384         if (mUsesTexture2DProj)
385         {
386             out << "float4 gl_texture2DProj(sampler2D s, float3 t)\n"
387                    "{\n"
388                    "    return tex2Dlod(s, float4(t.x / t.z, 1 - t.y / t.z, 0, 0));\n"
389                    "}\n"
390                    "\n"
391                    "float4 gl_texture2DProj(sampler2D s, float4 t)\n"
392                    "{\n"
393                    "    return tex2Dlod(s, float4(t.x / t.w, 1 - t.y / t.w, 0, 0));\n"
394                    "}\n"
395                    "\n";
396         }
397
398         if (mUsesTexture2DProjLod)
399         {
400             out << "float4 gl_texture2DProjLod(sampler2D s, float3 t, float lod)\n"
401                    "{\n"
402                    "    return tex2Dlod(s, float4(t.x / t.z, 1 - t.y / t.z, 0, lod));\n"
403                    "}\n"
404                    "\n"
405                    "float4 gl_texture2DProjLod(sampler2D s, float4 t, float lod)\n"
406                    "{\n"
407                    "    return tex2Dlod(s, float4(t.x / t.w, 1 - t.y / t.w, 0, lod));\n"
408                    "}\n"
409                    "\n";
410         }
411
412         if (mUsesTextureCube)
413         {
414             out << "float4 gl_textureCube(samplerCUBE s, float3 t)\n"
415                    "{\n"
416                    "    return texCUBElod(s, float4(t.x, -t.y, t.z, 0));\n"
417                    "}\n"
418                    "\n";
419         }
420
421         if (mUsesTextureCubeLod)
422         {
423             out << "float4 gl_textureCubeLod(samplerCUBE s, float3 t, float lod)\n"
424                    "{\n"
425                    "    return texCUBElod(s, float4(t.x, -t.y, t.z, lod));\n"
426                    "}\n"
427                    "\n";
428         }
429     }
430
431     if (mUsesFragCoord)
432     {
433         out << "#define GL_USES_FRAG_COORD\n";
434     }
435
436     if (mUsesPointCoord)
437     {
438         out << "#define GL_USES_POINT_COORD\n";
439     }
440
441     if (mUsesFrontFacing)
442     {
443         out << "#define GL_USES_FRONT_FACING\n";
444     }
445
446     if (mUsesPointSize)
447     {
448         out << "#define GL_USES_POINT_SIZE\n";
449     }
450
451     if (mUsesDepthRange)
452     {
453         out << "struct gl_DepthRangeParameters\n"
454                "{\n"
455                "    float near;\n"
456                "    float far;\n"
457                "    float diff;\n"
458                "};\n"
459                "\n"
460                "uniform float3 dx_DepthRange;"
461                "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n"
462                "\n";
463     }
464
465     if (mUsesXor)
466     {
467         out << "bool xor(bool p, bool q)\n"
468                "{\n"
469                "    return (p || q) && !(p && q);\n"
470                "}\n"
471                "\n";
472     }
473
474     if (mUsesMod1)
475     {
476         out << "float mod(float x, float y)\n"
477                "{\n"
478                "    return x - y * floor(x / y);\n"
479                "}\n"
480                "\n";
481     }
482     
483     if (mUsesMod2)
484     {
485         out << "float2 mod(float2 x, float y)\n"
486                "{\n"
487                "    return x - y * floor(x / y);\n"
488                "}\n"
489                "\n";
490     }
491     
492     if (mUsesMod3)
493     {
494         out << "float3 mod(float3 x, float y)\n"
495                "{\n"
496                "    return x - y * floor(x / y);\n"
497                "}\n"
498                "\n";
499     }
500
501     if (mUsesMod4)
502     {
503         out << "float4 mod(float4 x, float y)\n"
504                "{\n"
505                "    return x - y * floor(x / y);\n"
506                "}\n"
507                "\n";
508     }
509
510     if (mUsesFaceforward1)
511     {
512         out << "float faceforward(float N, float I, float Nref)\n"
513                "{\n"
514                "    if(dot(Nref, I) >= 0)\n"
515                "    {\n"
516                "        return -N;\n"
517                "    }\n"
518                "    else\n"
519                "    {\n"
520                "        return N;\n"
521                "    }\n"
522                "}\n"
523                "\n";
524     }
525
526     if (mUsesFaceforward2)
527     {
528         out << "float2 faceforward(float2 N, float2 I, float2 Nref)\n"
529                "{\n"
530                "    if(dot(Nref, I) >= 0)\n"
531                "    {\n"
532                "        return -N;\n"
533                "    }\n"
534                "    else\n"
535                "    {\n"
536                "        return N;\n"
537                "    }\n"
538                "}\n"
539                "\n";
540     }
541
542     if (mUsesFaceforward3)
543     {
544         out << "float3 faceforward(float3 N, float3 I, float3 Nref)\n"
545                "{\n"
546                "    if(dot(Nref, I) >= 0)\n"
547                "    {\n"
548                "        return -N;\n"
549                "    }\n"
550                "    else\n"
551                "    {\n"
552                "        return N;\n"
553                "    }\n"
554                "}\n"
555                "\n";
556     }
557
558     if (mUsesFaceforward4)
559     {
560         out << "float4 faceforward(float4 N, float4 I, float4 Nref)\n"
561                "{\n"
562                "    if(dot(Nref, I) >= 0)\n"
563                "    {\n"
564                "        return -N;\n"
565                "    }\n"
566                "    else\n"
567                "    {\n"
568                "        return N;\n"
569                "    }\n"
570                "}\n"
571                "\n";
572     }
573
574     if (mUsesEqualMat2)
575     {
576         out << "bool equal(float2x2 m, float2x2 n)\n"
577                "{\n"
578                "    return m[0][0] == n[0][0] && m[0][1] == n[0][1] &&\n"
579                "           m[1][0] == n[1][0] && m[1][1] == n[1][1];\n"
580                "}\n";
581     }
582
583     if (mUsesEqualMat3)
584     {
585         out << "bool equal(float3x3 m, float3x3 n)\n"
586                "{\n"
587                "    return m[0][0] == n[0][0] && m[0][1] == n[0][1] && m[0][2] == n[0][2] &&\n"
588                "           m[1][0] == n[1][0] && m[1][1] == n[1][1] && m[1][2] == n[1][2] &&\n"
589                "           m[2][0] == n[2][0] && m[2][1] == n[2][1] && m[2][2] == n[2][2];\n"
590                "}\n";
591     }
592
593     if (mUsesEqualMat4)
594     {
595         out << "bool equal(float4x4 m, float4x4 n)\n"
596                "{\n"
597                "    return m[0][0] == n[0][0] && m[0][1] == n[0][1] && m[0][2] == n[0][2] && m[0][3] == n[0][3] &&\n"
598                "           m[1][0] == n[1][0] && m[1][1] == n[1][1] && m[1][2] == n[1][2] && m[1][3] == n[1][3] &&\n"
599                "           m[2][0] == n[2][0] && m[2][1] == n[2][1] && m[2][2] == n[2][2] && m[2][3] == n[2][3] &&\n"
600                "           m[3][0] == n[3][0] && m[3][1] == n[3][1] && m[3][2] == n[3][2] && m[3][3] == n[3][3];\n"
601                "}\n";
602     }
603
604     if (mUsesEqualVec2)
605     {
606         out << "bool equal(float2 v, float2 u)\n"
607                "{\n"
608                "    return v.x == u.x && v.y == u.y;\n"
609                "}\n";
610     }
611
612     if (mUsesEqualVec3)
613     {
614         out << "bool equal(float3 v, float3 u)\n"
615                "{\n"
616                "    return v.x == u.x && v.y == u.y && v.z == u.z;\n"
617                "}\n";
618     }
619
620     if (mUsesEqualVec4)
621     {
622         out << "bool equal(float4 v, float4 u)\n"
623                "{\n"
624                "    return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
625                "}\n";
626     }
627
628     if (mUsesEqualIVec2)
629     {
630         out << "bool equal(int2 v, int2 u)\n"
631                "{\n"
632                "    return v.x == u.x && v.y == u.y;\n"
633                "}\n";
634     }
635
636     if (mUsesEqualIVec3)
637     {
638         out << "bool equal(int3 v, int3 u)\n"
639                "{\n"
640                "    return v.x == u.x && v.y == u.y && v.z == u.z;\n"
641                "}\n";
642     }
643
644     if (mUsesEqualIVec4)
645     {
646         out << "bool equal(int4 v, int4 u)\n"
647                "{\n"
648                "    return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
649                "}\n";
650     }
651
652     if (mUsesEqualBVec2)
653     {
654         out << "bool equal(bool2 v, bool2 u)\n"
655                "{\n"
656                "    return v.x == u.x && v.y == u.y;\n"
657                "}\n";
658     }
659
660     if (mUsesEqualBVec3)
661     {
662         out << "bool equal(bool3 v, bool3 u)\n"
663                "{\n"
664                "    return v.x == u.x && v.y == u.y && v.z == u.z;\n"
665                "}\n";
666     }
667
668     if (mUsesEqualBVec4)
669     {
670         out << "bool equal(bool4 v, bool4 u)\n"
671                "{\n"
672                "    return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
673                "}\n";
674     }
675
676     if (mUsesAtan2)
677     {
678         out << "float atanyx(float y, float x)\n"
679                "{\n"
680                "    if(x == 0 && y == 0) x = 1;\n"   // Avoid producing a NaN
681                "    return atan2(y, x);\n"
682                "}\n";
683     }
684 }
685
686 void OutputHLSL::visitSymbol(TIntermSymbol *node)
687 {
688     TInfoSinkBase &out = mBody;
689
690     TString name = node->getSymbol();
691
692     if (name == "gl_FragColor")
693     {
694         out << "gl_Color[0]";
695     }
696     else if (name == "gl_FragData")
697     {
698         out << "gl_Color";
699     }
700     else if (name == "gl_DepthRange")
701     {
702         mUsesDepthRange = true;
703         out << name;
704     }
705     else if (name == "gl_FragCoord")
706     {
707         mUsesFragCoord = true;
708         out << name;
709     }
710     else if (name == "gl_PointCoord")
711     {
712         mUsesPointCoord = true;
713         out << name;
714     }
715     else if (name == "gl_FrontFacing")
716     {
717         mUsesFrontFacing = true;
718         out << name;
719     }
720     else if (name == "gl_PointSize")
721     {
722         mUsesPointSize = true;
723         out << name;
724     }
725     else
726     {
727         TQualifier qualifier = node->getQualifier();
728
729         if (qualifier == EvqUniform)
730         {
731             mReferencedUniforms.insert(name.c_str());
732         }
733         else if (qualifier == EvqAttribute)
734         {
735             mReferencedAttributes.insert(name.c_str());
736         }
737         else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut || qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
738         {
739             mReferencedVaryings.insert(name.c_str());
740         }
741
742         out << decorate(name);
743     }
744 }
745
746 bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
747 {
748     TInfoSinkBase &out = mBody;
749
750     switch (node->getOp())
751     {
752       case EOpAssign:                  outputTriplet(visit, "(", " = ", ")");           break;
753       case EOpInitialize:
754         if (visit == PreVisit)
755         {
756             // GLSL allows to write things like "float x = x;" where a new variable x is defined
757             // and the value of an existing variable x is assigned. HLSL uses C semantics (the
758             // new variable is created before the assignment is evaluated), so we need to convert
759             // this to "float t = x, x = t;".
760
761             TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
762             TIntermTyped *expression = node->getRight();
763
764             sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
765             expression->traverse(&searchSymbol);
766             bool sameSymbol = searchSymbol.foundMatch();
767
768             if (sameSymbol)
769             {
770                 // Type already printed
771                 out << "t" + str(mUniqueIndex) + " = ";
772                 expression->traverse(this);
773                 out << ", ";
774                 symbolNode->traverse(this);
775                 out << " = t" + str(mUniqueIndex);
776
777                 mUniqueIndex++;
778                 return false;
779             }
780         }
781         else if (visit == InVisit)
782         {
783             out << " = ";
784         }
785         break;
786       case EOpAddAssign:               outputTriplet(visit, "(", " += ", ")");          break;
787       case EOpSubAssign:               outputTriplet(visit, "(", " -= ", ")");          break;
788       case EOpMulAssign:               outputTriplet(visit, "(", " *= ", ")");          break;
789       case EOpVectorTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")");          break;
790       case EOpMatrixTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")");          break;
791       case EOpVectorTimesMatrixAssign:
792         if (visit == PreVisit)
793         {
794             out << "(";
795         }
796         else if (visit == InVisit)
797         {
798             out << " = mul(";
799             node->getLeft()->traverse(this);
800             out << ", transpose(";   
801         }
802         else
803         {
804             out << ")))";
805         }
806         break;
807       case EOpMatrixTimesMatrixAssign:
808         if (visit == PreVisit)
809         {
810             out << "(";
811         }
812         else if (visit == InVisit)
813         {
814             out << " = mul(";
815             node->getLeft()->traverse(this);
816             out << ", ";   
817         }
818         else
819         {
820             out << "))";
821         }
822         break;
823       case EOpDivAssign:               outputTriplet(visit, "(", " /= ", ")");          break;
824       case EOpIndexDirect:             outputTriplet(visit, "", "[", "]");              break;
825       case EOpIndexIndirect:           outputTriplet(visit, "", "[", "]");              break;
826       case EOpIndexDirectStruct:
827         if (visit == InVisit)
828         {
829             out << "." + node->getType().getFieldName();
830
831             return false;
832         }
833         break;
834       case EOpVectorSwizzle:
835         if (visit == InVisit)
836         {
837             out << ".";
838
839             TIntermAggregate *swizzle = node->getRight()->getAsAggregate();
840
841             if (swizzle)
842             {
843                 TIntermSequence &sequence = swizzle->getSequence();
844
845                 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
846                 {
847                     TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
848
849                     if (element)
850                     {
851                         int i = element->getUnionArrayPointer()[0].getIConst();
852
853                         switch (i)
854                         {
855                         case 0: out << "x"; break;
856                         case 1: out << "y"; break;
857                         case 2: out << "z"; break;
858                         case 3: out << "w"; break;
859                         default: UNREACHABLE();
860                         }
861                     }
862                     else UNREACHABLE();
863                 }
864             }
865             else UNREACHABLE();
866
867             return false;   // Fully processed
868         }
869         break;
870       case EOpAdd:               outputTriplet(visit, "(", " + ", ")"); break;
871       case EOpSub:               outputTriplet(visit, "(", " - ", ")"); break;
872       case EOpMul:               outputTriplet(visit, "(", " * ", ")"); break;
873       case EOpDiv:               outputTriplet(visit, "(", " / ", ")"); break;
874       case EOpEqual:
875       case EOpNotEqual:
876         if (node->getLeft()->isScalar())
877         {
878             if (node->getOp() == EOpEqual)
879             {
880                 outputTriplet(visit, "(", " == ", ")");
881             }
882             else
883             {
884                 outputTriplet(visit, "(", " != ", ")");
885             }
886         }
887         else if (node->getLeft()->getBasicType() == EbtStruct)
888         {
889             if (node->getOp() == EOpEqual)
890             {
891                 out << "(";
892             }
893             else
894             {
895                 out << "!(";
896             }
897
898             const TTypeList *fields = node->getLeft()->getType().getStruct();
899
900             for (size_t i = 0; i < fields->size(); i++)
901             {
902                 const TType *fieldType = (*fields)[i].type;
903
904                 node->getLeft()->traverse(this);
905                 out << "." + fieldType->getFieldName() + " == ";
906                 node->getRight()->traverse(this);
907                 out << "." + fieldType->getFieldName();
908
909                 if (i < fields->size() - 1)
910                 {
911                     out << " && ";
912                 }
913             }
914
915             out << ")";
916
917             return false;
918         }
919         else
920         {
921             if (node->getLeft()->isMatrix())
922             {
923                 switch (node->getLeft()->getNominalSize())
924                 {
925                   case 2: mUsesEqualMat2 = true; break;
926                   case 3: mUsesEqualMat3 = true; break;
927                   case 4: mUsesEqualMat4 = true; break;
928                   default: UNREACHABLE();
929                 }
930             }
931             else if (node->getLeft()->isVector())
932             {
933                 switch (node->getLeft()->getBasicType())
934                 {
935                   case EbtFloat:
936                     switch (node->getLeft()->getNominalSize())
937                     {
938                       case 2: mUsesEqualVec2 = true; break;
939                       case 3: mUsesEqualVec3 = true; break;
940                       case 4: mUsesEqualVec4 = true; break;
941                       default: UNREACHABLE();
942                     }
943                     break;
944                   case EbtInt:
945                     switch (node->getLeft()->getNominalSize())
946                     {
947                       case 2: mUsesEqualIVec2 = true; break;
948                       case 3: mUsesEqualIVec3 = true; break;
949                       case 4: mUsesEqualIVec4 = true; break;
950                       default: UNREACHABLE();
951                     }
952                     break;
953                   case EbtBool:
954                     switch (node->getLeft()->getNominalSize())
955                     {
956                       case 2: mUsesEqualBVec2 = true; break;
957                       case 3: mUsesEqualBVec3 = true; break;
958                       case 4: mUsesEqualBVec4 = true; break;
959                       default: UNREACHABLE();
960                     }
961                     break;
962                   default: UNREACHABLE();
963                 }
964             }
965             else UNREACHABLE();
966
967             if (node->getOp() == EOpEqual)
968             {
969                 outputTriplet(visit, "equal(", ", ", ")");
970             }
971             else
972             {
973                 outputTriplet(visit, "!equal(", ", ", ")");
974             }
975         }
976         break;
977       case EOpLessThan:          outputTriplet(visit, "(", " < ", ")");   break;
978       case EOpGreaterThan:       outputTriplet(visit, "(", " > ", ")");   break;
979       case EOpLessThanEqual:     outputTriplet(visit, "(", " <= ", ")");  break;
980       case EOpGreaterThanEqual:  outputTriplet(visit, "(", " >= ", ")");  break;
981       case EOpVectorTimesScalar: outputTriplet(visit, "(", " * ", ")");   break;
982       case EOpMatrixTimesScalar: outputTriplet(visit, "(", " * ", ")");   break;
983       case EOpVectorTimesMatrix: outputTriplet(visit, "mul(", ", transpose(", "))"); break;
984       case EOpMatrixTimesVector: outputTriplet(visit, "mul(transpose(", "), ", ")"); break;
985       case EOpMatrixTimesMatrix: outputTriplet(visit, "transpose(mul(transpose(", "), transpose(", ")))"); break;
986       case EOpLogicalOr:         outputTriplet(visit, "(", " || ", ")");  break;
987       case EOpLogicalXor:
988         mUsesXor = true;
989         outputTriplet(visit, "xor(", ", ", ")");
990         break;
991       case EOpLogicalAnd:        outputTriplet(visit, "(", " && ", ")");  break;
992       default: UNREACHABLE();
993     }
994
995     return true;
996 }
997
998 bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
999 {
1000     TInfoSinkBase &out = mBody;
1001
1002     switch (node->getOp())
1003     {
1004       case EOpNegative:         outputTriplet(visit, "(-", "", ")");  break;
1005       case EOpVectorLogicalNot: outputTriplet(visit, "(!", "", ")");  break;
1006       case EOpLogicalNot:       outputTriplet(visit, "(!", "", ")");  break;
1007       case EOpPostIncrement:    outputTriplet(visit, "(", "", "++)"); break;
1008       case EOpPostDecrement:    outputTriplet(visit, "(", "", "--)"); break;
1009       case EOpPreIncrement:     outputTriplet(visit, "(++", "", ")"); break;
1010       case EOpPreDecrement:     outputTriplet(visit, "(--", "", ")"); break;
1011       case EOpConvIntToBool:
1012       case EOpConvFloatToBool:
1013         switch (node->getOperand()->getType().getNominalSize())
1014         {
1015           case 1:    outputTriplet(visit, "bool(", "", ")");  break;
1016           case 2:    outputTriplet(visit, "bool2(", "", ")"); break;
1017           case 3:    outputTriplet(visit, "bool3(", "", ")"); break;
1018           case 4:    outputTriplet(visit, "bool4(", "", ")"); break;
1019           default: UNREACHABLE();
1020         }
1021         break;
1022       case EOpConvBoolToFloat:
1023       case EOpConvIntToFloat:
1024         switch (node->getOperand()->getType().getNominalSize())
1025         {
1026           case 1:    outputTriplet(visit, "float(", "", ")");  break;
1027           case 2:    outputTriplet(visit, "float2(", "", ")"); break;
1028           case 3:    outputTriplet(visit, "float3(", "", ")"); break;
1029           case 4:    outputTriplet(visit, "float4(", "", ")"); break;
1030           default: UNREACHABLE();
1031         }
1032         break;
1033       case EOpConvFloatToInt:
1034       case EOpConvBoolToInt:
1035         switch (node->getOperand()->getType().getNominalSize())
1036         {
1037           case 1:    outputTriplet(visit, "int(", "", ")");  break;
1038           case 2:    outputTriplet(visit, "int2(", "", ")"); break;
1039           case 3:    outputTriplet(visit, "int3(", "", ")"); break;
1040           case 4:    outputTriplet(visit, "int4(", "", ")"); break;
1041           default: UNREACHABLE();
1042         }
1043         break;
1044       case EOpRadians:          outputTriplet(visit, "radians(", "", ")");   break;
1045       case EOpDegrees:          outputTriplet(visit, "degrees(", "", ")");   break;
1046       case EOpSin:              outputTriplet(visit, "sin(", "", ")");       break;
1047       case EOpCos:              outputTriplet(visit, "cos(", "", ")");       break;
1048       case EOpTan:              outputTriplet(visit, "tan(", "", ")");       break;
1049       case EOpAsin:             outputTriplet(visit, "asin(", "", ")");      break;
1050       case EOpAcos:             outputTriplet(visit, "acos(", "", ")");      break;
1051       case EOpAtan:             outputTriplet(visit, "atan(", "", ")");      break;
1052       case EOpExp:              outputTriplet(visit, "exp(", "", ")");       break;
1053       case EOpLog:              outputTriplet(visit, "log(", "", ")");       break;
1054       case EOpExp2:             outputTriplet(visit, "exp2(", "", ")");      break;
1055       case EOpLog2:             outputTriplet(visit, "log2(", "", ")");      break;
1056       case EOpSqrt:             outputTriplet(visit, "sqrt(", "", ")");      break;
1057       case EOpInverseSqrt:      outputTriplet(visit, "rsqrt(", "", ")");     break;
1058       case EOpAbs:              outputTriplet(visit, "abs(", "", ")");       break;
1059       case EOpSign:             outputTriplet(visit, "sign(", "", ")");      break;
1060       case EOpFloor:            outputTriplet(visit, "floor(", "", ")");     break;
1061       case EOpCeil:             outputTriplet(visit, "ceil(", "", ")");      break;
1062       case EOpFract:            outputTriplet(visit, "frac(", "", ")");      break;
1063       case EOpLength:           outputTriplet(visit, "length(", "", ")");    break;
1064       case EOpNormalize:        outputTriplet(visit, "normalize(", "", ")"); break;
1065       case EOpDFdx:             outputTriplet(visit, "ddx(", "", ")");       break;
1066       case EOpDFdy:             outputTriplet(visit, "(-ddy(", "", "))");    break;
1067       case EOpFwidth:           outputTriplet(visit, "fwidth(", "", ")");    break;        
1068       case EOpAny:              outputTriplet(visit, "any(", "", ")");       break;
1069       case EOpAll:              outputTriplet(visit, "all(", "", ")");       break;
1070       default: UNREACHABLE();
1071     }
1072
1073     return true;
1074 }
1075
1076 bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
1077 {
1078     ShShaderType shaderType = mContext.shaderType;
1079     TInfoSinkBase &out = mBody;
1080
1081     switch (node->getOp())
1082     {
1083       case EOpSequence:
1084         {
1085             if (mInsideFunction)
1086             {
1087                 outputLineDirective(node->getLine());
1088                 out << "{\n";
1089
1090                 mScopeDepth++;
1091
1092                 if (mScopeBracket.size() < mScopeDepth)
1093                 {
1094                     mScopeBracket.push_back(0);   // New scope level
1095                 }
1096                 else
1097                 {
1098                     mScopeBracket[mScopeDepth - 1]++;   // New scope at existing level
1099                 }
1100             }
1101
1102             for (TIntermSequence::iterator sit = node->getSequence().begin(); sit != node->getSequence().end(); sit++)
1103             {
1104                 outputLineDirective((*sit)->getLine());
1105
1106                 if (isSingleStatement(*sit))
1107                 {
1108                     mUnfoldSelect->traverse(*sit);
1109                 }
1110
1111                 (*sit)->traverse(this);
1112
1113                 out << ";\n";
1114             }
1115
1116             if (mInsideFunction)
1117             {
1118                 outputLineDirective(node->getEndLine());
1119                 out << "}\n";
1120
1121                 mScopeDepth--;
1122             }
1123
1124             return false;
1125         }
1126       case EOpDeclaration:
1127         if (visit == PreVisit)
1128         {
1129             TIntermSequence &sequence = node->getSequence();
1130             TIntermTyped *variable = sequence[0]->getAsTyped();
1131             bool visit = true;
1132
1133             if (variable && (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal))
1134             {
1135                 if (variable->getType().getStruct())
1136                 {
1137                     addConstructor(variable->getType(), scopedStruct(variable->getType().getTypeName()), NULL);
1138                 }
1139
1140                 if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "")   // Variable declaration
1141                 {
1142                     if (!mInsideFunction)
1143                     {
1144                         out << "static ";
1145                     }
1146
1147                     out << typeString(variable->getType()) + " ";
1148
1149                     for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
1150                     {
1151                         TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
1152
1153                         if (symbol)
1154                         {
1155                             symbol->traverse(this);
1156                             out << arrayString(symbol->getType());
1157                             out << " = " + initializer(variable->getType());
1158                         }
1159                         else
1160                         {
1161                             (*sit)->traverse(this);
1162                         }
1163
1164                         if (visit && this->inVisit)
1165                         {
1166                             if (*sit != sequence.back())
1167                             {
1168                                 visit = this->visitAggregate(InVisit, node);
1169                             }
1170                         }
1171                     }
1172
1173                     if (visit && this->postVisit)
1174                     {
1175                         this->visitAggregate(PostVisit, node);
1176                     }
1177                 }
1178                 else if (variable->getAsSymbolNode() && variable->getAsSymbolNode()->getSymbol() == "")   // Type (struct) declaration
1179                 {
1180                     // Already added to constructor map
1181                 }
1182                 else UNREACHABLE();
1183             }
1184             
1185             return false;
1186         }
1187         else if (visit == InVisit)
1188         {
1189             out << ", ";
1190         }
1191         break;
1192       case EOpPrototype:
1193         if (visit == PreVisit)
1194         {
1195             out << typeString(node->getType()) << " " << decorate(node->getName()) << "(";
1196
1197             TIntermSequence &arguments = node->getSequence();
1198
1199             for (unsigned int i = 0; i < arguments.size(); i++)
1200             {
1201                 TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
1202
1203                 if (symbol)
1204                 {
1205                     out << argumentString(symbol);
1206
1207                     if (i < arguments.size() - 1)
1208                     {
1209                         out << ", ";
1210                     }
1211                 }
1212                 else UNREACHABLE();
1213             }
1214
1215             out << ");\n";
1216
1217             return false;
1218         }
1219         break;
1220       case EOpComma:            outputTriplet(visit, "", ", ", "");                break;
1221       case EOpFunction:
1222         {
1223             TString name = TFunction::unmangleName(node->getName());
1224
1225             if (visit == PreVisit)
1226             {
1227                 out << typeString(node->getType()) << " ";
1228
1229                 if (name == "main")
1230                 {
1231                     out << "gl_main(";
1232                 }
1233                 else
1234                 {
1235                     out << decorate(name) << "(";
1236                 }
1237
1238                 TIntermSequence &sequence = node->getSequence();
1239                 TIntermSequence &arguments = sequence[0]->getAsAggregate()->getSequence();
1240
1241                 for (unsigned int i = 0; i < arguments.size(); i++)
1242                 {
1243                     TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
1244
1245                     if (symbol)
1246                     {
1247                         out << argumentString(symbol);
1248
1249                         if (i < arguments.size() - 1)
1250                         {
1251                             out << ", ";
1252                         }
1253                     }
1254                     else UNREACHABLE();
1255                 }
1256
1257                 sequence.erase(sequence.begin());
1258
1259                 out << ")\n";
1260                 
1261                 outputLineDirective(node->getLine());
1262                 out << "{\n";
1263                 
1264                 mInsideFunction = true;
1265             }
1266             else if (visit == PostVisit)
1267             {
1268                 outputLineDirective(node->getEndLine());
1269                 out << "}\n";
1270
1271                 mInsideFunction = false;
1272             }
1273         }
1274         break;
1275       case EOpFunctionCall:
1276         {
1277             if (visit == PreVisit)
1278             {
1279                 TString name = TFunction::unmangleName(node->getName());
1280
1281                 if (node->isUserDefined())
1282                 {
1283                     out << decorate(name) << "(";
1284                 }
1285                 else
1286                 {
1287                     if (name == "texture2D")
1288                     {
1289                         if (node->getSequence().size() == 2)
1290                         {
1291                             mUsesTexture2D = true;
1292                         }
1293                         else if (node->getSequence().size() == 3)
1294                         {
1295                             mUsesTexture2D_bias = true;
1296                         }
1297                         else UNREACHABLE();
1298
1299                         out << "gl_texture2D(";
1300                     }
1301                     else if (name == "texture2DProj")
1302                     {
1303                         if (node->getSequence().size() == 2)
1304                         {
1305                             mUsesTexture2DProj = true;
1306                         }
1307                         else if (node->getSequence().size() == 3)
1308                         {
1309                             mUsesTexture2DProj_bias = true;
1310                         }
1311                         else UNREACHABLE();
1312
1313                         out << "gl_texture2DProj(";
1314                     }
1315                     else if (name == "textureCube")
1316                     {
1317                         if (node->getSequence().size() == 2)
1318                         {
1319                             mUsesTextureCube = true;
1320                         }
1321                         else if (node->getSequence().size() == 3)
1322                         {
1323                             mUsesTextureCube_bias = true;
1324                         }
1325                         else UNREACHABLE();
1326
1327                         out << "gl_textureCube(";
1328                     }
1329                     else if (name == "texture2DLod")
1330                     {
1331                         if (node->getSequence().size() == 3)
1332                         {
1333                             mUsesTexture2DLod = true;
1334                         }
1335                         else UNREACHABLE();
1336
1337                         out << "gl_texture2DLod(";
1338                     }
1339                     else if (name == "texture2DProjLod")
1340                     {
1341                         if (node->getSequence().size() == 3)
1342                         {
1343                             mUsesTexture2DProjLod = true;
1344                         }
1345                         else UNREACHABLE();
1346
1347                         out << "gl_texture2DProjLod(";
1348                     }
1349                     else if (name == "textureCubeLod")
1350                     {
1351                         if (node->getSequence().size() == 3)
1352                         {
1353                             mUsesTextureCubeLod = true;
1354                         }
1355                         else UNREACHABLE();
1356
1357                         out << "gl_textureCubeLod(";
1358                     }
1359                     else UNREACHABLE();
1360                 }
1361             }
1362             else if (visit == InVisit)
1363             {
1364                 out << ", ";
1365             }
1366             else
1367             {
1368                 out << ")";
1369             }
1370         }
1371         break;
1372       case EOpParameters:       outputTriplet(visit, "(", ", ", ")\n{\n");             break;
1373       case EOpConstructFloat:
1374         addConstructor(node->getType(), "vec1", &node->getSequence());
1375         outputTriplet(visit, "vec1(", "", ")");
1376         break;
1377       case EOpConstructVec2:
1378         addConstructor(node->getType(), "vec2", &node->getSequence());
1379         outputTriplet(visit, "vec2(", ", ", ")");
1380         break;
1381       case EOpConstructVec3:
1382         addConstructor(node->getType(), "vec3", &node->getSequence());
1383         outputTriplet(visit, "vec3(", ", ", ")");
1384         break;
1385       case EOpConstructVec4:
1386         addConstructor(node->getType(), "vec4", &node->getSequence());
1387         outputTriplet(visit, "vec4(", ", ", ")");
1388         break;
1389       case EOpConstructBool:
1390         addConstructor(node->getType(), "bvec1", &node->getSequence());
1391         outputTriplet(visit, "bvec1(", "", ")");
1392         break;
1393       case EOpConstructBVec2:
1394         addConstructor(node->getType(), "bvec2", &node->getSequence());
1395         outputTriplet(visit, "bvec2(", ", ", ")");
1396         break;
1397       case EOpConstructBVec3:
1398         addConstructor(node->getType(), "bvec3", &node->getSequence());
1399         outputTriplet(visit, "bvec3(", ", ", ")");
1400         break;
1401       case EOpConstructBVec4:
1402         addConstructor(node->getType(), "bvec4", &node->getSequence());
1403         outputTriplet(visit, "bvec4(", ", ", ")");
1404         break;
1405       case EOpConstructInt:
1406         addConstructor(node->getType(), "ivec1", &node->getSequence());
1407         outputTriplet(visit, "ivec1(", "", ")");
1408         break;
1409       case EOpConstructIVec2:
1410         addConstructor(node->getType(), "ivec2", &node->getSequence());
1411         outputTriplet(visit, "ivec2(", ", ", ")");
1412         break;
1413       case EOpConstructIVec3:
1414         addConstructor(node->getType(), "ivec3", &node->getSequence());
1415         outputTriplet(visit, "ivec3(", ", ", ")");
1416         break;
1417       case EOpConstructIVec4:
1418         addConstructor(node->getType(), "ivec4", &node->getSequence());
1419         outputTriplet(visit, "ivec4(", ", ", ")");
1420         break;
1421       case EOpConstructMat2:
1422         addConstructor(node->getType(), "mat2", &node->getSequence());
1423         outputTriplet(visit, "mat2(", ", ", ")");
1424         break;
1425       case EOpConstructMat3:
1426         addConstructor(node->getType(), "mat3", &node->getSequence());
1427         outputTriplet(visit, "mat3(", ", ", ")");
1428         break;
1429       case EOpConstructMat4: 
1430         addConstructor(node->getType(), "mat4", &node->getSequence());
1431         outputTriplet(visit, "mat4(", ", ", ")");
1432         break;
1433       case EOpConstructStruct:
1434         addConstructor(node->getType(), scopedStruct(node->getType().getTypeName()), &node->getSequence());
1435         outputTriplet(visit, structLookup(node->getType().getTypeName()) + "_ctor(", ", ", ")");
1436         break;
1437       case EOpLessThan:         outputTriplet(visit, "(", " < ", ")");                 break;
1438       case EOpGreaterThan:      outputTriplet(visit, "(", " > ", ")");                 break;
1439       case EOpLessThanEqual:    outputTriplet(visit, "(", " <= ", ")");                break;
1440       case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")");                break;
1441       case EOpVectorEqual:      outputTriplet(visit, "(", " == ", ")");                break;
1442       case EOpVectorNotEqual:   outputTriplet(visit, "(", " != ", ")");                break;
1443       case EOpMod:
1444         {
1445             switch (node->getSequence()[0]->getAsTyped()->getNominalSize())   // Number of components in the first argument
1446             {
1447               case 1: mUsesMod1 = true; break;
1448               case 2: mUsesMod2 = true; break;
1449               case 3: mUsesMod3 = true; break;
1450               case 4: mUsesMod4 = true; break;
1451               default: UNREACHABLE();
1452             }
1453
1454             outputTriplet(visit, "mod(", ", ", ")");
1455         }
1456         break;
1457       case EOpPow:              outputTriplet(visit, "pow(", ", ", ")");               break;
1458       case EOpAtan:
1459         ASSERT(node->getSequence().size() == 2);   // atan(x) is a unary operator
1460         mUsesAtan2 = true;
1461         outputTriplet(visit, "atanyx(", ", ", ")");
1462         break;
1463       case EOpMin:           outputTriplet(visit, "min(", ", ", ")");           break;
1464       case EOpMax:           outputTriplet(visit, "max(", ", ", ")");           break;
1465       case EOpClamp:         outputTriplet(visit, "clamp(", ", ", ")");         break;
1466       case EOpMix:           outputTriplet(visit, "lerp(", ", ", ")");          break;
1467       case EOpStep:          outputTriplet(visit, "step(", ", ", ")");          break;
1468       case EOpSmoothStep:    outputTriplet(visit, "smoothstep(", ", ", ")");    break;
1469       case EOpDistance:      outputTriplet(visit, "distance(", ", ", ")");      break;
1470       case EOpDot:           outputTriplet(visit, "dot(", ", ", ")");           break;
1471       case EOpCross:         outputTriplet(visit, "cross(", ", ", ")");         break;
1472       case EOpFaceForward:
1473         {
1474             switch (node->getSequence()[0]->getAsTyped()->getNominalSize())   // Number of components in the first argument
1475             {
1476             case 1: mUsesFaceforward1 = true; break;
1477             case 2: mUsesFaceforward2 = true; break;
1478             case 3: mUsesFaceforward3 = true; break;
1479             case 4: mUsesFaceforward4 = true; break;
1480             default: UNREACHABLE();
1481             }
1482             
1483             outputTriplet(visit, "faceforward(", ", ", ")");
1484         }
1485         break;
1486       case EOpReflect:       outputTriplet(visit, "reflect(", ", ", ")");       break;
1487       case EOpRefract:       outputTriplet(visit, "refract(", ", ", ")");       break;
1488       case EOpMul:           outputTriplet(visit, "(", " * ", ")");             break;
1489       default: UNREACHABLE();
1490     }
1491
1492     return true;
1493 }
1494
1495 bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
1496 {
1497     TInfoSinkBase &out = mBody;
1498
1499     if (node->usesTernaryOperator())
1500     {
1501         out << "t" << mUnfoldSelect->getTemporaryIndex();
1502     }
1503     else  // if/else statement
1504     {
1505         mUnfoldSelect->traverse(node->getCondition());
1506
1507         out << "if(";
1508
1509         node->getCondition()->traverse(this);
1510
1511         out << ")\n";
1512         
1513         outputLineDirective(node->getLine());
1514         out << "{\n";
1515
1516         if (node->getTrueBlock())
1517         {
1518             node->getTrueBlock()->traverse(this);
1519         }
1520
1521         outputLineDirective(node->getLine());
1522         out << ";}\n";
1523
1524         if (node->getFalseBlock())
1525         {
1526             out << "else\n";
1527
1528             outputLineDirective(node->getFalseBlock()->getLine());
1529             out << "{\n";
1530
1531             outputLineDirective(node->getFalseBlock()->getLine());
1532             node->getFalseBlock()->traverse(this);
1533
1534             outputLineDirective(node->getFalseBlock()->getLine());
1535             out << ";}\n";
1536         }
1537     }
1538
1539     return false;
1540 }
1541
1542 void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
1543 {
1544     writeConstantUnion(node->getType(), node->getUnionArrayPointer());
1545 }
1546
1547 bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
1548 {
1549     if (handleExcessiveLoop(node))
1550     {
1551         return false;
1552     }
1553
1554     TInfoSinkBase &out = mBody;
1555
1556     if (node->getType() == ELoopDoWhile)
1557     {
1558         out << "do\n";
1559
1560         outputLineDirective(node->getLine());
1561         out << "{\n";
1562     }
1563     else
1564     {
1565         if (node->getInit())
1566         {
1567             mUnfoldSelect->traverse(node->getInit());
1568         }
1569         
1570         if (node->getCondition())
1571         {
1572             mUnfoldSelect->traverse(node->getCondition());
1573         }
1574         
1575         if (node->getExpression())
1576         {
1577             mUnfoldSelect->traverse(node->getExpression());
1578         }
1579
1580         out << "for(";
1581         
1582         if (node->getInit())
1583         {
1584             node->getInit()->traverse(this);
1585         }
1586
1587         out << "; ";
1588
1589         if (node->getCondition())
1590         {
1591             node->getCondition()->traverse(this);
1592         }
1593
1594         out << "; ";
1595
1596         if (node->getExpression())
1597         {
1598             node->getExpression()->traverse(this);
1599         }
1600
1601         out << ")\n";
1602         
1603         outputLineDirective(node->getLine());
1604         out << "{\n";
1605     }
1606
1607     if (node->getBody())
1608     {
1609         node->getBody()->traverse(this);
1610     }
1611
1612     outputLineDirective(node->getLine());
1613     out << "}\n";
1614
1615     if (node->getType() == ELoopDoWhile)
1616     {
1617         outputLineDirective(node->getCondition()->getLine());
1618         out << "while(\n";
1619
1620         node->getCondition()->traverse(this);
1621
1622         out << ")";
1623     }
1624
1625     out << ";\n";
1626
1627     return false;
1628 }
1629
1630 bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
1631 {
1632     TInfoSinkBase &out = mBody;
1633
1634     switch (node->getFlowOp())
1635     {
1636       case EOpKill:     outputTriplet(visit, "discard;\n", "", "");  break;
1637       case EOpBreak:    outputTriplet(visit, "break;\n", "", "");    break;
1638       case EOpContinue: outputTriplet(visit, "continue;\n", "", ""); break;
1639       case EOpReturn:
1640         if (visit == PreVisit)
1641         {
1642             if (node->getExpression())
1643             {
1644                 out << "return ";
1645             }
1646             else
1647             {
1648                 out << "return;\n";
1649             }
1650         }
1651         else if (visit == PostVisit)
1652         {
1653             if (node->getExpression())
1654             {
1655                 out << ";\n";
1656             }
1657         }
1658         break;
1659       default: UNREACHABLE();
1660     }
1661
1662     return true;
1663 }
1664
1665 bool OutputHLSL::isSingleStatement(TIntermNode *node)
1666 {
1667     TIntermAggregate *aggregate = node->getAsAggregate();
1668
1669     if (aggregate)
1670     {
1671         if (aggregate->getOp() == EOpSequence)
1672         {
1673             return false;
1674         }
1675         else
1676         {
1677             for (TIntermSequence::iterator sit = aggregate->getSequence().begin(); sit != aggregate->getSequence().end(); sit++)
1678             {
1679                 if (!isSingleStatement(*sit))
1680                 {
1681                     return false;
1682                 }
1683             }
1684
1685             return true;
1686         }
1687     }
1688
1689     return true;
1690 }
1691
1692 // Handle loops with more than 255 iterations (unsupported by D3D9) by splitting them
1693 bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
1694 {
1695     TInfoSinkBase &out = mBody;
1696
1697     // Parse loops of the form:
1698     // for(int index = initial; index [comparator] limit; index += increment)
1699     TIntermSymbol *index = NULL;
1700     TOperator comparator = EOpNull;
1701     int initial = 0;
1702     int limit = 0;
1703     int increment = 0;
1704
1705     // Parse index name and intial value
1706     if (node->getInit())
1707     {
1708         TIntermAggregate *init = node->getInit()->getAsAggregate();
1709
1710         if (init)
1711         {
1712             TIntermSequence &sequence = init->getSequence();
1713             TIntermTyped *variable = sequence[0]->getAsTyped();
1714
1715             if (variable && variable->getQualifier() == EvqTemporary)
1716             {
1717                 TIntermBinary *assign = variable->getAsBinaryNode();
1718
1719                 if (assign->getOp() == EOpInitialize)
1720                 {
1721                     TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
1722                     TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
1723
1724                     if (symbol && constant)
1725                     {
1726                         if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
1727                         {
1728                             index = symbol;
1729                             initial = constant->getUnionArrayPointer()[0].getIConst();
1730                         }
1731                     }
1732                 }
1733             }
1734         }
1735     }
1736
1737     // Parse comparator and limit value
1738     if (index != NULL && node->getCondition())
1739     {
1740         TIntermBinary *test = node->getCondition()->getAsBinaryNode();
1741         
1742         if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
1743         {
1744             TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
1745
1746             if (constant)
1747             {
1748                 if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
1749                 {
1750                     comparator = test->getOp();
1751                     limit = constant->getUnionArrayPointer()[0].getIConst();
1752                 }
1753             }
1754         }
1755     }
1756
1757     // Parse increment
1758     if (index != NULL && comparator != EOpNull && node->getExpression())
1759     {
1760         TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
1761         TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
1762         
1763         if (binaryTerminal)
1764         {
1765             TOperator op = binaryTerminal->getOp();
1766             TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
1767
1768             if (constant)
1769             {
1770                 if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
1771                 {
1772                     int value = constant->getUnionArrayPointer()[0].getIConst();
1773
1774                     switch (op)
1775                     {
1776                       case EOpAddAssign: increment = value;  break;
1777                       case EOpSubAssign: increment = -value; break;
1778                       default: UNIMPLEMENTED();
1779                     }
1780                 }
1781             }
1782         }
1783         else if (unaryTerminal)
1784         {
1785             TOperator op = unaryTerminal->getOp();
1786
1787             switch (op)
1788             {
1789               case EOpPostIncrement: increment = 1;  break;
1790               case EOpPostDecrement: increment = -1; break;
1791               case EOpPreIncrement:  increment = 1;  break;
1792               case EOpPreDecrement:  increment = -1; break;
1793               default: UNIMPLEMENTED();
1794             }
1795         }
1796     }
1797
1798     if (index != NULL && comparator != EOpNull && increment != 0)
1799     {
1800         if (comparator == EOpLessThanEqual)
1801         {
1802             comparator = EOpLessThan;
1803             limit += 1;
1804         }
1805
1806         if (comparator == EOpLessThan)
1807         {
1808             int iterations = (limit - initial) / increment;
1809
1810             if (iterations <= 255)
1811             {
1812                 return false;   // Not an excessive loop
1813             }
1814
1815             while (iterations > 0)
1816             {
1817                 int remainder = (limit - initial) % increment;
1818                 int clampedLimit = initial + increment * std::min(255, iterations);
1819
1820                 // for(int index = initial; index < clampedLimit; index += increment)
1821
1822                 out << "for(int ";
1823                 index->traverse(this);
1824                 out << " = ";
1825                 out << initial;
1826
1827                 out << "; ";
1828                 index->traverse(this);
1829                 out << " < ";
1830                 out << clampedLimit;
1831
1832                 out << "; ";
1833                 index->traverse(this);
1834                 out << " += ";
1835                 out << increment;
1836                 out << ")\n";
1837                 
1838                 outputLineDirective(node->getLine());
1839                 out << "{\n";
1840
1841                 if (node->getBody())
1842                 {
1843                     node->getBody()->traverse(this);
1844                 }
1845
1846                 outputLineDirective(node->getLine());
1847                 out << "}\n";
1848
1849                 initial += 255 * increment;
1850                 iterations -= 255;
1851             }
1852
1853             return true;
1854         }
1855         else UNIMPLEMENTED();
1856     }
1857
1858     return false;   // Not handled as an excessive loop
1859 }
1860
1861 void OutputHLSL::outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString)
1862 {
1863     TInfoSinkBase &out = mBody;
1864
1865     if (visit == PreVisit)
1866     {
1867         out << preString;
1868     }
1869     else if (visit == InVisit)
1870     {
1871         out << inString;
1872     }
1873     else if (visit == PostVisit)
1874     {
1875         out << postString;
1876     }
1877 }
1878
1879 void OutputHLSL::outputLineDirective(int line)
1880 {
1881     if ((mContext.compileOptions & SH_LINE_DIRECTIVES) && (line > 0))
1882     {
1883         mBody << "\n";
1884         mBody << "#line " << line;
1885
1886         if (mContext.sourcePath)
1887         {
1888             mBody << " \"" << mContext.sourcePath << "\"";
1889         }
1890         
1891         mBody << "\n";
1892     }
1893 }
1894
1895 TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
1896 {
1897     TQualifier qualifier = symbol->getQualifier();
1898     const TType &type = symbol->getType();
1899     TString name = symbol->getSymbol();
1900
1901     if (name.empty())   // HLSL demands named arguments, also for prototypes
1902     {
1903         name = "x" + str(mUniqueIndex++);
1904     }
1905     else
1906     {
1907         name = decorate(name);
1908     }
1909
1910     return qualifierString(qualifier) + " " + typeString(type) + " " + name + arrayString(type);
1911 }
1912
1913 TString OutputHLSL::qualifierString(TQualifier qualifier)
1914 {
1915     switch(qualifier)
1916     {
1917       case EvqIn:            return "in";
1918       case EvqOut:           return "out";
1919       case EvqInOut:         return "inout";
1920       case EvqConstReadOnly: return "const";
1921       default: UNREACHABLE();
1922     }
1923
1924     return "";
1925 }
1926
1927 TString OutputHLSL::typeString(const TType &type)
1928 {
1929     if (type.getBasicType() == EbtStruct)
1930     {
1931         if (type.getTypeName() != "")
1932         {
1933             return structLookup(type.getTypeName());
1934         }
1935         else   // Nameless structure, define in place
1936         {
1937             const TTypeList &fields = *type.getStruct();
1938
1939             TString string = "struct\n"
1940                              "{\n";
1941
1942             for (unsigned int i = 0; i < fields.size(); i++)
1943             {
1944                 const TType &field = *fields[i].type;
1945
1946                 string += "    " + typeString(field) + " " + field.getFieldName() + arrayString(field) + ";\n";
1947             }
1948
1949             string += "} ";
1950
1951             return string;
1952         }
1953     }
1954     else if (type.isMatrix())
1955     {
1956         switch (type.getNominalSize())
1957         {
1958           case 2: return "float2x2";
1959           case 3: return "float3x3";
1960           case 4: return "float4x4";
1961         }
1962     }
1963     else
1964     {
1965         switch (type.getBasicType())
1966         {
1967           case EbtFloat:
1968             switch (type.getNominalSize())
1969             {
1970               case 1: return "float";
1971               case 2: return "float2";
1972               case 3: return "float3";
1973               case 4: return "float4";
1974             }
1975           case EbtInt:
1976             switch (type.getNominalSize())
1977             {
1978               case 1: return "int";
1979               case 2: return "int2";
1980               case 3: return "int3";
1981               case 4: return "int4";
1982             }
1983           case EbtBool:
1984             switch (type.getNominalSize())
1985             {
1986               case 1: return "bool";
1987               case 2: return "bool2";
1988               case 3: return "bool3";
1989               case 4: return "bool4";
1990             }
1991           case EbtVoid:
1992             return "void";
1993           case EbtSampler2D:
1994             return "sampler2D";
1995           case EbtSamplerCube:
1996             return "samplerCUBE";
1997         }
1998     }
1999
2000     UNIMPLEMENTED();   // FIXME
2001     return "<unknown type>";
2002 }
2003
2004 TString OutputHLSL::arrayString(const TType &type)
2005 {
2006     if (!type.isArray())
2007     {
2008         return "";
2009     }
2010
2011     return "[" + str(type.getArraySize()) + "]";
2012 }
2013
2014 TString OutputHLSL::initializer(const TType &type)
2015 {
2016     TString string;
2017
2018     for (int component = 0; component < type.getObjectSize(); component++)
2019     {
2020         string += "0";
2021
2022         if (component < type.getObjectSize() - 1)
2023         {
2024             string += ", ";
2025         }
2026     }
2027
2028     return "{" + string + "}";
2029 }
2030
2031 void OutputHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters)
2032 {
2033     if (name == "")
2034     {
2035         return;   // Nameless structures don't have constructors
2036     }
2037
2038     TType ctorType = type;
2039     ctorType.clearArrayness();
2040     ctorType.setPrecision(EbpHigh);
2041     ctorType.setQualifier(EvqTemporary);
2042
2043     TString ctorName = type.getStruct() ? decorate(name) : name;
2044
2045     typedef std::vector<TType> ParameterArray;
2046     ParameterArray ctorParameters;
2047
2048     if (parameters)
2049     {
2050         for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++)
2051         {
2052             ctorParameters.push_back((*parameter)->getAsTyped()->getType());
2053         }
2054     }
2055     else if (type.getStruct())
2056     {
2057         mStructNames.insert(decorate(name));
2058
2059         TString structure;
2060         structure += "struct " + decorate(name) + "\n"
2061                      "{\n";
2062
2063         const TTypeList &fields = *type.getStruct();
2064
2065         for (unsigned int i = 0; i < fields.size(); i++)
2066         {
2067             const TType &field = *fields[i].type;
2068
2069             structure += "    " + typeString(field) + " " + field.getFieldName() + arrayString(field) + ";\n";
2070         }
2071
2072         structure += "};\n";
2073
2074         if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structure) == mStructDeclarations.end())
2075         {
2076             mStructDeclarations.push_back(structure);
2077         }
2078
2079         for (unsigned int i = 0; i < fields.size(); i++)
2080         {
2081             ctorParameters.push_back(*fields[i].type);
2082         }
2083     }
2084     else UNREACHABLE();
2085
2086     TString constructor;
2087
2088     if (ctorType.getStruct())
2089     {
2090         constructor += ctorName + " " + ctorName + "_ctor(";
2091     }
2092     else   // Built-in type
2093     {
2094         constructor += typeString(ctorType) + " " + ctorName + "(";
2095     }
2096
2097     for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++)
2098     {
2099         const TType &type = ctorParameters[parameter];
2100
2101         constructor += typeString(type) + " x" + str(parameter) + arrayString(type);
2102
2103         if (parameter < ctorParameters.size() - 1)
2104         {
2105             constructor += ", ";
2106         }
2107     }
2108
2109     constructor += ")\n"
2110                    "{\n";
2111
2112     if (ctorType.getStruct())
2113     {
2114         constructor += "    " + ctorName + " structure = {";
2115     }
2116     else
2117     {
2118         constructor += "    return " + typeString(ctorType) + "(";
2119     }
2120
2121     if (ctorType.isMatrix() && ctorParameters.size() == 1)
2122     {
2123         int dim = ctorType.getNominalSize();
2124         const TType &parameter = ctorParameters[0];
2125
2126         if (parameter.isScalar())
2127         {
2128             for (int row = 0; row < dim; row++)
2129             {
2130                 for (int col = 0; col < dim; col++)
2131                 {
2132                     constructor += TString((row == col) ? "x0" : "0.0");
2133                     
2134                     if (row < dim - 1 || col < dim - 1)
2135                     {
2136                         constructor += ", ";
2137                     }
2138                 }
2139             }
2140         }
2141         else if (parameter.isMatrix())
2142         {
2143             for (int row = 0; row < dim; row++)
2144             {
2145                 for (int col = 0; col < dim; col++)
2146                 {
2147                     if (row < parameter.getNominalSize() && col < parameter.getNominalSize())
2148                     {
2149                         constructor += TString("x0") + "[" + str(row) + "]" + "[" + str(col) + "]";
2150                     }
2151                     else
2152                     {
2153                         constructor += TString((row == col) ? "1.0" : "0.0");
2154                     }
2155
2156                     if (row < dim - 1 || col < dim - 1)
2157                     {
2158                         constructor += ", ";
2159                     }
2160                 }
2161             }
2162         }
2163         else UNREACHABLE();
2164     }
2165     else
2166     {
2167         int remainingComponents = ctorType.getObjectSize();
2168         int parameterIndex = 0;
2169
2170         while (remainingComponents > 0)
2171         {
2172             const TType &parameter = ctorParameters[parameterIndex];
2173             bool moreParameters = parameterIndex < (int)ctorParameters.size() - 1;
2174
2175             constructor += "x" + str(parameterIndex);
2176
2177             if (parameter.isScalar())
2178             {
2179                 remainingComponents -= parameter.getObjectSize();
2180             }
2181             else if (parameter.isVector())
2182             {
2183                 if (remainingComponents == parameter.getObjectSize() || moreParameters)
2184                 {
2185                     remainingComponents -= parameter.getObjectSize();
2186                 }
2187                 else if (remainingComponents < parameter.getNominalSize())
2188                 {
2189                     switch (remainingComponents)
2190                     {
2191                       case 1: constructor += ".x";    break;
2192                       case 2: constructor += ".xy";   break;
2193                       case 3: constructor += ".xyz";  break;
2194                       case 4: constructor += ".xyzw"; break;
2195                       default: UNREACHABLE();
2196                     }
2197
2198                     remainingComponents = 0;
2199                 }
2200                 else UNREACHABLE();
2201             }
2202             else if (parameter.isMatrix() || parameter.getStruct())
2203             {
2204                 ASSERT(remainingComponents == parameter.getObjectSize() || moreParameters);
2205                 
2206                 remainingComponents -= parameter.getObjectSize();
2207             }
2208             else UNREACHABLE();
2209
2210             if (moreParameters)
2211             {
2212                 parameterIndex++;
2213             }
2214
2215             if (remainingComponents)
2216             {
2217                 constructor += ", ";
2218             }
2219         }
2220     }
2221
2222     if (ctorType.getStruct())
2223     {
2224         constructor += "};\n"
2225                        "    return structure;\n"
2226                        "}\n";
2227     }
2228     else
2229     {
2230         constructor += ");\n"
2231                        "}\n";
2232     }
2233
2234     mConstructors.insert(constructor);
2235 }
2236
2237 const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const ConstantUnion *constUnion)
2238 {
2239     TInfoSinkBase &out = mBody;
2240
2241     if (type.getBasicType() == EbtStruct)
2242     {
2243         out << structLookup(type.getTypeName()) + "_ctor(";
2244         
2245         const TTypeList *structure = type.getStruct();
2246
2247         for (size_t i = 0; i < structure->size(); i++)
2248         {
2249             const TType *fieldType = (*structure)[i].type;
2250
2251             constUnion = writeConstantUnion(*fieldType, constUnion);
2252
2253             if (i != structure->size() - 1)
2254             {
2255                 out << ", ";
2256             }
2257         }
2258
2259         out << ")";
2260     }
2261     else
2262     {
2263         int size = type.getObjectSize();
2264         bool writeType = size > 1;
2265         
2266         if (writeType)
2267         {
2268             out << typeString(type) << "(";
2269         }
2270
2271         for (int i = 0; i < size; i++, constUnion++)
2272         {
2273             switch (constUnion->getType())
2274             {
2275               case EbtFloat: out << constUnion->getFConst(); break;
2276               case EbtInt:   out << constUnion->getIConst(); break;
2277               case EbtBool:  out << constUnion->getBConst(); break;
2278               default: UNREACHABLE();
2279             }
2280
2281             if (i != size - 1)
2282             {
2283                 out << ", ";
2284             }
2285         }
2286
2287         if (writeType)
2288         {
2289             out << ")";
2290         }
2291     }
2292
2293     return constUnion;
2294 }
2295
2296 TString OutputHLSL::scopeString(unsigned int depthLimit)
2297 {
2298     TString string;
2299
2300     for (unsigned int i = 0; i < mScopeBracket.size() && i < depthLimit; i++)
2301     {
2302         string += "_" + str(i);
2303     }
2304
2305     return string;
2306 }
2307
2308 TString OutputHLSL::scopedStruct(const TString &typeName)
2309 {
2310     if (typeName == "")
2311     {
2312         return typeName;
2313     }
2314
2315     return typeName + scopeString(mScopeDepth);
2316 }
2317
2318 TString OutputHLSL::structLookup(const TString &typeName)
2319 {
2320     for (int depth = mScopeDepth; depth >= 0; depth--)
2321     {
2322         TString scopedName = decorate(typeName + scopeString(depth));
2323
2324         for (StructNames::iterator structName = mStructNames.begin(); structName != mStructNames.end(); structName++)
2325         {
2326             if (*structName == scopedName)
2327             {
2328                 return scopedName;
2329             }
2330         }
2331     }
2332
2333     UNREACHABLE();   // Should have found a matching constructor
2334
2335     return typeName;
2336 }
2337
2338 TString OutputHLSL::decorate(const TString &string)
2339 {
2340     if (string.substr(0, 3) != "gl_" && string.substr(0, 3) != "dx_")
2341     {
2342         return "_" + string;
2343     }
2344     else
2345     {
2346         return string;
2347     }
2348 }
2349 }