<commit_before>#include <math.h>
#include <stdio.h>

#include <cppunit/simpleheader.hxx>

#ifndef _RTL_UUID_H_
#include <rtl/uuid.h>
#endif

#ifndef _RTL_USTRING_H_
#include <rtl/ustring.h>
#endif
#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif

#ifdef UNX
#include <unistd.h>
#include <time.h>
#endif

using namespace rtl;

/** print a UNI_CODE String. And also print some comments of the string.
*/
inline void printUString( const ::rtl::OUString & str, const sal_Char * msg = "" )
{
    t_print("#%s #printUString_u# ", msg );
    rtl::OString aString;
    aString = ::rtl::OUStringToOString( str, RTL_TEXTENCODING_ASCII_US );
    t_print("%s\n", (char *)aString.getStr( ) );
}

/************************************************************************
 * For diagnostics( from sal/test/testuuid.cxx )
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sal.hxx"
void printUuid( sal_uInt8 *pNode )
{
    for( sal_Int32 i1 = 0 ; i1 < 4 ; i1++ )
    {
        for( sal_Int32 i2 = 0 ; i2 < 4 ; i2++ )
        {
            printf( "%02x" , pNode[i1*4 +i2] );
        }
        if( i1 == 3 )
            break;
        printf( "-" );
    }

    printf( "\n# " );
}

namespace rtl_Uuid
{
class createUuid : public CppUnit::TestFixture
{
public:
    // initialise your test code values here.
    void setUp()
    {
    }

    void tearDown()
    {
    }

#define TEST_UUID 20
    void createUuid_001()
    {
    sal_uInt8 aNode[TEST_UUID][16];
    sal_Int32 i,i2;
    for( i = 0 ; i < TEST_UUID ; i ++ )
    {
        rtl_createUuid( aNode[i], 0, sal_False );
    }
    sal_Bool bRes = sal_True;
    for( i = 0 ; i < TEST_UUID ; i ++ )
    {
        for( i2 = i+1 ; i2 < TEST_UUID ; i2 ++ )
        {
            if ( rtl_compareUuid( aNode[i] , aNode[i2] ) == 0  )
            {
                bRes = sal_False;
                break;
            }
        }
        if ( bRes == sal_False )
            break;
    }
    CPPUNIT_ASSERT_MESSAGE("createUuid: every uuid must be different.", bRes == sal_True );
    }
   /*
    void createUuid_002()
    {
    sal_uInt8 pNode[16];
    sal_uInt8 aNode[TEST_UUID][16];
    sal_Int32 i,i2;
    for( i = 0 ; i < TEST_UUID ; i ++ )
    {
        rtl_createUuid( aNode[i], pNode, sal_True );
    }
    sal_Bool bRes = sal_True;
    for( i = 0 ; i < TEST_UUID ; i ++ )
    {
        //printUuid( aNode[i] );
        for( i2 = i+1 ; i2 < TEST_UUID ; i2 ++ )
        {
            if ( rtl_compareUuid( aNode[i] , aNode[i2] ) == 0  )
            {
                bRes = sal_False;
                break;
            }
        }
        if ( bRes == sal_False )
            break;
    }
    CPPUNIT_ASSERT_MESSAGE("createUuid: every uuid must be different.", bRes == sal_True );
    }*/

    CPPUNIT_TEST_SUITE(createUuid);
    CPPUNIT_TEST(createUuid_001);
    //CPPUNIT_TEST(createUuid_002);
    CPPUNIT_TEST_SUITE_END();
}; // class createUuid

namespace ThreadHelper
{
     void thread_sleep(sal_Int32 _nSec)
    {
#ifdef WNT      //Windows
        Sleep(_nSec * 10 );
#endif
#if ( defined UNX ) || ( defined OS2 )  //Unix
        sleep( _nSec );
#endif
    }
}

class createNamedUuid : public CppUnit::TestFixture
{
public:
    // initialise your test code values here.
    void setUp()
    {
    }

    void tearDown()
    {
    }

    void createNamedUuid_001()
    {
        sal_uInt8 NameSpace_DNS[16] = RTL_UUID_NAMESPACE_DNS;
        sal_uInt8 NameSpace_URL[16] = RTL_UUID_NAMESPACE_URL;
        sal_uInt8 pPriorCalculatedUUID[16] = {
            0x52,0xc9,0x30,0xa5,
            0xd1,0x61,0x3b,0x16,
            0x98,0xc5,0xf8,0xd1,
            0x10,0x10,0x6d,0x4d };

        sal_uInt8 pNamedUUID[16], pNamedUUID2[16];

        // Same name does generate the same uuid
        rtl_String *pName = 0;
        rtl_string_newFromStr( &pName , "this is a bla.blubs.DNS-Name" );
        rtl_createNamedUuid( pNamedUUID , NameSpace_DNS , pName );
        rtl_createNamedUuid( pNamedUUID2 , NameSpace_DNS , pName );
        CPPUNIT_ASSERT_MESSAGE( "Same name should generate the same uuid", ! memcmp( pNamedUUID , pNamedUUID2 , 16 ) && rtl_compareUuid( pNamedUUID , pNamedUUID2 ) == 0 );
        CPPUNIT_ASSERT_MESSAGE( "Same name should generate the same uuid", ! memcmp( pNamedUUID  , pPriorCalculatedUUID , 16 ) );

        // Different names does not generate the same uuid
        rtl_string_newFromStr( &pName , "this is a bla.blubs.DNS-Namf" );
        rtl_createNamedUuid( pNamedUUID2 , NameSpace_DNS , pName );
        CPPUNIT_ASSERT_MESSAGE("Different names does not generate the same uuid.", memcmp( pNamedUUID , pNamedUUID2 , 16 ) );

        // the same name with different namespace uuid produces different uuids
        rtl_createNamedUuid( pNamedUUID , NameSpace_URL , pName );
        CPPUNIT_ASSERT_MESSAGE( " same name with different namespace uuid produces different uuids", memcmp( pNamedUUID , pNamedUUID2 , 16 ) && rtl_compareUuid( pNamedUUID , pNamedUUID2 ) != 0);

        //test compareUuid
        if ( rtl_compareUuid( pNamedUUID , pNamedUUID2 ) > 0 )
        {   CPPUNIT_ASSERT_MESSAGE( " compare uuids", rtl_compareUuid( pNamedUUID2 , pNamedUUID ) < 0);
        }
        else
            CPPUNIT_ASSERT_MESSAGE( " compare uuids", rtl_compareUuid( pNamedUUID2 , pNamedUUID ) > 0);

        rtl_string_release( pName );
    }

    CPPUNIT_TEST_SUITE(createNamedUuid);
    CPPUNIT_TEST(createNamedUuid_001);
    CPPUNIT_TEST_SUITE_END();
}; // class createNamedUuid

CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(rtl_Uuid::createUuid, "rtl_Uuid");
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(rtl_Uuid::createNamedUuid, "rtl_Uuid");
} // namespace rtl_Uuid

// -----------------------------------------------------------------------------

// this macro creates an empty function, which will called by the RegisterAllFunctions()
// to let the user the possibility to also register some functions by hand.
NOADDITIONAL;

<commit_msg>INTEGRATION: CWS reportdesign01 (1.5.98); FILE MERGED 2007/10/04 09:03:58 lla 1.5.98.1: #i67655# only updates on some tests to build warning free<commit_after> /*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: rtl_Uuid.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: ihi $ $Date: 2007-11-20 19:48:05 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sal.hxx"

#include <math.h>
#include <stdio.h>

#include <cppunit/simpleheader.hxx>

#ifndef _RTL_UUID_H_
#include <rtl/uuid.h>
#endif

#ifndef _RTL_USTRING_H_
#include <rtl/ustring.h>
#endif
#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif

#ifdef UNX
#include <unistd.h>
#include <time.h>
#endif

using namespace rtl;

/** print a UNI_CODE String. And also print some comments of the string.
*/
inline void printUString( const ::rtl::OUString & str, const sal_Char * msg = "" )
{
    t_print("#%s #printUString_u# ", msg );
    rtl::OString aString;
    aString = ::rtl::OUStringToOString( str, RTL_TEXTENCODING_ASCII_US );
    t_print("%s\n", (char *)aString.getStr( ) );
}

/************************************************************************
 * For diagnostics( from sal/test/testuuid.cxx )
 ************************************************************************/

void printUuid( sal_uInt8 *pNode )
{
    for( sal_Int32 i1 = 0 ; i1 < 4 ; i1++ )
    {
        for( sal_Int32 i2 = 0 ; i2 < 4 ; i2++ )
        {
            printf( "%02x" , pNode[i1*4 +i2] );
        }
        if( i1 == 3 )
            break;
        printf( "-" );
    }

    printf( "\n# " );
}

namespace rtl_Uuid
{
class createUuid : public CppUnit::TestFixture
{
public:
    // initialise your test code values here.
    void setUp()
    {
    }

    void tearDown()
    {
    }

#define TEST_UUID 20
    void createUuid_001()
    {
    sal_uInt8 aNode[TEST_UUID][16];
    sal_Int32 i,i2;
    for( i = 0 ; i < TEST_UUID ; i ++ )
    {
        rtl_createUuid( aNode[i], 0, sal_False );
    }
    sal_Bool bRes = sal_True;
    for( i = 0 ; i < TEST_UUID ; i ++ )
    {
        for( i2 = i+1 ; i2 < TEST_UUID ; i2 ++ )
        {
            if ( rtl_compareUuid( aNode[i] , aNode[i2] ) == 0  )
            {
                bRes = sal_False;
                break;
            }
        }
        if ( bRes == sal_False )
            break;
    }
    CPPUNIT_ASSERT_MESSAGE("createUuid: every uuid must be different.", bRes == sal_True );
    }
   /*
    void createUuid_002()
    {
    sal_uInt8 pNode[16];
    sal_uInt8 aNode[TEST_UUID][16];
    sal_Int32 i,i2;
    for( i = 0 ; i < TEST_UUID ; i ++ )
    {
        rtl_createUuid( aNode[i], pNode, sal_True );
    }
    sal_Bool bRes = sal_True;
    for( i = 0 ; i < TEST_UUID ; i ++ )
    {
        //printUuid( aNode[i] );
        for( i2 = i+1 ; i2 < TEST_UUID ; i2 ++ )
        {
            if ( rtl_compareUuid( aNode[i] , aNode[i2] ) == 0  )
            {
                bRes = sal_False;
                break;
            }
        }
        if ( bRes == sal_False )
            break;
    }
    CPPUNIT_ASSERT_MESSAGE("createUuid: every uuid must be different.", bRes == sal_True );
    }*/

    CPPUNIT_TEST_SUITE(createUuid);
    CPPUNIT_TEST(createUuid_001);
    //CPPUNIT_TEST(createUuid_002);
    CPPUNIT_TEST_SUITE_END();
}; // class createUuid

namespace ThreadHelper
{
     void thread_sleep(sal_Int32 _nSec)
    {
#ifdef WNT      //Windows
        Sleep(_nSec * 10 );
#endif
#if ( defined UNX ) || ( defined OS2 )  //Unix
        sleep( _nSec );
#endif
    }
}

class createNamedUuid : public CppUnit::TestFixture
{
public:
    // initialise your test code values here.
    void setUp()
    {
    }

