Added GLSL backend for ESSL translator.
Review URL: http://codereview.appspot.com/698041

git-svn-id: https://angleproject.googlecode.com/svn/trunk@69 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/compiler/OutputGLSL.cpp b/src/compiler/OutputGLSL.cpp
new file mode 100644
index 0000000..de29b54
--- /dev/null
+++ b/src/compiler/OutputGLSL.cpp
@@ -0,0 +1,469 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "OutputGLSL.h"
+#include "common/debug.h"
+
+namespace
+{
+TString getTypeName(const TType& type)
+{
+    TInfoSinkBase out;
+    if (type.isMatrix())
+    {
+        out << "mat";
+        out << type.getNominalSize();
+    }
+    else if (type.isArray())
+    {
+        UNIMPLEMENTED();
+    }
+    else if (type.isVector())
+    {
+        switch (type.getBasicType())
+        {
+            case EbtFloat: out << "vec"; break;
+            case EbtInt: out << "ivec"; break;
+            case EbtBool: out << "bvec"; break;
+            default: UNREACHABLE(); break;
+        }
+        out << type.getNominalSize();
+    }
+    else
+    {
+        if (type.getBasicType() == EbtStruct)
+            out << type.getTypeName();
+        else
+            out << type.getBasicString();
+    }
+    return TString(out.c_str());
+}
+
+TString getUnmangledFunctionName(const TString& mangledName)
+{
+    return TString(mangledName.c_str(), mangledName.find_first_of('('));
+}
+
+TString getIndentationString(int depth)
+{
+    TString indentation(depth, ' ');
+    return indentation;
+}
+}  // namespace
+
+TOutputGLSL::TOutputGLSL(TParseContext &context)
+    : TIntermTraverser(true, true, true),
+      writeFullSymbol(false),
+      parseContext(context)
+{
+}
+
+void TOutputGLSL::header()
+{
+    TInfoSinkBase& out = objSink();
+
+    TSymbolTableLevel* symbols = parseContext.symbolTable.getGlobalLevel();
+    for (TSymbolTableLevel::const_iterator symbolIter = symbols->begin(); symbolIter != symbols->end(); ++symbolIter)
+    {
+        const TSymbol* symbol = symbolIter->second;
+        if (!symbol->isVariable())
+            continue;
+
+        const TVariable* variable = static_cast<const TVariable*>(symbol);
+        const TString& name = variable->getName();
+        const TType& type = variable->getType();
+        TQualifier qualifier = type.getQualifier();
+
+        //symbol->dump(parseContext.infoSink);
+    }
+}
+
+void TOutputGLSL::writeTriplet(Visit visit, const char* preStr, const char* inStr, const char* postStr)
+{
+    TInfoSinkBase& out = objSink();
+    if (visit == PreVisit && preStr)
+    {
+        out << preStr;
+    }
+    else if (visit == InVisit && inStr)
+    {
+        out << inStr;
+    }
+    else if (visit == PostVisit && postStr)
+    {
+        out << postStr;
+    }
+}
+
+void TOutputGLSL::visitSymbol(TIntermSymbol* node)
+{
+    TInfoSinkBase& out = objSink();
+    if (writeFullSymbol)
+    {
+        TQualifier qualifier = node->getQualifier();
+        if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal))
+            out << node->getQualifierString() << " ";
+ 
+        out << getTypeName(node->getType()) << " ";
+    }
+    out << node->getSymbol();
+}
+
+void TOutputGLSL::visitConstantUnion(TIntermConstantUnion* node)
+{
+    TInfoSinkBase& out = objSink();
+
+    TType type = node->getType();
+    int size = type.getObjectSize();
+    if (size > 1)
+        out << getTypeName(type) << "(";
+    for (int i = 0; i < size; ++i) {
+        const constUnion& data = node->getUnionArrayPointer()[i];
+        switch (data.getType())
+        {
+            case EbtFloat: out << data.getFConst(); break;
+            case EbtInt: out << data.getIConst(); break;
+            case EbtBool: out << data.getBConst(); break;
+            default: UNREACHABLE(); break;
+        }
+        if (i != size - 1)
+            out << ", ";
+    }
+    if (size > 1)
+        out << ")";
+}
+
+bool TOutputGLSL::visitBinary(Visit visit, TIntermBinary* node)
+{
+    bool visitChildren = true;
+    TInfoSinkBase& out = objSink();
+    switch (node->getOp())
+    {
+        case EOpAssign: writeTriplet(visit, NULL, " = ", NULL); break;
+        case EOpInitialize:
+            if (visit == InVisit) {
+                out << " = ";
+                writeFullSymbol= false;
+            }
+            break;
+        case EOpAddAssign: writeTriplet(visit, NULL, " += ", NULL); break;
+        case EOpSubAssign: UNIMPLEMENTED(); break;
+        case EOpMulAssign: UNIMPLEMENTED(); break;
+        case EOpVectorTimesMatrixAssign: UNIMPLEMENTED(); break;
+        case EOpVectorTimesScalarAssign: UNIMPLEMENTED(); break;
+        case EOpMatrixTimesScalarAssign: UNIMPLEMENTED(); break;
+        case EOpMatrixTimesMatrixAssign: UNIMPLEMENTED(); break;
+        case EOpDivAssign: UNIMPLEMENTED(); break;
+
+        case EOpIndexDirect: writeTriplet(visit, NULL, "[", "]"); break;
+        case EOpIndexIndirect: UNIMPLEMENTED(); break;
+        case EOpIndexDirectStruct:
+            if (visit == InVisit)
+            {
+                out << ".";
+                // TODO(alokp): ASSERT
+                out << node->getType().getFieldName();
+                visitChildren = false;
+            }
+            break;
+        case EOpVectorSwizzle:
+            if (visit == InVisit)
+            {
+                out << ".";
+                TIntermAggregate* rightChild = node->getRight()->getAsAggregate();
+                TIntermSequence& sequence = rightChild->getSequence();
+                for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit)
+                {
+                    TIntermConstantUnion* element = (*sit)->getAsConstantUnion();
+                    ASSERT(element->getBasicType() == EbtInt);
+                    ASSERT(element->getNominalSize() == 1);
+                    const constUnion& data = element->getUnionArrayPointer()[0];
+                    ASSERT(data.getType() == EbtInt);
+                    switch (data.getIConst())
+                    {
+                        case 0: out << "x"; break;
+                        case 1: out << "y"; break;
+                        case 2: out << "z"; break;
+                        case 3: out << "w"; break;
+                        default: UNREACHABLE(); break;
+                    }
+                }
+                visitChildren = false;
+            }
+            break;
+
+        case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break;
+        case EOpSub: writeTriplet(visit, "(", " - ", ")"); break;
+        case EOpMul: writeTriplet(visit, "(", " * ", ")"); break;
+        case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break;
+        case EOpMod: UNIMPLEMENTED(); break;
+        case EOpEqual: UNIMPLEMENTED(); break;
+        case EOpNotEqual: UNIMPLEMENTED(); break;
+        case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break;
+        case EOpGreaterThan: writeTriplet(visit, NULL, " > ", NULL); break;
+        case EOpLessThanEqual: UNIMPLEMENTED(); break;
+        case EOpGreaterThanEqual: UNIMPLEMENTED(); break;
+
+        // Notice the fall-through.
+        case EOpVectorTimesScalar:
+        case EOpVectorTimesMatrix:
+        case EOpMatrixTimesVector:
+        case EOpMatrixTimesScalar:
+        case EOpMatrixTimesMatrix:
+            writeTriplet(visit, "(", " * ", ")");
+            break;
+
+        case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break;
+        case EOpLogicalXor: UNIMPLEMENTED(); break;
+        case EOpLogicalAnd: UNIMPLEMENTED(); break;
+        default: UNREACHABLE(); break;
+    }
+
+    return visitChildren;
+}
+
+bool TOutputGLSL::visitUnary(Visit visit, TIntermUnary* node)
+{
+    TInfoSinkBase& out = objSink();
+
+    switch (node->getOp())
+    {
+        case EOpNegative: writeTriplet(visit, "(-", NULL, ")"); break;
+        case EOpVectorLogicalNot: UNIMPLEMENTED(); break;
+        case EOpLogicalNot: UNIMPLEMENTED(); break;
+
+        case EOpPostIncrement: UNIMPLEMENTED(); break;
+        case EOpPostDecrement: UNIMPLEMENTED(); break;
+        case EOpPreIncrement: UNIMPLEMENTED(); break;
+        case EOpPreDecrement: UNIMPLEMENTED(); break;
+
+        case EOpConvIntToBool: UNIMPLEMENTED(); break;
+        case EOpConvFloatToBool: UNIMPLEMENTED(); break;
+        case EOpConvBoolToFloat: UNIMPLEMENTED(); break;
+        case EOpConvIntToFloat: writeTriplet(visit, "float(", NULL, ")"); break;
+        case EOpConvFloatToInt: UNIMPLEMENTED(); break;
+        case EOpConvBoolToInt: UNIMPLEMENTED(); break;
+
+        case EOpRadians: UNIMPLEMENTED(); break;
+        case EOpDegrees: UNIMPLEMENTED(); break;
+        case EOpSin: writeTriplet(visit, "sin(", NULL, ")"); break;
+        case EOpCos: writeTriplet(visit, "cos(", NULL, ")"); break;
+        case EOpTan: UNIMPLEMENTED(); break;
+        case EOpAsin: UNIMPLEMENTED(); break;
+        case EOpAcos: UNIMPLEMENTED(); break;
+        case EOpAtan: UNIMPLEMENTED(); break;
+
+        case EOpExp: UNIMPLEMENTED(); break;
+        case EOpLog: UNIMPLEMENTED(); break;
+        case EOpExp2: UNIMPLEMENTED(); break;
+        case EOpLog2: UNIMPLEMENTED(); break;
+        case EOpSqrt: UNIMPLEMENTED(); break;
+        case EOpInverseSqrt: UNIMPLEMENTED(); break;
+
+        case EOpAbs: UNIMPLEMENTED(); break;
+        case EOpSign: UNIMPLEMENTED(); break;
+        case EOpFloor: writeTriplet(visit, "floor(", NULL, ")"); break;
+        case EOpCeil: UNIMPLEMENTED(); break;
+        case EOpFract: UNIMPLEMENTED(); break;
+
+        case EOpLength: UNIMPLEMENTED(); break;
+        case EOpNormalize: writeTriplet(visit, "normalize(", NULL, ")"); break;
+
+        case EOpAny: UNIMPLEMENTED(); break;
+        case EOpAll: UNIMPLEMENTED(); break;
+
+        default: UNREACHABLE(); break;
+    }
+
+    return true;
+}
+
+bool TOutputGLSL::visitSelection(Visit visit, TIntermSelection* node)
+{
+    TInfoSinkBase& out = objSink();
+
+    out << "if (";
+    node->getCondition()->traverse(this);
+    out << ") {\n";
+
+    incrementDepth();
+    node->getTrueBlock()->traverse(this);
+    out << getIndentationString(depth - 2) << "}";
+
+    if (node->getFalseBlock())
+    {
+        out << " else {\n";
+        node->getFalseBlock()->traverse(this);
+        out << getIndentationString(depth - 2) << "}";
+    }
+    decrementDepth();
+
+    out << "\n";
+    return false;
+}
+
+bool TOutputGLSL::visitAggregate(Visit visit, TIntermAggregate* node)
+{
+    TInfoSinkBase& out = objSink();
+    switch (node->getOp())
+    {
+        case EOpSequence:
+            if (visit == PreVisit)
+            {
+                out << getIndentationString(depth);
+            }
+            else if (visit == InVisit)
+            {
+                out << ";\n";
+                out << getIndentationString(depth - 1);
+            }
+            else
+            {
+                out << ";\n";
+            }
+            break;
+        case EOpComma:
+            UNIMPLEMENTED();
+            return true;
+        case EOpFunction:
+            if (visit == PreVisit)
+            {
+                TString returnType = node->getBasicString();
+                TString functionName = getUnmangledFunctionName(node->getName());
+                out << returnType << " " << functionName;
+            }
+            else if (visit == InVisit)
+            {
+                // Called after traversing function arguments (EOpParameters)
+                // but before traversing function body (EOpSequence).
+                out << "{\n";
+            }
+            else if (visit == PostVisit)
+            {
+                // Called after traversing function body (EOpSequence).
+                out << "}\n";
+            }
+            break;
+        case EOpFunctionCall:
+            if (visit == PreVisit)
+            {
+                TString functionName = getUnmangledFunctionName(node->getName());
+                out << functionName << "(";
+            }
+            else if (visit == InVisit)
+            {
+                out << ", ";
+            }
+            else
+            {
+                out << ")";
+            }
+            break;
+        case EOpParameters:
+            if (visit == PreVisit)
+            {
+                out << "(";
+                writeFullSymbol = true;
+            }
+            else if (visit == InVisit)
+            {
+                out << ", ";
+            }
+            else
+            {
+                out << ")";
+                writeFullSymbol = false;
+            }
+            break;
+        case EOpDeclaration:
+            if (visit == PreVisit)
+            {
+                writeFullSymbol = true;
+            }
+            else if (visit == InVisit)
+            {
+                out << ", ";
+                writeFullSymbol = false;
+            }
+            else
+            {
+                writeFullSymbol = false;
+            }
+            break;
+
+        case EOpConstructFloat: UNIMPLEMENTED(); break;
+	case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break;
+	case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break;
+	case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break;
+	case EOpConstructBool: UNIMPLEMENTED(); break;
+	case EOpConstructBVec2: UNIMPLEMENTED(); break;
+	case EOpConstructBVec3: UNIMPLEMENTED(); break;
+	case EOpConstructBVec4: UNIMPLEMENTED(); break;
+	case EOpConstructInt: UNIMPLEMENTED(); break;
+	case EOpConstructIVec2: UNIMPLEMENTED(); break;
+	case EOpConstructIVec3: UNIMPLEMENTED(); break;
+	case EOpConstructIVec4: UNIMPLEMENTED(); break;
+	case EOpConstructMat2: UNIMPLEMENTED(); break;
+	case EOpConstructMat3: UNIMPLEMENTED(); break;
+	case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break;
+	case EOpConstructStruct: UNIMPLEMENTED(); break;
+
+	case EOpLessThan: UNIMPLEMENTED(); break;
+	case EOpGreaterThan: UNIMPLEMENTED(); break;
+	case EOpLessThanEqual: UNIMPLEMENTED(); break;
+	case EOpGreaterThanEqual: UNIMPLEMENTED(); break;
+	case EOpVectorEqual: UNIMPLEMENTED(); break;
+	case EOpVectorNotEqual: UNIMPLEMENTED(); break;
+
+	case EOpMod: writeTriplet(visit, "mod(", ", ", ")"); break;
+	case EOpPow: writeTriplet(visit, "pow(", ", ", ")"); break;
+
+	case EOpAtan: UNIMPLEMENTED(); break;
+
+	case EOpMin: writeTriplet(visit, "min(", ", ", ")"); break;
+	case EOpMax: writeTriplet(visit, "max(", ", ", ")"); break;
+	case EOpClamp: writeTriplet(visit, "clamp(", ", ", ")"); break;
+	case EOpMix: writeTriplet(visit, "mix(", ", ", ")"); break;
+	case EOpStep: UNIMPLEMENTED(); break;
+	case EOpSmoothStep: UNIMPLEMENTED(); break;
+
+	case EOpDistance: UNIMPLEMENTED(); break;
+	case EOpDot: writeTriplet(visit, "dot(", ", ", ")"); break;
+	case EOpCross: UNIMPLEMENTED(); break;
+	case EOpFaceForward: UNIMPLEMENTED(); break;
+	case EOpReflect: writeTriplet(visit, "reflect(", ", ", ")"); break;
+	case EOpRefract: UNIMPLEMENTED(); break;
+	case EOpMul: UNIMPLEMENTED(); break;
+
+        default: UNREACHABLE(); break;
+    }
+    return true;
+}
+
+bool TOutputGLSL::visitLoop(Visit visit, TIntermLoop* node)
+{
+    UNIMPLEMENTED();
+    return true;
+}
+
+bool TOutputGLSL::visitBranch(Visit visit, TIntermBranch* node)
+{
+    TInfoSinkBase &out = objSink();
+
+    switch (node->getFlowOp())
+    {
+        case EOpKill: UNIMPLEMENTED(); break;
+        case EOpBreak: UNIMPLEMENTED(); break;
+        case EOpContinue: UNIMPLEMENTED(); break;
+        case EOpReturn:
+            if (visit == PreVisit)
+                out << "return ";
+            break;
+        default: UNREACHABLE(); break;
+    }
+
+    return true;
+}