blob: c5df47a36651c265e5ed8f2123a2687eb584eda1 [file] [log] [blame]
/*-------------------------------------------------------------------------
* 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