    void tearDown()
    {
    }

    void createNamedUuid_001()
    {
        sal_uInt8 NameSpace_DNS[16] = RTL_UUID_NAMESPACE_DNS;
        sal_uInt8 NameSpace_URL[16] = RTL_UUID_NAMESPACE_URL;
        sal_uInt8 pPriorCalculatedUUID[16] = {
            0x52,0xc9,0x30,0xa5,
            0xd1,0x61,0x3b,0x16,
            0x98,0xc5,0xf8,0xd1,
            0x10,0x10,0x6d,0x4d };

        sal_uInt8 pNamedUUID[16], pNamedUUID2[16];

        // Same name does generate the same uuid
        rtl_String *pName = 0;
        rtl_string_newFromStr( &pName , "this is a bla.blubs.DNS-Name" );
        rtl_createNamedUuid( pNamedUUID , NameSpace_DNS , pName );
        rtl_createNamedUuid( pNamedUUID2 , NameSpace_DNS , pName );
        CPPUNIT_ASSERT_MESSAGE( "Same name should generate the same uuid", ! memcmp( pNamedUUID , pNamedUUID2 , 16 ) && rtl_compareUuid( pNamedUUID , pNamedUUID2 ) == 0 );
        CPPUNIT_ASSERT_MESSAGE( "Same name should generate the same uuid", ! memcmp( pNamedUUID  , pPriorCalculatedUUID , 16 ) );

        // Different names does not generate the same uuid
        rtl_string_newFromStr( &pName , "this is a bla.blubs.DNS-Namf" );
        rtl_createNamedUuid( pNamedUUID2 , NameSpace_DNS , pName );
        CPPUNIT_ASSERT_MESSAGE("Different names does not generate the same uuid.", memcmp( pNamedUUID , pNamedUUID2 , 16 ) );

        // the same name with different namespace uuid produces different uuids
        rtl_createNamedUuid( pNamedUUID , NameSpace_URL , pName );
        CPPUNIT_ASSERT_MESSAGE( " same name with different namespace uuid produces different uuids", memcmp( pNamedUUID , pNamedUUID2 , 16 ) && rtl_compareUuid( pNamedUUID , pNamedUUID2 ) != 0);

        //test compareUuid
        if ( rtl_compareUuid( pNamedUUID , pNamedUUID2 ) > 0 )
        {   CPPUNIT_ASSERT_MESSAGE( " compare uuids", rtl_compareUuid( pNamedUUID2 , pNamedUUID ) < 0);
        }
        else
            CPPUNIT_ASSERT_MESSAGE( " compare uuids", rtl_compareUuid( pNamedUUID2 , pNamedUUID ) > 0);

        rtl_string_release( pName );
    }

    CPPUNIT_TEST_SUITE(createNamedUuid);
    CPPUNIT_TEST(createNamedUuid_001);
    CPPUNIT_TEST_SUITE_END();
}; // class createNamedUuid

CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(rtl_Uuid::createUuid, "rtl_Uuid");
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(rtl_Uuid::createNamedUuid, "rtl_Uuid");
} // namespace rtl_Uuid

// -----------------------------------------------------------------------------

// this macro creates an empty function, which will called by the RegisterAllFunctions()
// to let the user the possibility to also register some functions by hand.
NOADDITIONAL;

<|endoftext|>


<commit_before>#include "nodes.hpp"

namespace lang {

  void printIndent(int level) {
    for (int i = 0; i < level; ++i) print("  ");
  }

  ASTNode::ASTNode() {}
  ASTNode::~ASTNode() {}

  void ASTNode::addChild(ASTNode* child) {
    child->setParent(this);
    children.push_back(child);
  }

  std::vector<ASTNode*>& ASTNode::getChildren() {
    return children;
  }

  void ASTNode::setParent(ASTNode* parent) {
    this->parent = parent;
  }
  ASTNode* ASTNode::getParent() {
    return parent;
  }

  void ASTNode::setLineNumber(int lines) {
    this->lines = lines;
  }
  int ASTNode::getLineNumber() {
    return this->lines;
  }

  std::string ASTNode::getNodeType() {
    return "ASTNode";
  }

  void ASTNode::printTree(int level) {
    printIndent(level);
    print("Plain ASTNode");
    for (auto child : children) {
      child->printTree(level + 1);
    }
  }

  SingleChildNode::SingleChildNode() {};
  void SingleChildNode::addChild(ASTNode* child) {
    if (this->getChildren().size() >= 1) throw std::runtime_error("Trying to add more than one child to SingleChildNode.");
    else {
      this->ASTNode::addChild(child);
    }
  }

  ASTNode* SingleChildNode::getChild() {
    return children[0];
  }

  std::string SingleChildNode::getNodeType() {
    return "SingleChildNode";
  }

  void SingleChildNode::printTree(int level) {
    printIndent(level);
    auto child = dynamic_cast<SingleChildNode*>(this->getChild());
    if (child == nullptr) {
      print("SingleChildNode, empty", "\n");
      return;
    }
    print("SingleChildNode with: ", child, "\n");
    child->printTree(level + 1);
  }

  DeclarationNode::DeclarationNode(std::string typeName, Token identifier) {
    this->typeName = typeName;
    this->identifier = identifier;
  }

  void DeclarationNode::addChild(ASTNode* child) {
    auto node = dynamic_cast<ExpressionNode*>(child);
    if (node == 0) throw std::invalid_argument("DeclarationNode only accepts an ExpressionNode as its child.");
    this->SingleChildNode::addChild(node);
  }

  std::string DeclarationNode::getNodeType() {
    return "DeclarationNode";
  }

  void DeclarationNode::printTree(int level) {
    printIndent(level);
    print("Declared ", this->typeName, " as ", this->identifier, "\n");
    if (this->getChildren().size() == 1) dynamic_cast<ExpressionNode*>(this->getChild())->printTree(level + 1);
  }

  std::vector<TokenType> ExpressionNode::validOperandTypes {
    INTEGER, FLOAT, STRING, BOOLEAN, ARRAY, TYPE, VARIABLE, FUNCTION, UNPROCESSED
  };

  ExpressionNode::ExpressionNode(std::vector<Token>& tokens) {
    for (uint64 i = 0; i < tokens.size(); ++i) {
      if (EXPRESSION_STEPS) {
        for (auto tok : outStack) print(tok.data, " ");
        print("\n-------\n");
        for (auto tok : opStack) print(tok.data, " ");
        print("\n=======\n");
      }
      if (contains(tokens[i].type, validOperandTypes)) {
        outStack.push_back(tokens[i]);
      } else if (tokens[i].type == OPERATOR) {
        /*
        * This prevents crash when there's no operators.
        * Or when it found a parenthesis, because they're not really operators.
        */
        if (opStack.size() == 0 || opStack.back().data == "(") {
          opStack.push_back(tokens[i]);
          continue;
        }
        Operator current = *static_cast<Operator*>(tokens[i].typeData);
        Operator topOfStack = *static_cast<Operator*>(opStack.back().typeData);
        while (opStack.size() != 0) {
          if ((current.getAssociativity() == ASSOCIATE_FROM_LEFT && current.getPrecedence() <= topOfStack.getPrecedence()) ||
          (current.getAssociativity() == ASSOCIATE_FROM_RIGHT && current.getPrecedence() < topOfStack.getPrecedence())) {
            popToOut();
          } else break;
          // Non-operators (eg parenthesis) will crash on next line, and must break to properly evaluate expression
          if (opStack.back().type != OPERATOR) break;
          // Get new top of stack
          if (opStack.size() != 0) topOfStack = *static_cast<Operator*>(opStack.back().typeData);
        }
        opStack.push_back(tokens[i]);
      } else if (tokens[i].type == CONSTRUCT) {
        if (tokens[i].data == ";") break;
        if (tokens[i].data != "(" && tokens[i].data != ")") {
          throw SyntaxError("Illegal construct in expression. \"" + tokens[i].data + "\"", tokens[i].line);
        } else if (tokens[i].data == "(") {
          opStack.push_back(tokens[i]);
        } else if (tokens[i].data == ")") {
          while (opStack.size() != 0 && opStack.back().data != "(") popToOut();
          if (opStack.back().data != "(") throw SyntaxError("Mismatched parenthesis in expression", outStack.back().line);
          opStack.pop_back(); // Get rid of "("
          if (opStack.back().type == FUNCTION) popToOut();
        }
      }
    }
    while (opStack.size() > 0) popToOut();
  }

  std::vector<Token> ExpressionNode::getRPNOutput() {
    return outStack;
  }

  void ExpressionNode::buildSubtree(void) {
    std::vector<Token> stackCopy(outStack);
    ExpressionChildNode* node;
    if (stackCopy.size() >= 1) {
      auto tok = stackCopy.back();
      stackCopy.pop_back();
      node = new ExpressionChildNode(tok, stackCopy);
    } else {
      throw std::runtime_error("Empty expression.\n");
    }

    this->addChild(node);
  }

  std::string ExpressionNode::getNodeType() {
    return "ExpressionNode";
  }

  void ExpressionNode::printTree(int level) {
    auto top = static_cast<ExpressionChildNode*>(this->getChildren()[0]);
    top->printTree(level);
  }

  ExpressionChildNode::ExpressionChildNode(Token operand): t(operand) {};
  ExpressionChildNode::ExpressionChildNode(Token op, std::vector<Token>& operands): t(op) {
    if (operands.size() == 0) return;
    auto arity = static_cast<Operator*>(op.typeData)->getArity();
    for (int i = 0; i < arity; ++i) {
      auto next = operands[operands.size() - 1];
      if (next.type == OPERATOR) {
        operands.pop_back();
        auto branch = new ExpressionChildNode(next, operands);
        this->addChild(branch);
      } else {
        operands.pop_back();
        auto leaf = new ExpressionChildNode(next);
        this->addChild(leaf);
      }
    }
  };

  std::string ExpressionChildNode::getNodeType() {
    return "ExpressionChildNode";
  }

  void ExpressionChildNode::printTree(int level) {
    printIndent(level);
    print(this->t, "\n");
    for (auto child : this->getChildren()) {
      static_cast<ExpressionChildNode*>(child)->printTree(level + 1);
    }
  }

  BlockNode::BlockNode() {}

  std::string BlockNode::getNodeType() {
    return "BlockNode";
  }

  void BlockNode::printTree(int level) {
    printIndent(level);
    print("BlockNode\n");
    for (auto node : children) {
      node->printTree(level + 1);
    }
  }

  ConditionalNode::ConditionalNode(ExpressionNode* condition, BlockNode* trueBlock, BlockNode* falseBlock) {
    this->children.push_back(condition);
    this->children.push_back(trueBlock);
    this->children.push_back(falseBlock);
    condition->setParent(this);
    trueBlock->setParent(this);
    falseBlock->setParent(this);
  }

  ExpressionNode* ConditionalNode::getCondition() {return dynamic_cast<ExpressionNode*>(children[0]);}
  BlockNode* ConditionalNode::getTrueBlock() {return dynamic_cast<BlockNode*>(children[1]);}
  BlockNode* ConditionalNode::getFalseBlock() {return dynamic_cast<BlockNode*>(children[2]);}

