Recursively write ConstantUnion to correctly construct structs.
Review URL: http://codereview.appspot.com/1108041
git-svn-id: https://angleproject.googlecode.com/svn/trunk@229 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/compiler/OutputGLSL.cpp b/src/compiler/OutputGLSL.cpp
index 3b639e9..219909e 100644
--- a/src/compiler/OutputGLSL.cpp
+++ b/src/compiler/OutputGLSL.cpp
@@ -43,7 +43,8 @@
TOutputGLSL::TOutputGLSL(TInfoSinkBase& objSink)
: TIntermTraverser(true, true, true),
mObjSink(objSink),
- mWriteFullSymbol(false)
+ mWriteFullSymbol(false),
+ mScopeSequences(false)
{
}
@@ -64,6 +65,50 @@
}
}
+const ConstantUnion* TOutputGLSL::writeConstantUnion(const TType& type, const ConstantUnion* pConstUnion)
+{
+ TInfoSinkBase& out = objSink();
+
+ if (type.getBasicType() == EbtStruct)
+ {
+ out << type.getTypeName() << "(";
+ const TTypeList* structure = type.getStruct();
+ ASSERT(structure != NULL);
+ for (size_t i = 0; i < structure->size(); ++i)
+ {
+ const TType* fieldType = (*structure)[i].type;
+ ASSERT(fieldType != NULL);
+ pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
+ if (i != structure->size() - 1) out << ", ";
+ }
+ out << ")";
+ }
+ else
+ {
+ int size = type.getObjectSize();
+ bool writeType = size > 1;
+ if (writeType) out << getTypeName(type) << "(";
+ for (int i = 0; i < size; ++i, ++pConstUnion)
+ {
+ switch (pConstUnion->getType())
+ {
+ case EbtFloat: out << pConstUnion->getFConst(); break;
+ case EbtInt: out << pConstUnion->getIConst(); break;
+ case EbtBool:
+ if (pConstUnion->getBConst())
+ out << "true";
+ else
+ out << "false";
+ break;
+ default: UNREACHABLE();
+ }
+ if (i != size - 1) out << ", ";
+ }
+ if (writeType) out << ")";
+ }
+ return pConstUnion;
+}
+
void TOutputGLSL::visitSymbol(TIntermSymbol* node)
{
TInfoSinkBase& out = objSink();
@@ -106,28 +151,7 @@
void TOutputGLSL::visitConstantUnion(TIntermConstantUnion* node)
{
- TInfoSinkBase& out = objSink();
-
- const TType& type = node->getType();
- int size = type.getObjectSize();
- bool writeType = (size > 1) || (type.getBasicType() == EbtStruct);
- if (writeType)
- out << getTypeName(type) << "(";
- for (int i = 0; i < size; ++i)
- {
- const ConstantUnion& 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 (writeType)
- out << ")";
+ writeConstantUnion(node->getType(), node->getUnionArrayPointer());
}
bool TOutputGLSL::visitBinary(Visit visit, TIntermBinary* node)
@@ -331,13 +355,13 @@
{
node->getTrueBlock()->traverse(this);
}
- out << "}";
+ out << ";\n}";
if (node->getFalseBlock())
{
out << " else {\n";
node->getFalseBlock()->traverse(this);
- out << "}";
+ out << ";\n}";
}
decrementDepth();
out << "\n";
@@ -347,11 +371,26 @@
bool TOutputGLSL::visitAggregate(Visit visit, TIntermAggregate* node)
{
+ bool visitChildren = true;
TInfoSinkBase& out = objSink();
switch (node->getOp())
{
case EOpSequence:
- writeTriplet(visit, NULL, ";\n", ";\n");
+ if (visit == PreVisit)
+ {
+ if (mScopeSequences)
+ out << "{\n";
+ }
+ else if (visit == InVisit)
+ {
+ out << ";\n";
+ }
+ else if (visit == PostVisit)
+ {
+ out << ";\n";
+ if (mScopeSequences)
+ out << "}\n";
+ }
break;
case EOpPrototype:
// Function declaration.
@@ -373,26 +412,47 @@
mWriteFullSymbol = false;
}
break;
- case EOpFunction:
+ case EOpFunction: {
// Function definition.
- if (visit == PreVisit)
+ TString returnType = getTypeName(node->getType());
+ TString functionName = TFunction::unmangleName(node->getName());
+ out << returnType << " " << functionName;
+
+ // Function definition node contains one or two children nodes
+ // representing function parameters and function body. The latter
+ // is not present in case of empty function bodies.
+ const TIntermSequence& sequence = node->getSequence();
+ ASSERT((sequence.size() == 1) || (sequence.size() == 2));
+ TIntermSequence::const_iterator seqIter = sequence.begin();
+
+ // Traverse function parameters.
+ TIntermAggregate* params = (*seqIter)->getAsAggregate();
+ ASSERT(params != NULL);
+ ASSERT(params->getOp() == EOpParameters);
+ params->traverse(this);
+
+ // Traverse function body.
+ TIntermAggregate* body = ++seqIter != sequence.end() ?
+ (*seqIter)->getAsAggregate() : NULL;
+ if (body != NULL)
{
- TString returnType = getTypeName(node->getType());
- TString functionName = TFunction::unmangleName(node->getName());
- out << returnType << " " << functionName;
+ ASSERT(body->getOp() == EOpSequence);
+ // Sequences are scoped with {} inside function body so that
+ // variables are declared in the correct scope.
+ mScopeSequences = true;
+ body->traverse(this);
+ mScopeSequences = false;
}
- else if (visit == InVisit)
+ else
{
- // Called after traversing function arguments (EOpParameters)
- // but before traversing function body (EOpSequence).
- out << "{\n";
+ // Empty function body.
+ out << "{}\n";
}
- else if (visit == PostVisit)
- {
- // Called after traversing function body (EOpSequence).
- out << "}\n";
- }
+
+ // Fully processed; no need to visit children.
+ visitChildren = false;
break;
+ }
case EOpFunctionCall:
// Function call.
if (visit == PreVisit)
@@ -503,7 +563,7 @@
default: UNREACHABLE(); break;
}
- return true;
+ return visitChildren;
}
bool TOutputGLSL::visitLoop(Visit visit, TIntermLoop* node)