| /*------------------------------------------------------------------------- |
| * 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 |