  void ConditionalNode::addChild(ASTNode* child) {
    children[this->block]->addChild(child);
  }

  void ConditionalNode::nextBlock() {
    static bool wasCalled = false;
    if (!wasCalled) {
      wasCalled = true;
      this->block++;
    } else throw SyntaxError("Multiple else statements.\n", children[2]->getLineNumber());
  }

  std::string ConditionalNode::getNodeType() {
    return "ConditionalNode";
  }

  void ConditionalNode::printTree(int level) {
    printIndent(level);
    print("Condition\n");
    this->getCondition()->printTree(level + 1);
  }

  AST::AbstractSyntaxTree() {}

  void AST::addRootChild(ASTNode* node) {
    root.addChild(node);
  }

  ChildrenNodes AST::getRootChildren() {
    return root.getChildren();
  }

} /* namespace lang */
<commit_msg>Improved newline detection in ExprNode<commit_after>#include "nodes.hpp"

namespace lang {

  void printIndent(int level) {
    for (int i = 0; i < level; ++i) print("  ");
  }

  ASTNode::ASTNode() {}
  ASTNode::~ASTNode() {}

  void ASTNode::addChild(ASTNode* child) {
    child->setParent(this);
    children.push_back(child);
  }

  std::vector<ASTNode*>& ASTNode::getChildren() {
    return children;
  }

  void ASTNode::setParent(ASTNode* parent) {
    this->parent = parent;
  }
  ASTNode* ASTNode::getParent() {
    return parent;
  }

  void ASTNode::setLineNumber(int lines) {
    this->lines = lines;
  }
  int ASTNode::getLineNumber() {
    return this->lines;
  }

  std::string ASTNode::getNodeType() {
    return "ASTNode";
  }

  void ASTNode::printTree(int level) {
    printIndent(level);
    print("Plain ASTNode");
    for (auto child : children) {
      child->printTree(level + 1);
    }
  }

  SingleChildNode::SingleChildNode() {};
  void SingleChildNode::addChild(ASTNode* child) {
    if (this->getChildren().size() >= 1) throw std::runtime_error("Trying to add more than one child to SingleChildNode.");
    else {
      this->ASTNode::addChild(child);
    }
  }

  ASTNode* SingleChildNode::getChild() {
    return children[0];
  }

  std::string SingleChildNode::getNodeType() {
    return "SingleChildNode";
  }

  void SingleChildNode::printTree(int level) {
    printIndent(level);
    auto child = dynamic_cast<SingleChildNode*>(this->getChild());
    if (child == nullptr) {
      print("SingleChildNode, empty", "\n");
      return;
    }
    print("SingleChildNode with: ", child, "\n");
    child->printTree(level + 1);
  }

  DeclarationNode::DeclarationNode(std::string typeName, Token identifier) {
    this->typeName = typeName;
    this->identifier = identifier;
  }

  void DeclarationNode::addChild(ASTNode* child) {
    auto node = dynamic_cast<ExpressionNode*>(child);
    if (node == 0) throw std::invalid_argument("DeclarationNode only accepts an ExpressionNode as its child.");
    this->SingleChildNode::addChild(node);
  }

  std::string DeclarationNode::getNodeType() {
    return "DeclarationNode";
  }

  void DeclarationNode::printTree(int level) {
    printIndent(level);
    print("Declared ", this->typeName, " as ", this->identifier, "\n");
    if (this->getChildren().size() == 1) dynamic_cast<ExpressionNode*>(this->getChild())->printTree(level + 1);
  }

  std::vector<TokenType> ExpressionNode::validOperandTypes {
    INTEGER, FLOAT, STRING, BOOLEAN, ARRAY, TYPE, VARIABLE, FUNCTION, UNPROCESSED
  };

  ExpressionNode::ExpressionNode(std::vector<Token>& tokens) {
    for (uint64 i = 0; i < tokens.size(); ++i) {
      if (EXPRESSION_STEPS) {
        for (auto tok : outStack) print(tok.data, " ");
        print("\n-------\n");
        for (auto tok : opStack) print(tok.data, " ");
        print("\n=======\n");
      }
      if (contains(tokens[i].type, validOperandTypes)) {
        outStack.push_back(tokens[i]);
      } else if (tokens[i].type == OPERATOR) {
        /*
        * This prevents crash when there's no operators.
        * Or when it found a parenthesis, because they're not really operators.
        */
        if (opStack.size() == 0 || opStack.back().data == "(") {
          opStack.push_back(tokens[i]);
          continue;
        }
        Operator current = *static_cast<Operator*>(tokens[i].typeData);
        Operator topOfStack = *static_cast<Operator*>(opStack.back().typeData);
        while (opStack.size() != 0) {
          if ((current.getAssociativity() == ASSOCIATE_FROM_LEFT && current.getPrecedence() <= topOfStack.getPrecedence()) ||
          (current.getAssociativity() == ASSOCIATE_FROM_RIGHT && current.getPrecedence() < topOfStack.getPrecedence())) {
            popToOut();
          } else break;
          // Non-operators (eg parenthesis) will crash on next line, and must break to properly evaluate expression
          if (opStack.back().type != OPERATOR) break;
          // Get new top of stack
          if (opStack.size() != 0) topOfStack = *static_cast<Operator*>(opStack.back().typeData);
        }
        opStack.push_back(tokens[i]);
      } else if (tokens[i].type == CONSTRUCT) {
        if (isNewLine(tokens[i])) break;
        if (tokens[i].data != "(" && tokens[i].data != ")") {
          throw SyntaxError("Illegal construct in expression. \"" + tokens[i].data + "\"", tokens[i].line);
        } else if (tokens[i].data == "(") {
          opStack.push_back(tokens[i]);
        } else if (tokens[i].data == ")") {
          while (opStack.size() != 0 && opStack.back().data != "(") popToOut();
          if (opStack.back().data != "(") throw SyntaxError("Mismatched parenthesis in expression", outStack.back().line);
          opStack.pop_back(); // Get rid of "("
          if (opStack.back().type == FUNCTION) popToOut();
        }
      }
    }
    while (opStack.size() > 0) popToOut();
  }

  std::vector<Token> ExpressionNode::getRPNOutput() {
    return outStack;
  }

  void ExpressionNode::buildSubtree(void) {
    std::vector<Token> stackCopy(outStack);
    ExpressionChildNode* node;
    if (stackCopy.size() >= 1) {
      auto tok = stackCopy.back();
      stackCopy.pop_back();
      node = new ExpressionChildNode(tok, stackCopy);
    } else {
      throw std::runtime_error("Empty expression.\n");
    }

    this->addChild(node);
  }

  std::string ExpressionNode::getNodeType() {
    return "ExpressionNode";
  }

  void ExpressionNode::printTree(int level) {
    auto top = static_cast<ExpressionChildNode*>(this->getChildren()[0]);
    top->printTree(level);
  }

  ExpressionChildNode::ExpressionChildNode(Token operand): t(operand) {};
  ExpressionChildNode::ExpressionChildNode(Token op, std::vector<Token>& operands): t(op) {
    if (operands.size() == 0) return;
    auto arity = static_cast<Operator*>(op.typeData)->getArity();
    for (int i = 0; i < arity; ++i) {
      auto next = operands[operands.size() - 1];
      if (next.type == OPERATOR) {
        operands.pop_back();
        auto branch = new ExpressionChildNode(next, operands);
        this->addChild(branch);
      } else {
        operands.pop_back();
        auto leaf = new ExpressionChildNode(next);
        this->addChild(leaf);
      }
    }
  };

  std::string ExpressionChildNode::getNodeType() {
    return "ExpressionChildNode";
  }

  void ExpressionChildNode::printTree(int level) {
    printIndent(level);
    print(this->t, "\n");
    for (auto child : this->getChildren()) {
      static_cast<ExpressionChildNode*>(child)->printTree(level + 1);
    }
  }

  BlockNode::BlockNode() {}

  std::string BlockNode::getNodeType() {
    return "BlockNode";
  }

  void BlockNode::printTree(int level) {
    printIndent(level);
    print("BlockNode\n");
    for (auto node : children) {
      node->printTree(level + 1);
    }
  }

  ConditionalNode::ConditionalNode(ExpressionNode* condition, BlockNode* trueBlock, BlockNode* falseBlock) {
    this->children.push_back(condition);
    this->children.push_back(trueBlock);
    this->children.push_back(falseBlock);
    condition->setParent(this);
    trueBlock->setParent(this);
    falseBlock->setParent(this);
  }

  ExpressionNode* ConditionalNode::getCondition() {return dynamic_cast<ExpressionNode*>(children[0]);}
  BlockNode* ConditionalNode::getTrueBlock() {return dynamic_cast<BlockNode*>(children[1]);}
  BlockNode* ConditionalNode::getFalseBlock() {return dynamic_cast<BlockNode*>(children[2]);}

  void ConditionalNode::addChild(ASTNode* child) {
    children[this->block]->addChild(child);
  }

  void ConditionalNode::nextBlock() {
    static bool wasCalled = false;
    if (!wasCalled) {
      wasCalled = true;
      this->block++;
    } else throw SyntaxError("Multiple else statements.\n", children[2]->getLineNumber());
  }

  std::string ConditionalNode::getNodeType() {
    return "ConditionalNode";
  }

  void ConditionalNode::printTree(int level) {
    printIndent(level);
    print("Condition\n");
    this->getCondition()->printTree(level + 1);
  }

  AST::AbstractSyntaxTree() {}

  void AST::addRootChild(ASTNode* node) {
    root.addChild(node);
  }

  ChildrenNodes AST::getRootChildren() {
    return root.getChildren();
  }

} /* namespace lang */
<|endoftext|>


<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2011 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "GLTexture.h"

#include "../base/Exception.h"
#include "../base/StringHelper.h"
#include "../base/MathHelper.h"
#include "../base/ObjectCounter.h"

#include "GLContext.h"
#include "TextureMover.h"
#ifndef AVG_ENABLE_EGL
    #include "PBO.h"
#endif
#include "FBO.h"
#include "Filterfliprgb.h"

#include <string.h>
#include <iostream>

