/*-------------------------------------------------------------------------
|
* drawElements Quality Program OpenGL ES Utilities
|
* ------------------------------------------------
|
*
|
* Copyright 2014 The Android Open Source Project
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
*
|
*//*!
|
* \file
|
* \brief Shader variable type utilities.
|
*//*--------------------------------------------------------------------*/
|
|
#include "gluVarTypeUtil.hpp"
|
|
#include <stdlib.h>
|
|
namespace glu
|
{
|
|
// VarTokenizer
|
|
VarTokenizer::VarTokenizer (const char* str)
|
: m_str (str)
|
, m_token (TOKEN_LAST)
|
, m_tokenStart (0)
|
, m_tokenLen (0)
|
{
|
advance();
|
}
|
|
int VarTokenizer::getNumber (void) const
|
{
|
return atoi(getIdentifier().c_str());
|
}
|
|
static inline bool isNum (char c) { return de::inRange(c, '0', '9'); }
|
static inline bool isAlpha (char c) { return de::inRange(c, 'a', 'z') || de::inRange(c, 'A', 'Z'); }
|
static inline bool isIdentifierChar (char c) { return isAlpha(c) || isNum(c) || c == '_'; }
|
|
void VarTokenizer::advance (void)
|
{
|
DE_ASSERT(m_token != TOKEN_END);
|
|
m_tokenStart += m_tokenLen;
|
m_token = TOKEN_LAST;
|
m_tokenLen = 1;
|
|
if (m_str[m_tokenStart] == '[')
|
m_token = TOKEN_LEFT_BRACKET;
|
else if (m_str[m_tokenStart] == ']')
|
m_token = TOKEN_RIGHT_BRACKET;
|
else if (m_str[m_tokenStart] == 0)
|
m_token = TOKEN_END;
|
else if (m_str[m_tokenStart] == '.')
|
m_token = TOKEN_PERIOD;
|
else if (isNum(m_str[m_tokenStart]))
|
{
|
m_token = TOKEN_NUMBER;
|
while (isNum(m_str[m_tokenStart+m_tokenLen]))
|
m_tokenLen += 1;
|
}
|
else if (isIdentifierChar(m_str[m_tokenStart]))
|
{
|
m_token = TOKEN_IDENTIFIER;
|
while (isIdentifierChar(m_str[m_tokenStart+m_tokenLen]))
|
m_tokenLen += 1;
|
}
|
else
|
TCU_FAIL("Unexpected character");
|
}
|
|
// SubTypeAccess
|
|
SubTypeAccess::SubTypeAccess (const VarType& type)
|
: m_type(type)
|
{
|
}
|
|
std::string parseVariableName (const char* nameWithPath)
|
{
|
VarTokenizer tokenizer(nameWithPath);
|
TCU_CHECK(tokenizer.getToken() == VarTokenizer::TOKEN_IDENTIFIER);
|
return tokenizer.getIdentifier();
|
}
|
|
void parseTypePath (const char* nameWithPath, const VarType& type, TypeComponentVector& path)
|
{
|
VarTokenizer tokenizer(nameWithPath);
|
|
if (tokenizer.getToken() == VarTokenizer::TOKEN_IDENTIFIER)
|
tokenizer.advance();
|
|
path.clear();
|
while (tokenizer.getToken() != VarTokenizer::TOKEN_END)
|
{
|
VarType curType = getVarType(type, path);
|
|
if (tokenizer.getToken() == VarTokenizer::TOKEN_PERIOD)
|
{
|
tokenizer.advance();
|
TCU_CHECK(tokenizer.getToken() == VarTokenizer::TOKEN_IDENTIFIER);
|
TCU_CHECK_MSG(curType.isStructType(), "Invalid field selector");
|
|
// Find member.
|
std::string memberName = tokenizer.getIdentifier();
|
int ndx = 0;
|
for (; ndx < curType.getStructPtr()->getNumMembers(); ndx++)
|
{
|
if (memberName == curType.getStructPtr()->getMember(ndx).getName())
|
break;
|
}
|
TCU_CHECK_MSG(ndx < curType.getStructPtr()->getNumMembers(), "Member not found in type");
|
|
path.push_back(VarTypeComponent(VarTypeComponent::STRUCT_MEMBER, ndx));
|
tokenizer.advance();
|
}
|
else if (tokenizer.getToken() == VarTokenizer::TOKEN_LEFT_BRACKET)
|
{
|
tokenizer.advance();
|
TCU_CHECK(tokenizer.getToken() == VarTokenizer::TOKEN_NUMBER);
|
|
int ndx = tokenizer.getNumber();
|
|
if (curType.isArrayType())
|
{
|
TCU_CHECK(de::inBounds(ndx, 0, curType.getArraySize()));
|
path.push_back(VarTypeComponent(VarTypeComponent::ARRAY_ELEMENT, ndx));
|
}
|
else if (curType.isBasicType() && isDataTypeMatrix(curType.getBasicType()))
|
{
|
TCU_CHECK(de::inBounds(ndx, 0, getDataTypeMatrixNumColumns(curType.getBasicType())));
|
path.push_back(VarTypeComponent(VarTypeComponent::MATRIX_COLUMN, ndx));
|
}
|
else if (curType.isBasicType() && isDataTypeVector(curType.getBasicType()))
|
{
|
TCU_CHECK(de::inBounds(ndx, 0, getDataTypeScalarSize(curType.getBasicType())));
|
path.push_back(VarTypeComponent(VarTypeComponent::VECTOR_COMPONENT, ndx));
|
}
|
else
|
TCU_FAIL("Invalid subscript");
|
|
tokenizer.advance();
|
TCU_CHECK(tokenizer.getToken() == VarTokenizer::TOKEN_RIGHT_BRACKET);
|
tokenizer.advance();
|
}
|
else
|
TCU_FAIL("Unexpected token");
|
}
|
}
|
|
std::ostream& operator<< (std::ostream& str, const TypeAccessFormat& format)
|
{
|
const VarType* curType = &format.type;
|
|
for (TypeComponentVector::const_iterator iter = format.path.begin(); iter != format.path.end(); iter++)
|
{
|
switch (iter->type)
|
{
|
case VarTypeComponent::ARRAY_ELEMENT:
|
curType = &curType->getElementType(); // Update current type.
|
// Fall-through.
|
|
case VarTypeComponent::MATRIX_COLUMN:
|
case VarTypeComponent::VECTOR_COMPONENT:
|
str << "[" << iter->index << "]";
|
break;
|
|
case VarTypeComponent::STRUCT_MEMBER:
|
{
|
const StructMember& member = curType->getStructPtr()->getMember(iter->index);
|
str << "." << member.getName();
|
curType = &member.getType();
|
break;
|
}
|
|
default:
|
DE_ASSERT(false);
|
}
|
}
|
|
return str;
|
}
|
|
} // glu
|