blob: 7831b624c13793cc0a9f3209e7a4f6ddd33597e7 [file] [log] [blame]
//
// 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 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();
if (node->usesTernaryOperator())
{
out << "(";
node->getCondition()->traverse(this);
out << ") ? (";
node->getTrueBlock()->traverse(this);
out << ") : (";
node->getFalseBlock()->traverse(this);
out << ")";
}
else
{
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 = TFunction::unmangleName(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 = TFunction::unmangleName(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;
}