namespace avg {

using namespace std;

// We assign our own texture ids and never reuse them instead of using glGenTextures.
// That works very well, except that other components (e.g. Ogre3d) with shared gl
// contexts don't know anything about our ids and thus use the same ones.
// Somewhat hackish solution: Assign ids starting with a very high id, so the id ranges
// don't overlap.
unsigned GLTexture::s_LastTexID = 10000000;

GLTexture::GLTexture(const IntPoint& size, PixelFormat pf, bool bMipmap,
        int potBorderColor, unsigned wrapSMode, unsigned wrapTMode, bool bForcePOT)
    : m_Size(size),
      m_pf(pf),
      m_bMipmap(bMipmap),
      m_bDeleteTex(true),
      m_bIsDirty(true)
{
    m_pGLContext = GLContext::getCurrent();
    ObjectCounter::get()->incRef(&typeid(*this));
    m_bUsePOT = m_pGLContext->usePOTTextures() || bForcePOT;
    if (m_pGLContext->isGLES() && bMipmap) {
        m_bUsePOT = true;
    }
    if (m_bUsePOT) {
        m_GLSize.x = nextpow2(m_Size.x);
        m_GLSize.y = nextpow2(m_Size.y);
    } else {
        m_GLSize = m_Size;
    }

    int maxTexSize = m_pGLContext->getMaxTexSize();
    if (m_Size.x > maxTexSize || m_Size.y > maxTexSize) {
        throw Exception(AVG_ERR_VIDEO_GENERAL, "Texture too large ("  + toString(m_Size)
                + "). Maximum supported by graphics card is "
                + toString(maxTexSize));
    }
    if (getGLType(m_pf) == GL_FLOAT && !isFloatFormatSupported()) {
        throw Exception(AVG_ERR_UNSUPPORTED,
                "Float textures not supported by OpenGL configuration.");
    }

    s_LastTexID++;
    m_TexID = s_LastTexID;
    m_pGLContext->bindTexture(GL_TEXTURE0, m_TexID);
    if (bMipmap) {
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    } else {
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    }
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapSMode);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapTMode);
    glTexImage2D(GL_TEXTURE_2D, 0, getGLInternalFormat(), m_GLSize.x, m_GLSize.y, 0,
            getGLFormat(m_pf), getGLType(m_pf), 0);
    GLContext::checkError("GLTexture: glTexImage2D()");

    if (m_bUsePOT) {
        // Make sure the texture is transparent and black before loading stuff
        // into it to avoid garbage at the borders.
        // In the case of UV textures, we set the border color to 128...
        int TexMemNeeded = m_GLSize.x*m_GLSize.y*getBytesPerPixel(m_pf);
        char * pPixels = new char[TexMemNeeded];
        memset(pPixels, potBorderColor, TexMemNeeded);
        glTexImage2D(GL_TEXTURE_2D, 0, getGLInternalFormat(), m_GLSize.x,
                m_GLSize.y, 0, getGLFormat(m_pf), getGLType(m_pf),
                pPixels);
        GLContext::checkError("PBOTexture::createTexture: glTexImage2D()");
        delete[] pPixels;
    }
}

GLTexture::GLTexture(unsigned glTexID, const IntPoint& size, PixelFormat pf, bool bMipmap,
        bool bDeleteTex)
    : m_Size(size),
      m_GLSize(size),
      m_pf(pf),
      m_bMipmap(bMipmap),
      m_bDeleteTex(bDeleteTex),
      m_bUsePOT(false),
      m_TexID(glTexID),
      m_bIsDirty(true)
{
    m_pGLContext = GLContext::getCurrent();
    ObjectCounter::get()->incRef(&typeid(*this));
}

GLTexture::~GLTexture()
{
    if (m_bDeleteTex) {
        glDeleteTextures(1, &m_TexID);
        GLContext::checkError("GLTexture: DeleteTextures()");
    }
    ObjectCounter::get()->decRef(&typeid(*this));
}

void GLTexture::activate(int textureUnit)
{
    m_pGLContext->bindTexture(textureUnit, m_TexID);
}

void GLTexture::generateMipmaps()
{
    if (m_bMipmap) {
        activate();
        glproc::GenerateMipmap(GL_TEXTURE_2D);
        GLContext::checkError("GLTexture::generateMipmaps()");
    }
}

void GLTexture::setWrapMode(unsigned wrapSMode, unsigned wrapTMode)
{
    activate();
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapSMode);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapTMode);
}

void GLTexture::enableStreaming()
{
    m_pMover = TextureMover::create(m_Size, m_pf, GL_STREAM_DRAW);
}

BitmapPtr GLTexture::lockStreamingBmp()
{
    AVG_ASSERT(m_pMover);
    return m_pMover->lock();
}

void GLTexture::unlockStreamingBmp(bool bUpdated)
{
    AVG_ASSERT(m_pMover);
    m_pMover->unlock();
    if (bUpdated) {
        m_pMover->moveToTexture(*this);
        m_bIsDirty = true;
    }
}

void GLTexture::moveBmpToTexture(BitmapPtr pBmp)
{
    TextureMoverPtr pMover = TextureMover::create(m_Size, m_pf, GL_DYNAMIC_DRAW);
    pMover->moveBmpToTexture(pBmp, *this);
    m_bIsDirty = true;
}

BitmapPtr GLTexture::moveTextureToBmp(int mipmapLevel)
{
    GLContext* pContext = GLContext::getCurrent();
    if (pContext->getMemoryMode() == MM_PBO) {
#ifdef AVG_ENABLE_EGL
        AVG_ASSERT(false);
        return BitmapPtr();
#else
        return PBO(m_GLSize, m_pf, GL_DYNAMIC_READ).moveTextureToBmp(*this, mipmapLevel);
#endif
    } else {
        unsigned fbo = pContext->genFBO();
        glproc::BindFramebuffer(GL_FRAMEBUFFER, fbo);
        glproc::FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                GL_TEXTURE_2D, m_TexID, mipmapLevel);
        FBO::checkError("moveTextureToBmp");
        IntPoint size = getMipmapSize(mipmapLevel);
        BitmapPtr pBmp(new Bitmap(size, m_pf));
        int glPixelFormat = getGLReadFormat(m_pf);
        glReadPixels(0, 0, size.x, size.y, glPixelFormat, getGLType(m_pf),
                pBmp->getPixels());
        if (m_pf == R8G8B8A8 || m_pf == R8G8B8 || pContext->isGLES()) {
            FilterFlipRGB(!pContext->isGLES()).applyInPlace(pBmp);
        }
        GLContext::checkError("GLTexture::moveTextureToBmp: glReadPixels()");
        glproc::FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                GL_TEXTURE_2D, 0, 0);
        pContext->returnFBOToCache(fbo);
        return pBmp;
    }
}

const IntPoint& GLTexture::getSize() const
{
    return m_Size;
}

const IntPoint& GLTexture::getGLSize() const
{
    return m_GLSize;
}

PixelFormat GLTexture::getPF() const
{
    return m_pf;
}

unsigned GLTexture::getID() const
{
    return m_TexID;
}

IntPoint GLTexture::getMipmapSize(int level) const
{
    IntPoint size = m_Size;
    for (int i=0; i<level; ++i) {
        size.x = max(1, size.x >> 1);
        size.y = max(1, size.y >> 1);
    }
    return size;
}

bool GLTexture::isFloatFormatSupported()
{
    return queryOGLExtension("GL_ARB_texture_float");
}

int GLTexture::getGLFormat(PixelFormat pf)
{
    switch (pf) {
        case I8:
        case I32F:
            return GL_LUMINANCE;
        case A8:
            return GL_ALPHA;
        case R8G8B8A8:
        case R8G8B8X8:
            return GL_RGBA;
#ifdef AVG_ENABLE_EGL
        case B8G8R8A8:
        case B8G8R8X8:
            return GL_BGRA_EXT;
#else
        case B8G8R8A8:
        case B8G8R8X8:
            return GL_BGRA;
        case R32G32B32A32F:
            return GL_BGRA;
#endif
        case B5G6R5:
            return GL_RGB;
        default:
            AVG_ASSERT(false);
            return 0;
    }
}

int GLTexture::getGLReadFormat(PixelFormat pf)
{
    int glPixelFormat = getGLFormat(pf);
#ifdef AVG_ENABLE_EGL
    if (glPixelFormat == GL_BGRA_EXT) {
        glPixelFormat = GL_RGBA;
    }
#endif
    return glPixelFormat;
}

int GLTexture::getGLType(PixelFormat pf)
{
    switch (pf) {
        case I8:
        case A8:
            return GL_UNSIGNED_BYTE;
        case R8G8B8A8:
        case R8G8B8X8:
        case B8G8R8A8:
        case B8G8R8X8:
#ifdef __APPLE__
            return GL_UNSIGNED_INT_8_8_8_8_REV;
#else
            return GL_UNSIGNED_BYTE;
#endif
        case R32G32B32A32F:
        case I32F:
            return GL_FLOAT;
        case B5G6R5:
            return GL_UNSIGNED_SHORT_5_6_5;
        default:
            AVG_ASSERT(false);
            return 0;
    }
}

int GLTexture::getGLInternalFormat() const
{
    switch (m_pf) {
        case I8:
            return GL_LUMINANCE;
        case A8:
            return GL_ALPHA;
        case R8G8B8A8:
        case R8G8B8X8:
            return GL_RGBA;
#ifdef AVG_ENABLE_EGL
        case B8G8R8A8:
        case B8G8R8X8:
            return GL_BGRA_EXT;
#else
        case B8G8R8A8:
        case B8G8R8X8:
            return GL_RGBA;
        case R32G32B32A32F:
            return GL_RGBA32F_ARB;
        case I32F:
            return GL_LUMINANCE32F_ARB;
#endif
        case B5G6R5:
            return GL_RGB;
        default:
            AVG_ASSERT(false);
            return 0;
    }
}

void GLTexture::setDirty()
{
    m_bIsDirty = true;
}

bool GLTexture::isDirty() const
{
    return m_bIsDirty;
}

void GLTexture::resetDirty()
{
    m_bIsDirty = false;
}

}
<commit_msg>egl branch: Fixed nvidia glx tests.<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2011 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "GLTexture.h"

#include "../base/Exception.h"
#include "../base/StringHelper.h"
#include "../base/MathHelper.h"
#include "../base/ObjectCounter.h"

#include "GLContext.h"
#include "TextureMover.h"
#ifndef AVG_ENABLE_EGL
    #include "PBO.h"
#endif
#include "FBO.h"
#include "Filterfliprgb.h"

#include <string.h>
#include <iostream>

namespace avg {

using namespace std;

// We assign our own texture ids and never reuse them instead of using glGenTextures.
// That works very well, except that other components (e.g. Ogre3d) with shared gl
// contexts don't know anything about our ids and thus use the same ones.
// Somewhat hackish solution: Assign ids starting with a very high id, so the id ranges
// don't overlap.
unsigned GLTexture::s_LastTexID = 10000000;

GLTexture::GLTexture(const IntPoint& size, PixelFormat pf, bool bMipmap,
        int potBorderColor, unsigned wrapSMode, unsigned wrapTMode, bool bForcePOT)
    : m_Size(size),
      m_pf(pf),
      m_bMipmap(bMipmap),
      m_bDeleteTex(true),
      m_bIsDirty(true)
{
    m_pGLContext = GLContext::getCurrent();
    ObjectCounter::get()->incRef(&typeid(*this));
    m_bUsePOT = m_pGLContext->usePOTTextures() || bForcePOT;
    if (m_pGLContext->isGLES() && bMipmap) {
        m_bUsePOT = true;
    }
    if (m_bUsePOT) {
        m_GLSize.x = nextpow2(m_Size.x);
        m_GLSize.y = nextpow2(m_Size.y);
    } else {
        m_GLSize = m_Size;
    }

    int maxTexSize = m_pGLContext->getMaxTexSize();
    if (m_Size.x > maxTexSize || m_Size.y > maxTexSize) {
        throw Exception(AVG_ERR_VIDEO_GENERAL, "Texture too large ("  + toString(m_Size)
                + "). Maximum supported by graphics card is "
                + toString(maxTexSize));
    }
    if (getGLType(m_pf) == GL_FLOAT && !isFloatFormatSupported()) {
        throw Exception(AVG_ERR_UNSUPPORTED,
                "Float textures not supported by OpenGL configuration.");
    }

    s_LastTexID++;
    m_TexID = s_LastTexID;
    m_pGLContext->bindTexture(GL_TEXTURE0, m_TexID);
    if (bMipmap) {
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    } else {
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    }
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapSMode);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapTMode);
    glTexImage2D(GL_TEXTURE_2D, 0, getGLInternalFormat(), m_GLSize.x, m_GLSize.y, 0,
            getGLFormat(m_pf), getGLType(m_pf), 0);
    GLContext::checkError("GLTexture: glTexImage2D()");

    if (m_bUsePOT) {
        // Make sure the texture is transparent and black before loading stuff
        // into it to avoid garbage at the borders.
        // In the case of UV textures, we set the border color to 128...
        int TexMemNeeded = m_GLSize.x*m_GLSize.y*getBytesPerPixel(m_pf);
        char * pPixels = new char[TexMemNeeded];
        memset(pPixels, potBorderColor, TexMemNeeded);
        glTexImage2D(GL_TEXTURE_2D, 0, getGLInternalFormat(), m_GLSize.x,
                m_GLSize.y, 0, getGLFormat(m_pf), getGLType(m_pf),
                pPixels);
        GLContext::checkError("PBOTexture::createTexture: glTexImage2D()");
        delete[] pPixels;
    }
}

GLTexture::GLTexture(unsigned glTexID, const IntPoint& size, PixelFormat pf, bool bMipmap,
        bool bDeleteTex)
    : m_Size(size),
      m_GLSize(size),
      m_pf(pf),
      m_bMipmap(bMipmap),
      m_bDeleteTex(bDeleteTex),
      m_bUsePOT(false),
      m_TexID(glTexID),
      m_bIsDirty(true)
{
    m_pGLContext = GLContext::getCurrent();
    ObjectCounter::get()->incRef(&typeid(*this));
}

GLTexture::~GLTexture()
{
    if (m_bDeleteTex) {
        glDeleteTextures(1, &m_TexID);
        GLContext::checkError("GLTexture: DeleteTextures()");
    }
    ObjectCounter::get()->decRef(&typeid(*this));
}

void GLTexture::activate(int textureUnit)
{
    m_pGLContext->bindTexture(textureUnit, m_TexID);
}

void GLTexture::generateMipmaps()
{
    if (m_bMipmap) {
        activate();
        glproc::GenerateMipmap(GL_TEXTURE_2D);
        GLContext::checkError("GLTexture::generateMipmaps()");
    }
}

void GLTexture::setWrapMode(unsigned wrapSMode, unsigned wrapTMode)
{
    activate();
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapSMode);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapTMode);
}

void GLTexture::enableStreaming()
{
    m_pMover = TextureMover::create(m_Size, m_pf, GL_STREAM_DRAW);
}

BitmapPtr GLTexture::lockStreamingBmp()
{
    AVG_ASSERT(m_pMover);
    return m_pMover->lock();
}

void GLTexture::unlockStreamingBmp(bool bUpdated)
{
    AVG_ASSERT(m_pMover);
    m_pMover->unlock();
    if (bUpdated) {
        m_pMover->moveToTexture(*this);
        m_bIsDirty = true;
    }
}

void GLTexture::moveBmpToTexture(BitmapPtr pBmp)
{
    TextureMoverPtr pMover = TextureMover::create(m_Size, m_pf, GL_DYNAMIC_DRAW);
    pMover->moveBmpToTexture(pBmp, *this);
    m_bIsDirty = true;
}

BitmapPtr GLTexture::moveTextureToBmp(int mipmapLevel)
{
    GLContext* pContext = GLContext::getCurrent();
    if (pContext->getMemoryMode() == MM_PBO) {
#ifdef AVG_ENABLE_EGL
        AVG_ASSERT(false);
        return BitmapPtr();
#else
        return PBO(m_GLSize, m_pf, GL_DYNAMIC_READ).moveTextureToBmp(*this, mipmapLevel);
#endif
    } else {
        unsigned fbo = pContext->genFBO();
        glproc::BindFramebuffer(GL_FRAMEBUFFER, fbo);
        glproc::FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                GL_TEXTURE_2D, m_TexID, mipmapLevel);
        FBO::checkError("moveTextureToBmp");
        IntPoint size = getMipmapSize(mipmapLevel);
        BitmapPtr pBmp(new Bitmap(size, m_pf));
        int glPixelFormat = getGLReadFormat(m_pf);
        glReadPixels(0, 0, size.x, size.y, glPixelFormat, getGLType(m_pf),
                pBmp->getPixels());
        if (m_pf == R8G8B8A8 || m_pf == R8G8B8 || pContext->isGLES()) {
            FilterFlipRGB(!pContext->isGLES()).applyInPlace(pBmp);
        }
        GLContext::checkError("GLTexture::moveTextureToBmp: glReadPixels()");
        glproc::FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                GL_TEXTURE_2D, 0, 0);
        pContext->returnFBOToCache(fbo);
        return pBmp;
    }
}

const IntPoint& GLTexture::getSize() const
{
    return m_Size;
}

const IntPoint& GLTexture::getGLSize() const
{
    return m_GLSize;
}

PixelFormat GLTexture::getPF() const
{
    return m_pf;
}

unsigned GLTexture::getID() const
{
    return m_TexID;
}

IntPoint GLTexture::getMipmapSize(int level) const
{
    IntPoint size = m_Size;
    for (int i=0; i<level; ++i) {
        size.x = max(1, size.x >> 1);
        size.y = max(1, size.y >> 1);
    }
    return size;
}

bool GLTexture::isFloatFormatSupported()
{
    return queryOGLExtension("GL_ARB_texture_float");
}

int GLTexture::getGLFormat(PixelFormat pf)
{
    switch (pf) {
        case I8:
        case I32F:
            return GL_LUMINANCE;
        case A8:
            return GL_ALPHA;
        case R8G8B8A8:
        case R8G8B8X8:
            return GL_RGBA;
#ifdef AVG_ENABLE_EGL
        case B8G8R8A8:
        case B8G8R8X8:
            return GL_BGRA_EXT;
#else
        case B8G8R8A8:
        case B8G8R8X8:
            return GL_BGRA;
        case R32G32B32A32F:
            return GL_BGRA;
#endif
        case B5G6R5:
            return GL_RGB;
        default:
            AVG_ASSERT(false);
            return 0;
    }
}

int GLTexture::getGLReadFormat(PixelFormat pf)
{
    int glPixelFormat = getGLFormat(pf);
    if (GLContext::getCurrent()->isGLES()) {
        if (glPixelFormat == GL_BGRA_EXT) {
            glPixelFormat = GL_RGBA;
        }
    }
    return glPixelFormat;
}

int GLTexture::getGLType(PixelFormat pf)
{
    switch (pf) {
        case I8:
        case A8:
            return GL_UNSIGNED_BYTE;
        case R8G8B8A8:
        case R8G8B8X8:
        case B8G8R8A8:
        case B8G8R8X8:
#ifdef __APPLE__
            return GL_UNSIGNED_INT_8_8_8_8_REV;
#else
            return GL_UNSIGNED_BYTE;
#endif
        case R32G32B32A32F:
        case I32F:
            return GL_FLOAT;
        case B5G6R5:
            return GL_UNSIGNED_SHORT_5_6_5;
        default:
            AVG_ASSERT(false);
            return 0;
    }
}

int GLTexture::getGLInternalFormat() const
{
    switch (m_pf) {
        case I8:
            return GL_LUMINANCE;
        case A8:
            return GL_ALPHA;
        case R8G8B8A8:
        case R8G8B8X8:
            return GL_RGBA;
#ifdef AVG_ENABLE_EGL
        case B8G8R8A8:
        case B8G8R8X8:
            return GL_BGRA_EXT;
#else
        case B8G8R8A8:
        case B8G8R8X8:
            return GL_RGBA;
        case R32G32B32A32F:
            return GL_RGBA32F_ARB;
        case I32F:
            return GL_LUMINANCE32F_ARB;
#endif
        case B5G6R5:
            return GL_RGB;
        default:
            AVG_ASSERT(false);
            return 0;
    }
}

void GLTexture::setDirty()
{
    m_bIsDirty = true;
}

bool GLTexture::isDirty() const
{
    return m_bIsDirty;
}

void GLTexture::resetDirty()
{
    m_bIsDirty = false;
}

}
<|endoftext|>


<commit_before>#include "./ha_buffer.h"
#include <iostream>
#include <algorithm>
#include "./shader_program.h"
#include "./quad.h"

namespace Graphics
{

HABuffer::HABuffer(Eigen::Vector2i size) : size(size)
{
  offsets = new unsigned int[512];
}

HABuffer::~HABuffer()
{
  delete[] offsets;
}

void HABuffer::initialize(Gl *gl)
{
  this->gl = gl;

  quad = std::make_shared<Quad>();
  quad->skipSettingUniforms = true;
  quad->initialize(gl);

  initializeShadersHash();
  initializeBufferHash();
}

void HABuffer::initializeShadersHash()
{
  printf("initShaders %d %d\n", size(0), size(1));

  renderShader = std::make_shared<ShaderProgram>(
      gl, ":shader/renderHABuffer.vert", ":shader/renderHABuffer.frag");
  clearShader = std::make_shared<ShaderProgram>(
      gl, ":shader/clearHABuffer.vert", ":shader/clearHABuffer.frag");
}

void HABuffer::initializeBufferHash()
{
  habufferScreenSize = std::max(size[0], size[1]);
  uint num_records = habufferScreenSize * habufferScreenSize * 8;
  habufferTableSize =
      std::max(habufferScreenSize,
               static_cast<uint>(ceil(sqrt(static_cast<float>(num_records)))));
  habufferNumRecords = habufferTableSize * habufferTableSize;
  habufferCountsSize = habufferScreenSize * habufferScreenSize + 1;
  printf("HA-Buffer: Screen size: %d %d\n"
         "             # records: %d (%d x %d)\n",
         size.x(), size.y(), habufferNumRecords, habufferTableSize,
         habufferTableSize);

  // HA-Buffer records
  if (!RecordsBuffer.isInitialized())
    RecordsBuffer.initialize(gl, habufferNumRecords * sizeof(uint) * 2);
  else
    RecordsBuffer.resize(habufferNumRecords * sizeof(uint) * 2);

  if (!CountsBuffer.isInitialized())
    CountsBuffer.initialize(gl, habufferCountsSize * sizeof(uint));
  else
    CountsBuffer.resize(habufferCountsSize * sizeof(uint));

  if (!FragmentDataBuffer.isInitialized())
    FragmentDataBuffer.initialize(gl,
                                  habufferNumRecords * sizeof(FragmentData));
  else
    FragmentDataBuffer.resize(habufferNumRecords * sizeof(FragmentData));

  // clear counts
  CountsBuffer.clear(0);

  gl->glMemoryBarrier(GL_ALL_BARRIER_BITS);

  printf("[HABuffer] Memory usage: %.2fMB",
         ((habufferNumRecords * sizeof(uint) * 2 +
           habufferNumRecords * sizeof(FragmentData) +
           (habufferScreenSize * habufferScreenSize + 1) * sizeof(uint)) /
          1024) /
             1024.0f);
}

void HABuffer::begin(const RenderData &renderData)
{
  glAssert(gl->glDisable(GL_CULL_FACE));
  glAssert(gl->glDisable(GL_DEPTH_TEST));
}

bool HABuffer::end()
{
#if 1
  glAssert(gl->glMemoryBarrier(GL_ALL_BARRIER_BITS));
#endif
  glAssert(gl->glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT));

  uint numInserted = 1;
  CountsBuffer.getData(&numInserted, sizeof(uint),
                       CountsBuffer.getSize() - sizeof(uint));

  bool overflow = false;
  if (numInserted >= habufferNumRecords)
  {
    overflow = true;
    printf("Frame was interrupted: %u\n", numInserted);
  }
  else if (numInserted > habufferNumRecords * 0.8)
  {
    printf("inserted %u / %u\n", numInserted, habufferNumRecords);
  }

  displayStatistics("after render");

  return overflow;
}

void HABuffer::render()
{
  renderShader->bind();
  Eigen::Matrix4f identity = Eigen::Matrix4f::Identity();
  renderShader->setUniform("u_Projection", identity);
  renderShader->setUniform("u_View", identity);
  renderShader->setUniform("u_Model", identity);

  renderShader->setUniform("u_ScreenSz", habufferScreenSize);
  renderShader->setUniform("u_HashSz", habufferTableSize);
  renderShader->setUniformAsVec2Array("u_Offsets", offsets, 512);
  renderShader->setUniform("u_Records", RecordsBuffer);
  renderShader->setUniform("u_Counts", CountsBuffer);
  renderShader->setUniform("u_FragmentData", FragmentDataBuffer);

  // Ensure that all global memory write are done before resolving
  glAssert(gl->glMemoryBarrier(GL_SHADER_GLOBAL_ACCESS_BARRIER_BIT_NV));

  glAssert(gl->glDepthMask(GL_FALSE));
  glAssert(gl->glDisable(GL_DEPTH_TEST));

  quad->setShaderProgram(renderShader);
  quad->render(gl, RenderData());

  glAssert(gl->glDepthMask(GL_TRUE));
  glAssert(gl->glEnable(GL_DEPTH_TEST));

  // TODO(SIRK): print timing
  /*
  float tm_threshold = TIMING_THRESHOLD;
  float cleartime = g_TmClear.waitResult();
  float buildtime = g_TmBuild.waitResult();
  float rendertime = g_TmRender.waitResult();
  if (cleartime > tm_threshold ||
      buildtime > tm_threshold ||
      rendertime > tm_threshold)
  {
    printf("Clear time %lf ms\n", cleartime);
    printf("Build time %lf ms\n", buildtime);
    printf("Render time %lf ms\n", rendertime);
  }
  */
}

void HABuffer::clear()
{
  for (int i = 0; i < 512; i++)
  {
    offsets[i] = rand() ^ (rand() << 8) ^ (rand() << 16);
    offsets[i] = offsets[i] % habufferTableSize;
  }

  clearShader->bind();
  clearShader->setUniform("u_NumRecords", habufferNumRecords);
  clearShader->setUniform("u_ScreenSz", habufferScreenSize);
  clearShader->setUniform("u_Records", RecordsBuffer);
  clearShader->setUniform("u_Counts", CountsBuffer);

  // Render the full screen quad

  quad->setShaderProgram(clearShader);
  quad->render(gl, RenderData());

  // Ensure that all global memory write are done before starting to render
  glAssert(gl->glMemoryBarrier(GL_SHADER_GLOBAL_ACCESS_BARRIER_BIT_NV));
}

void HABuffer::setBuildHABufferUniforms(std::shared_ptr<ShaderProgram> shader)
{
  shader->setUniform("u_NumRecords", habufferNumRecords);
  shader->setUniform("u_ScreenSz", habufferScreenSize);
  shader->setUniform("u_HashSz", habufferTableSize);
  shader->setUniformAsVec2Array("u_Offsets", offsets, 512);

  shader->setUniform("u_ZNear", habufferZNear);
  shader->setUniform("u_ZFar", habufferZFar);
  shader->setUniform("Opacity", habufferOpacity);
  shader->setUniform("u_Records", RecordsBuffer);
  shader->setUniform("u_Counts", CountsBuffer);
  shader->setUniform("u_FragmentData", FragmentDataBuffer);
}

void HABuffer::displayStatistics(const char *label)
{
  uint *lcounts = new uint[habufferCountsSize];

  CountsBuffer.getData(lcounts, CountsBuffer.getSize());

  int avgdepth = 0;
  int num = 0;
  for (uint c = 0; c < habufferCountsSize - 1; c++)
  {
    if (lcounts[c] > 0)
    {
      num++;
      avgdepth += lcounts[c];
    }
  }
  if (num == 0)
    num = 1;

  double rec_percentage = lcounts[habufferCountsSize - 1] /
                          static_cast<double>(habufferNumRecords) * 100.0;

  if (rec_percentage > 80.0)
  {
    std::cerr << label << " habufferCountsSize:" << habufferCountsSize
              << "<avg:" << avgdepth / static_cast<float>(num)
              << " max: " << lcounts[habufferCountsSize - 1] << "/"
              << habufferNumRecords << "(" << rec_percentage << "% " << '>'
              << std::endl;
  }

  delete[] lcounts;
}

}  // namespace Graphics
<commit_msg>Fix argument to setUniformAsVec2Array because it is the element count, not the size.<commit_after>#include "./ha_buffer.h"
#include <iostream>
#include <algorithm>
#include "./shader_program.h"
#include "./quad.h"

namespace Graphics
{

HABuffer::HABuffer(Eigen::Vector2i size) : size(size)
{
  offsets = new unsigned int[512];
}

HABuffer::~HABuffer()
{
  delete[] offsets;
}

void HABuffer::initialize(Gl *gl)
{
  this->gl = gl;

  quad = std::make_shared<Quad>();
  quad->skipSettingUniforms = true;
  quad->initialize(gl);

  initializeShadersHash();
  initializeBufferHash();
}

void HABuffer::initializeShadersHash()
{
  printf("initShaders %d %d\n", size(0), size(1));

  renderShader = std::make_shared<ShaderProgram>(
      gl, ":shader/renderHABuffer.vert", ":shader/renderHABuffer.frag");
  clearShader = std::make_shared<ShaderProgram>(
      gl, ":shader/clearHABuffer.vert", ":shader/clearHABuffer.frag");
}

void HABuffer::initializeBufferHash()
{
  habufferScreenSize = std::max(size[0], size[1]);
  uint num_records = habufferScreenSize * habufferScreenSize * 8;
  habufferTableSize =
      std::max(habufferScreenSize,
               static_cast<uint>(ceil(sqrt(static_cast<float>(num_records)))));
  habufferNumRecords = habufferTableSize * habufferTableSize;
  habufferCountsSize = habufferScreenSize * habufferScreenSize + 1;
  printf("HA-Buffer: Screen size: %d %d\n"
         "             # records: %d (%d x %d)\n",
         size.x(), size.y(), habufferNumRecords, habufferTableSize,
         habufferTableSize);

  // HA-Buffer records
  if (!RecordsBuffer.isInitialized())
    RecordsBuffer.initialize(gl, habufferNumRecords * sizeof(uint) * 2);
  else
    RecordsBuffer.resize(habufferNumRecords * sizeof(uint) * 2);

  if (!CountsBuffer.isInitialized())
    CountsBuffer.initialize(gl, habufferCountsSize * sizeof(uint));
  else
    CountsBuffer.resize(habufferCountsSize * sizeof(uint));

  if (!FragmentDataBuffer.isInitialized())
    FragmentDataBuffer.initialize(gl,
                                  habufferNumRecords * sizeof(FragmentData));
  else
    FragmentDataBuffer.resize(habufferNumRecords * sizeof(FragmentData));

  // clear counts
  CountsBuffer.clear(0);

  gl->glMemoryBarrier(GL_ALL_BARRIER_BITS);

  printf("[HABuffer] Memory usage: %.2fMB",
         ((habufferNumRecords * sizeof(uint) * 2 +
           habufferNumRecords * sizeof(FragmentData) +
           (habufferScreenSize * habufferScreenSize + 1) * sizeof(uint)) /
          1024) /
             1024.0f);
}

void HABuffer::begin(const RenderData &renderData)
{
  glAssert(gl->glDisable(GL_CULL_FACE));
  glAssert(gl->glDisable(GL_DEPTH_TEST));
}

bool HABuffer::end()
{
#if 1
  glAssert(gl->glMemoryBarrier(GL_ALL_BARRIER_BITS));
#endif
  glAssert(gl->glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT));

  uint numInserted = 1;
  CountsBuffer.getData(&numInserted, sizeof(uint),
                       CountsBuffer.getSize() - sizeof(uint));

  bool overflow = false;
  if (numInserted >= habufferNumRecords)
  {
    overflow = true;
    printf("Frame was interrupted: %u\n", numInserted);
  }
  else if (numInserted > habufferNumRecords * 0.8)
  {
    printf("inserted %u / %u\n", numInserted, habufferNumRecords);
  }

  displayStatistics("after render");

  return overflow;
}

void HABuffer::render()
{
  renderShader->bind();
  Eigen::Matrix4f identity = Eigen::Matrix4f::Identity();
  renderShader->setUniform("u_Projection", identity);
  renderShader->setUniform("u_View", identity);
  renderShader->setUniform("u_Model", identity);

  renderShader->setUniform("u_ScreenSz", habufferScreenSize);
  renderShader->setUniform("u_HashSz", habufferTableSize);
  renderShader->setUniformAsVec2Array("u_Offsets", offsets, 256);
  renderShader->setUniform("u_Records", RecordsBuffer);
  renderShader->setUniform("u_Counts", CountsBuffer);
  renderShader->setUniform("u_FragmentData", FragmentDataBuffer);

  // Ensure that all global memory write are done before resolving
  glAssert(gl->glMemoryBarrier(GL_SHADER_GLOBAL_ACCESS_BARRIER_BIT_NV));

  glAssert(gl->glDepthMask(GL_FALSE));
  glAssert(gl->glDisable(GL_DEPTH_TEST));

  quad->setShaderProgram(renderShader);
  quad->render(gl, RenderData());

  glAssert(gl->glDepthMask(GL_TRUE));
  glAssert(gl->glEnable(GL_DEPTH_TEST));

  // TODO(SIRK): print timing
  /*
  float tm_threshold = TIMING_THRESHOLD;
  float cleartime = g_TmClear.waitResult();
  float buildtime = g_TmBuild.waitResult();
  float rendertime = g_TmRender.waitResult();
  if (cleartime > tm_threshold ||
      buildtime > tm_threshold ||
      rendertime > tm_threshold)
  {
    printf("Clear time %lf ms\n", cleartime);
    printf("Build time %lf ms\n", buildtime);
    printf("Render time %lf ms\n", rendertime);
  }
  */
}

void HABuffer::clear()
{
  for (int i = 0; i < 512; i++)
  {
    offsets[i] = rand() ^ (rand() << 8) ^ (rand() << 16);
    offsets[i] = offsets[i] % habufferTableSize;
  }

  clearShader->bind();
  clearShader->setUniform("u_NumRecords", habufferNumRecords);
  clearShader->setUniform("u_ScreenSz", habufferScreenSize);
  clearShader->setUniform("u_Records", RecordsBuffer);
  clearShader->setUniform("u_Counts", CountsBuffer);

  // Render the full screen quad

  quad->setShaderProgram(clearShader);
  quad->render(gl, RenderData());

  // Ensure that all global memory write are done before starting to render
  glAssert(gl->glMemoryBarrier(GL_SHADER_GLOBAL_ACCESS_BARRIER_BIT_NV));
}

void HABuffer::setBuildHABufferUniforms(std::shared_ptr<ShaderProgram> shader)
{
  shader->setUniform("u_NumRecords", habufferNumRecords);
  shader->setUniform("u_ScreenSz", habufferScreenSize);
  shader->setUniform("u_HashSz", habufferTableSize);
  shader->setUniformAsVec2Array("u_Offsets", offsets, 256);

  shader->setUniform("u_ZNear", habufferZNear);
  shader->setUniform("u_ZFar", habufferZFar);
  shader->setUniform("Opacity", habufferOpacity);
  shader->setUniform("u_Records", RecordsBuffer);
  shader->setUniform("u_Counts", CountsBuffer);
  shader->setUniform("u_FragmentData", FragmentDataBuffer);
}

void HABuffer::displayStatistics(const char *label)
{
  uint *lcounts = new uint[habufferCountsSize];

  CountsBuffer.getData(lcounts, CountsBuffer.getSize());

  int avgdepth = 0;
  int num = 0;
  for (uint c = 0; c < habufferCountsSize - 1; c++)
  {
    if (lcounts[c] > 0)
    {
      num++;
      avgdepth += lcounts[c];
    }
  }
  if (num == 0)
    num = 1;

  double rec_percentage = lcounts[habufferCountsSize - 1] /
                          static_cast<double>(habufferNumRecords) * 100.0;

  if (rec_percentage > 80.0)
  {
    std::cerr << label << " habufferCountsSize:" << habufferCountsSize
              << "<avg:" << avgdepth / static_cast<float>(num)
              << " max: " << lcounts[habufferCountsSize - 1] << "/"
              << habufferNumRecords << "(" << rec_percentage << "% " << '>'
              << std::endl;
  }

  delete[] lcounts;
}

}  // namespace Graphics
<|endoftext|>


<commit_before>/** @file gsDofMapper.h

    @brief Provides the gsDofMapper class for re-indexing DoFs.

    This file is part of the G+Smo library.

    This Source Code Form is subject to the terms of the Mozilla Public
    License, v. 2.0. If a copy of the MPL was not distributed with this
    file, You can obtain one at http://mozilla.org/MPL/2.0/.

    Author(s): C. Hofreither, A. Mantzaflaris
*/

#include <gsCore/gsDofMapper.h>

namespace gismo
{

gsDofMapper::gsDofMapper() :
m_shift(0), m_numFreeDofs(0), m_curElimId(-1), m_curCouplingId(1)
{
    m_offset.resize(1,0);
}

void gsDofMapper::localToGlobal(const gsMatrix<unsigned>& locals,
                                index_t patchIndex,
                                gsMatrix<unsigned>& globals) const
{
    GISMO_ASSERT( locals.cols() == 1, "localToGlobal: Expecting one column of locals");
    const index_t numActive = locals.rows();

    globals.resize(numActive,1);

    for (index_t i = 0; i < numActive; ++i)
        globals(i,0) = MAPPER_PATCH_DOF(locals(i,0), patchIndex)+m_shift;
}

// This function can not have enough information to do its job if dim>2
// GISMO_DEPRECATED
void gsDofMapper::matchInterface( index_t k1, index_t k2,
                                     const gsMatrix<unsigned> & b1,
                                     const gsMatrix<unsigned> & b2,
                                     const gsVector<bool> &orient )
{
    // Boundaries must be conforming (matching)
    const index_t sz = b1.size();
    if ( sz != b2.size() )
    {
        gsWarn<<"gsDofMapper: Problem: non-conforming interface "<<
                "("    <<k1<<","<< //i.first().side<<
                ")<->("<<k2<<","<< //i.second().side<<
                ") ~ ("<<sz<<","<<b2.size() <<").\n";

        gsWarn<< b1.transpose() << "\n";
        gsWarn<< b2.transpose() << "\n";

        GISMO_ERROR( "Non-conforming boundaries.\n" );
    }

    if( orient.size() )
    {
        if ( orient[0] == true ) // assumes 1D side
        {
            for ( index_t k=0; k<sz; ++k)
                this->matchDof( k1, b1(k,0), k2, b2(k,0) );
        }
        else
        {
            for ( index_t k=0; k<sz; ++k)
                this->matchDof( k1, b1(k,0), k2, b2(sz-k-1,0) );
        }
    }
    else
        for ( index_t k=0; k<sz; ++k)
            this->matchDof( k1, b1(k,0), k2, b2(k,0) );
}

void gsDofMapper::colapseDofs(index_t k, const gsMatrix<unsigned> & b )
{
    const index_t last = b.size()-1;
    for ( index_t k=0; k<last; ++k)
    {
        this->matchDof( k, b(k,0), k, b(k+1,0) );
    }
}

void gsDofMapper::matchDof( index_t u, index_t i, index_t v, index_t j )
{
    index_t d1 = MAPPER_PATCH_DOF(i,u);
    index_t d2 = MAPPER_PATCH_DOF(j,v);

    // make sure that d1 <= d2, simplifies implementation
    if (d1 > d2)
    {
        std::swap(d1, d2);
        std::swap(u, v);
        std::swap(i, j);
    }

    if (d1 < 0)         // first dof is eliminated
    {
        if (d2 < 0)         mergeDofsGlobally( d1, d2 );        // both are eliminated, merge their indices
        else if (d2 == 0)   MAPPER_PATCH_DOF(j,v) = d1;             // second is free, eliminate it along with first
        else /* d2 > 0*/    replaceDofGlobally( d2, d1 );       // second is coupling, eliminate all instances of it
    }
    else if (d1 == 0)   // first dof is a free dof
    {
        if (d2 == 0)        MAPPER_PATCH_DOF(i,u) = MAPPER_PATCH_DOF(j,v) = m_curCouplingId++;  // both are free, assign them a new coupling id
        else if (d2 > 0)    MAPPER_PATCH_DOF(i,u) = d2;             // second is coupling, add first to the same coupling group
        else                GISMO_ERROR("Something went terribly wrong");
    }
    else /* d1 > 0 */   // first dof is a coupling dof
    {
        GISMO_ASSERT(d2 > 0, "Something went terribly wrong");
        mergeDofsGlobally( d1, d2 );                            // both are coupling dofs, merge them
    }

    // if we merged two different non-eliminated dofs, we lost one free dof
    if ( (d1 != d2 && (d1 >= 0 || d2 >= 0) ) || (d1 == 0 && d2 == 0) )
        --m_numFreeDofs;
}

void gsDofMapper::markBoundary( index_t k, const gsMatrix<unsigned> & boundaryDofs )
{
    for (index_t i = 0; i < boundaryDofs.rows(); ++i)
    {
        eliminateDof( boundaryDofs(i,0), k );
    }

    // TO DO: save inverse, eg boundaryDofs(i,0)
}

void gsDofMapper::eliminateDof( index_t i, index_t k )
{
    const index_t old = MAPPER_PATCH_DOF(i,k);
    if (old == 0)       // regular free dof
    {
        --m_numFreeDofs;
        MAPPER_PATCH_DOF(i,k) = m_curElimId--;
    }
    else if (old > 0)   // coupling dof
    {
        --m_numFreeDofs;
        replaceDofGlobally( old, m_curElimId-- );
    }
    // else: old < 0: already an eliminated dof, nothing to do
}

void gsDofMapper::finalize()
{
    GISMO_ASSERT(m_curElimId!=0, "Error in gsDofMapper::finalize() called twince.");

    index_t curFreeDof = 0;                 // free dofs start at 0
    index_t curElimDof = m_numFreeDofs;     // eliminated dofs start after free dofs
    std::vector<index_t> couplingDofs(m_curCouplingId - 1, -1);
    std::vector<index_t> elimDofs(-m_curElimId - 1, -1);

    // Coupled dofs start after standard dofs
    index_t curCplDof = m_numFreeDofs - couplingDofs.size();

    for (std::size_t k = 0; k < m_dofs.size(); ++k)
    {
        const index_t dofType = m_dofs[k];

        if (dofType == 0)       // standard dof
            m_dofs[k] = curFreeDof++;
        else if (dofType < 0)   // eliminated dof
        {
            const index_t id = -dofType - 1;
            if (elimDofs[id] < 0)
                elimDofs[id] = curElimDof++;
            m_dofs[k] = elimDofs[id];
        }
        else // dofType > 0     // coupling dof
        {
            const index_t id = dofType - 1;
            if (couplingDofs[id] < 0)
                //couplingDofs[id] = curFreeDof++;
                couplingDofs[id] =   curCplDof++;
            m_dofs[k] = couplingDofs[id];
        }
    }
    m_numElimDofs = curElimDof - m_numFreeDofs;

    GISMO_ASSERT(curCplDof == m_numFreeDofs,
                 "gsDofMapper::finalize() - computed number of coupling dofs does not match allocated number");
    GISMO_ASSERT(curFreeDof + static_cast<index_t>(couplingDofs.size()) == m_numFreeDofs,
                 "gsDofMapper::finalize() - computed number of free dofs does not match allocated number");

    m_curElimId = 0;// Only equal to zero after finalize is called.

}

void gsDofMapper::print() const
{
    gsInfo<<"Dofs: "<< this->size() <<"\n";
    gsInfo<<" free: "<< this->freeSize() <<"\n";
    gsInfo<<" elim: "<< this->boundarySize() <<"\n";
}

void gsDofMapper::setIdentity(index_t nPatches, size_t nDofs)
{
    m_curElimId     = -1;
    m_curCouplingId =  1;
    m_numFreeDofs = nDofs;

    // Initialize all offsets to zero
    m_offset.resize(nPatches, 0);

    m_dofs.resize( m_numFreeDofs, 0);

    finalize();
}

void gsDofMapper::initPatchDofs(const gsVector<index_t> & patchDofSizes)
{
    m_curElimId     = -1;
    m_curCouplingId =  1;

    const size_t nPatches = patchDofSizes.size();

    // Initialize offsets and dof holder
    m_offset.reserve( nPatches );
    m_offset.push_back(0);
    for (size_t k = 1; k < nPatches; ++k)
    {
        m_offset.push_back( m_offset.back() + patchDofSizes[k-1] );
    }

    m_numFreeDofs = m_offset.back() + patchDofSizes[nPatches-1];

    m_dofs.resize( m_numFreeDofs, 0);
}

void gsDofMapper::replaceDofGlobally(index_t oldIdx, index_t newIdx)
{
    std::replace( m_dofs.begin(), m_dofs.end(), oldIdx, newIdx );
}

void gsDofMapper::mergeDofsGlobally(index_t dof1, index_t dof2)
{
    if (dof1 != dof2)
    {
        // replace the larger by the smaller for more consistent numbering.
        if (dof1 < dof2)
            std::swap(dof1, dof2);

        replaceDofGlobally(dof1, dof2);
    }
}

index_t gsDofMapper::coupledSize() const
{
    // Property: coupled (eliminated or not) DoFs appear more than once in the mapping.
    GISMO_ENSURE(m_curElimId==0, "finalize() was not called on gsDofMapper");

    std::vector<index_t> CountMap(m_numFreeDofs,0);

    // Count number of appearances of each free DoF
    for (std::vector<index_t>::const_iterator it = m_dofs.begin(); it != m_dofs.end(); ++it)
        if ( *it < m_numFreeDofs )
            CountMap[*it]++;

    // Count the number of freeDoFs that appear more than once
    index_t count = 0;
    for (std::vector<index_t>::const_iterator it = CountMap.begin(); it != CountMap.end(); ++it)
        if ( *it > 1 )
            count++;

    return count;
}

void gsDofMapper::setShift (index_t shift)
{
    m_shift=shift;
}

} // namespace gismo

<commit_msg>more improvement in coupledSize<commit_after>/** @file gsDofMapper.h

    @brief Provides the gsDofMapper class for re-indexing DoFs.

    This file is part of the G+Smo library.

    This Source Code Form is subject to the terms of the Mozilla Public
    License, v. 2.0. If a copy of the MPL was not distributed with this
    file, You can obtain one at http://mozilla.org/MPL/2.0/.

    Author(s): C. Hofreither, A. Mantzaflaris
*/

#include <gsCore/gsDofMapper.h>

namespace gismo
{

gsDofMapper::gsDofMapper() :
m_shift(0), m_numFreeDofs(0), m_curElimId(-1), m_curCouplingId(1)
{
    m_offset.resize(1,0);
}

void gsDofMapper::localToGlobal(const gsMatrix<unsigned>& locals,
                                index_t patchIndex,
                                gsMatrix<unsigned>& globals) const
{
    GISMO_ASSERT( locals.cols() == 1, "localToGlobal: Expecting one column of locals");
    const index_t numActive = locals.rows();

    globals.resize(numActive,1);

    for (index_t i = 0; i < numActive; ++i)
        globals(i,0) = MAPPER_PATCH_DOF(locals(i,0), patchIndex)+m_shift;
}

// This function can not have enough information to do its job if dim>2
// GISMO_DEPRECATED
void gsDofMapper::matchInterface( index_t k1, index_t k2,
                                     const gsMatrix<unsigned> & b1,
                                     const gsMatrix<unsigned> & b2,
                                     const gsVector<bool> &orient )
{
    // Boundaries must be conforming (matching)
    const index_t sz = b1.size();
    if ( sz != b2.size() )
    {
        gsWarn<<"gsDofMapper: Problem: non-conforming interface "<<
                "("    <<k1<<","<< //i.first().side<<
                ")<->("<<k2<<","<< //i.second().side<<
                ") ~ ("<<sz<<","<<b2.size() <<").\n";

        gsWarn<< b1.transpose() << "\n";
        gsWarn<< b2.transpose() << "\n";

        GISMO_ERROR( "Non-conforming boundaries.\n" );
    }

    if( orient.size() )
    {
        if ( orient[0] == true ) // assumes 1D side
        {
            for ( index_t k=0; k<sz; ++k)
                this->matchDof( k1, b1(k,0), k2, b2(k,0) );
        }
        else
        {
            for ( index_t k=0; k<sz; ++k)
                this->matchDof( k1, b1(k,0), k2, b2(sz-k-1,0) );
        }
    }
    else
        for ( index_t k=0; k<sz; ++k)
            this->matchDof( k1, b1(k,0), k2, b2(k,0) );
}

void gsDofMapper::colapseDofs(index_t k, const gsMatrix<unsigned> & b )
{
    const index_t last = b.size()-1;
    for ( index_t k=0; k<last; ++k)
    {
        this->matchDof( k, b(k,0), k, b(k+1,0) );
    }
}

void gsDofMapper::matchDof( index_t u, index_t i, index_t v, index_t j )
{
    index_t d1 = MAPPER_PATCH_DOF(i,u);
    index_t d2 = MAPPER_PATCH_DOF(j,v);

    // make sure that d1 <= d2, simplifies implementation
    if (d1 > d2)
    {
        std::swap(d1, d2);
        std::swap(u, v);
        std::swap(i, j);
    }

    if (d1 < 0)         // first dof is eliminated
    {
        if (d2 < 0)         mergeDofsGlobally( d1, d2 );        // both are eliminated, merge their indices
        else if (d2 == 0)   MAPPER_PATCH_DOF(j,v) = d1;             // second is free, eliminate it along with first
        else /* d2 > 0*/    replaceDofGlobally( d2, d1 );       // second is coupling, eliminate all instances of it
    }
    else if (d1 == 0)   // first dof is a free dof
    {
        if (d2 == 0)        MAPPER_PATCH_DOF(i,u) = MAPPER_PATCH_DOF(j,v) = m_curCouplingId++;  // both are free, assign them a new coupling id
        else if (d2 > 0)    MAPPER_PATCH_DOF(i,u) = d2;             // second is coupling, add first to the same coupling group
        else                GISMO_ERROR("Something went terribly wrong");
    }
    else /* d1 > 0 */   // first dof is a coupling dof
    {
        GISMO_ASSERT(d2 > 0, "Something went terribly wrong");
        mergeDofsGlobally( d1, d2 );                            // both are coupling dofs, merge them
    }

    // if we merged two different non-eliminated dofs, we lost one free dof
    if ( (d1 != d2 && (d1 >= 0 || d2 >= 0) ) || (d1 == 0 && d2 == 0) )
        --m_numFreeDofs;
}

void gsDofMapper::markBoundary( index_t k, const gsMatrix<unsigned> & boundaryDofs )
{
    for (index_t i = 0; i < boundaryDofs.rows(); ++i)
    {
        eliminateDof( boundaryDofs(i,0), k );
    }

    // TO DO: save inverse, eg boundaryDofs(i,0)
}

void gsDofMapper::eliminateDof( index_t i, index_t k )
{
    const index_t old = MAPPER_PATCH_DOF(i,k);
    if (old == 0)       // regular free dof
    {
        --m_numFreeDofs;
        MAPPER_PATCH_DOF(i,k) = m_curElimId--;
    }
    else if (old > 0)   // coupling dof
    {
        --m_numFreeDofs;
        replaceDofGlobally( old, m_curElimId-- );
    }
    // else: old < 0: already an eliminated dof, nothing to do
}

void gsDofMapper::finalize()
{
    GISMO_ASSERT(m_curElimId!=0, "Error in gsDofMapper::finalize() called twince.");

    index_t curFreeDof = 0;                 // free dofs start at 0
    index_t curElimDof = m_numFreeDofs;     // eliminated dofs start after free dofs
    std::vector<index_t> couplingDofs(m_curCouplingId - 1, -1);
    std::vector<index_t> elimDofs(-m_curElimId - 1, -1);

    // Coupled dofs start after standard dofs
    index_t curCplDof = m_numFreeDofs - couplingDofs.size();

    for (std::size_t k = 0; k < m_dofs.size(); ++k)
    {
        const index_t dofType = m_dofs[k];

        if (dofType == 0)       // standard dof
            m_dofs[k] = curFreeDof++;
        else if (dofType < 0)   // eliminated dof
        {
            const index_t id = -dofType - 1;
            if (elimDofs[id] < 0)
                elimDofs[id] = curElimDof++;
            m_dofs[k] = elimDofs[id];
        }
        else // dofType > 0     // coupling dof
        {
            const index_t id = dofType - 1;
            if (couplingDofs[id] < 0)
                //couplingDofs[id] = curFreeDof++;
                couplingDofs[id] =   curCplDof++;
            m_dofs[k] = couplingDofs[id];
        }
    }
    m_numElimDofs = curElimDof - m_numFreeDofs;

    GISMO_ASSERT(curCplDof == m_numFreeDofs,
                 "gsDofMapper::finalize() - computed number of coupling dofs does not match allocated number");
    GISMO_ASSERT(curFreeDof + static_cast<index_t>(couplingDofs.size()) == m_numFreeDofs,
                 "gsDofMapper::finalize() - computed number of free dofs does not match allocated number");

    m_curElimId = 0;// Only equal to zero after finalize is called.

}

void gsDofMapper::print() const
{
    gsInfo<<"Dofs: "<< this->size() <<"\n";
    gsInfo<<" free: "<< this->freeSize() <<"\n";
    gsInfo<<" elim: "<< this->boundarySize() <<"\n";
}

void gsDofMapper::setIdentity(index_t nPatches, size_t nDofs)
{
    m_curElimId     = -1;
    m_curCouplingId =  1;
    m_numFreeDofs = nDofs;

    // Initialize all offsets to zero
    m_offset.resize(nPatches, 0);

    m_dofs.resize( m_numFreeDofs, 0);

    finalize();
}

void gsDofMapper::initPatchDofs(const gsVector<index_t> & patchDofSizes)
{
    m_curElimId     = -1;
    m_curCouplingId =  1;

    const size_t nPatches = patchDofSizes.size();

    // Initialize offsets and dof holder
    m_offset.reserve( nPatches );
    m_offset.push_back(0);
    for (size_t k = 1; k < nPatches; ++k)
    {
        m_offset.push_back( m_offset.back() + patchDofSizes[k-1] );
    }

    m_numFreeDofs = m_offset.back() + patchDofSizes[nPatches-1];

    m_dofs.resize( m_numFreeDofs, 0);
}

void gsDofMapper::replaceDofGlobally(index_t oldIdx, index_t newIdx)
{
    std::replace( m_dofs.begin(), m_dofs.end(), oldIdx, newIdx );
}

void gsDofMapper::mergeDofsGlobally(index_t dof1, index_t dof2)
{
    if (dof1 != dof2)
    {
        // replace the larger by the smaller for more consistent numbering.
        if (dof1 < dof2)
            std::swap(dof1, dof2);

        replaceDofGlobally(dof1, dof2);
    }
}

index_t gsDofMapper::coupledSize() const
{
    // Property: coupled (eliminated or not) DoFs appear more than once in the mapping.
    GISMO_ENSURE(m_curElimId==0, "finalize() was not called on gsDofMapper");

    std::vector<index_t> CountMap(m_numFreeDofs,0);

    // Count number of appearances of each free DoF
    for (std::vector<index_t>::const_iterator it = m_dofs.begin(); it != m_dofs.end(); ++it)
        if ( *it < m_numFreeDofs )
            CountMap[*it]++;

    // Count the number of freeDoFs that appear more than once
    return std::count_if( CountMap.begin(), CountMap.end(), std::bind1st(std::greater<index_t>(), 1) );
    /* // Equivalent implementation
    index_t count = 0;
    for (std::vector<index_t>::const_iterator it = CountMap.begin(); it != CountMap.end(); ++it)
        if ( *it > 1 )
            count++;
    return count;
    */
}

void gsDofMapper::setShift (index_t shift)
{
    m_shift=shift;
}

} // namespace gismo

<|endoftext|>