<commit_before>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Albrecht
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//
// Contributors: Kirsten Weber

#ifndef DUNE_GDT_DISCRETEFUNCTION_DEFAULT_HH
#define DUNE_GDT_DISCRETEFUNCTION_DEFAULT_HH

#include <memory>
#include <type_traits>

#include <dune/common/exceptions.hh>
#include <dune/common/fvector.hh>

#include <dune/grid/io/file/vtk.hh>

#include <dune/stuff/la/container/interfaces.hh>

#include <dune/gdt/space/interface.hh>

#include "local.hh"

namespace Dune {
namespace GDT {

template< class SpaceImp, class VectorImp >
class ConstDiscreteFunction
  : public Stuff::LocalizableFunctionInterface< typename SpaceImp::EntityType,
        typename SpaceImp::DomainFieldType, SpaceImp::dimDomain,
        typename SpaceImp::RangeFieldType, SpaceImp::dimRange, SpaceImp::dimRangeCols >
{
  static_assert(std::is_base_of< SpaceInterface< typename SpaceImp::Traits >, SpaceImp >::value,
                "SpaceImp has to be derived from SpaceInterface!");
  static_assert(std::is_base_of< Dune::Stuff::LA::VectorInterface< typename VectorImp::Traits >, VectorImp >::value,
                "VectorImp has to be derived from Stuff::LA::VectorInterface!");
  static_assert(std::is_same< typename SpaceImp::RangeFieldType, typename VectorImp::ScalarType >::value,
                "Types do not match!");
  typedef Stuff::LocalizableFunctionInterface
      < typename SpaceImp::EntityType, typename SpaceImp::DomainFieldType, SpaceImp::dimDomain,
        typename SpaceImp::RangeFieldType, SpaceImp::dimRange, SpaceImp::dimRangeCols >
    BaseType;
  typedef ConstDiscreteFunction< SpaceImp, VectorImp > ThisType;
public:
  typedef SpaceImp                              SpaceType;
  typedef VectorImp                             VectorType;
  typedef typename BaseType::EntityType         EntityType;
  typedef typename BaseType::LocalfunctionType  LocalfunctionType;

  static const unsigned int                   dimDomain = BaseType::dimDomain;
  typedef typename BaseType::DomainFieldType  DomainFieldType;
  typedef typename BaseType::DomainType       DomainType;

  static const unsigned int                     dimRange = BaseType::dimRange;
  static const unsigned int                     dimRangeCols = BaseType::dimRangeCols;
  typedef typename BaseType::RangeFieldType     RangeFieldType;
  typedef typename BaseType::RangeType          RangeType;
  typedef typename BaseType::JacobianRangeType  JacobianRangeType;

  typedef ConstLocalDiscreteFunction< SpaceType, VectorType > ConstLocalDiscreteFunctionType;

  ConstDiscreteFunction(const SpaceType& sp,
                        const VectorType& vec,
                        const std::string nm = "dune.gdt.constdiscretefunction")
    : space_(sp)
    , vector_(vec)
    , name_(nm)
  {
    assert(vector_.size() == space_.mapper().size() && "Given vector has wrong size!");
  }

  ConstDiscreteFunction(const ThisType& other)
    : space_(other.space_)
    , vector_(other.vector_)
    , name_(other.name_)
  {}

  ConstDiscreteFunction(ThisType&& source)
    : space_(source.space_)
    , vector_(source.vector_)
    , name_(std::move(source.name_))
  {}

  ThisType& operator=(const ThisType& other) = delete;

  ~ConstDiscreteFunction() {}

  virtual ThisType* copy() const DS_OVERRIDE
  {
    return new ThisType(*this);
  }

  virtual std::string name() const DS_OVERRIDE
  {
    return name_;
  }

  const SpaceType& space() const
  {
    return space_;
  }

  const VectorType& vector() const
  {
    return vector_;
  }

  ConstLocalDiscreteFunctionType local_discrete_function(const EntityType& entity) const
  {
    assert(space_.grid_view()->indexSet().contains(entity));
    return ConstLocalDiscreteFunctionType(space_, vector_, entity);
  }

  virtual std::unique_ptr< LocalfunctionType > local_function(const EntityType& entity) const DS_OVERRIDE
  {
    return std::unique_ptr< ConstLocalDiscreteFunctionType >
        (new ConstLocalDiscreteFunctionType(local_discrete_function(entity)));
  }

  void visualize(const std::string filename,
                 const bool subsampling = true,
                 VTK::OutputType vtk_output_type = VTK::appendedraw) const
  {
    BaseType::template visualize< typename SpaceType::GridViewType >(*(space().grid_view()),
                                                                     filename,
                                                                     subsampling,
                                                                     vtk_output_type);
  }

protected:
  const SpaceType& space_;
private:
  const VectorType& vector_;
  const std::string name_;
}; // class ConstDiscreteFunction

template< class SpaceImp, class VectorImp >
class DiscreteFunction
  : public ConstDiscreteFunction< SpaceImp, VectorImp >
{
  typedef ConstDiscreteFunction< SpaceImp, VectorImp >  BaseType;
  typedef DiscreteFunction< SpaceImp, VectorImp >       ThisType;
public:
  typedef typename BaseType::SpaceType          SpaceType;
  typedef typename BaseType::VectorType         VectorType;
  typedef typename BaseType::EntityType         EntityType;
  typedef typename BaseType::LocalfunctionType  LocalfunctionType;

  typedef LocalDiscreteFunction< SpaceType, VectorType > LocalDiscreteFunctionType;

  DiscreteFunction(const SpaceType& sp,
                   VectorType& vec,
                   const std::string nm = "dune.gdt.discretefunction")
    : BaseType(sp, vec, nm)
    , vector_(vec)
  {}

  DiscreteFunction(const ThisType& other)
    : BaseType(other)
    , vector_(other.vector_)
  {}

  DiscreteFunction(ThisType&& source)
    : BaseType(std::move(source))
    , vector_(source.vector_)
  {}

  ThisType& operator=(const ThisType& other) = delete;

  ~DiscreteFunction() {}

  virtual ThisType* copy() const DS_OVERRIDE
  {
    return new ThisType(*this);
  }

  VectorType& vector()
  {
    return vector_;
  }

  LocalDiscreteFunctionType local_discrete_function(const EntityType& entity)
  {
    assert(space_.grid_view()->indexSet().contains(entity));
    return LocalDiscreteFunctionType(space_, vector_, entity);
  }

private:
  using BaseType::space_;
  VectorType& vector_;
}; // class DiscreteFunction

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_DISCRETEFUNCTION_DEFAULT_HH
<commit_msg>[discretefunction.default] * allow to get a const local discrete function from a non const function<commit_after>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Albrecht
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//
// Contributors: Kirsten Weber

#ifndef DUNE_GDT_DISCRETEFUNCTION_DEFAULT_HH
#define DUNE_GDT_DISCRETEFUNCTION_DEFAULT_HH

#include <memory>
#include <type_traits>

#include <dune/common/exceptions.hh>
#include <dune/common/fvector.hh>

#include <dune/grid/io/file/vtk.hh>

#include <dune/stuff/la/container/interfaces.hh>

#include <dune/gdt/space/interface.hh>

#include "local.hh"

namespace Dune {
namespace GDT {

template< class SpaceImp, class VectorImp >
class ConstDiscreteFunction
  : public Stuff::LocalizableFunctionInterface< typename SpaceImp::EntityType,
        typename SpaceImp::DomainFieldType, SpaceImp::dimDomain,
        typename SpaceImp::RangeFieldType, SpaceImp::dimRange, SpaceImp::dimRangeCols >
{
  static_assert(std::is_base_of< SpaceInterface< typename SpaceImp::Traits >, SpaceImp >::value,
                "SpaceImp has to be derived from SpaceInterface!");
  static_assert(std::is_base_of< Dune::Stuff::LA::VectorInterface< typename VectorImp::Traits >, VectorImp >::value,
                "VectorImp has to be derived from Stuff::LA::VectorInterface!");
  static_assert(std::is_same< typename SpaceImp::RangeFieldType, typename VectorImp::ScalarType >::value,
                "Types do not match!");
  typedef Stuff::LocalizableFunctionInterface
      < typename SpaceImp::EntityType, typename SpaceImp::DomainFieldType, SpaceImp::dimDomain,
        typename SpaceImp::RangeFieldType, SpaceImp::dimRange, SpaceImp::dimRangeCols >
    BaseType;
  typedef ConstDiscreteFunction< SpaceImp, VectorImp > ThisType;
public:
  typedef SpaceImp                              SpaceType;
  typedef VectorImp                             VectorType;
  typedef typename BaseType::EntityType         EntityType;
  typedef typename BaseType::LocalfunctionType  LocalfunctionType;

  static const unsigned int                   dimDomain = BaseType::dimDomain;
  typedef typename BaseType::DomainFieldType  DomainFieldType;
  typedef typename BaseType::DomainType       DomainType;

  static const unsigned int                     dimRange = BaseType::dimRange;
  static const unsigned int                     dimRangeCols = BaseType::dimRangeCols;
  typedef typename BaseType::RangeFieldType     RangeFieldType;
  typedef typename BaseType::RangeType          RangeType;
  typedef typename BaseType::JacobianRangeType  JacobianRangeType;

  typedef ConstLocalDiscreteFunction< SpaceType, VectorType > ConstLocalDiscreteFunctionType;

  ConstDiscreteFunction(const SpaceType& sp,
                        const VectorType& vec,
                        const std::string nm = "dune.gdt.constdiscretefunction")
    : space_(sp)
    , vector_(vec)
    , name_(nm)
  {
    assert(vector_.size() == space_.mapper().size() && "Given vector has wrong size!");
  }

  ConstDiscreteFunction(const ThisType& other)
    : space_(other.space_)
    , vector_(other.vector_)
    , name_(other.name_)
  {}

  ConstDiscreteFunction(ThisType&& source)
    : space_(source.space_)
    , vector_(source.vector_)
    , name_(std::move(source.name_))
  {}

  ThisType& operator=(const ThisType& other) = delete;

  ~ConstDiscreteFunction() {}

  virtual ThisType* copy() const DS_OVERRIDE
  {
    return new ThisType(*this);
  }

  virtual std::string name() const DS_OVERRIDE
  {
    return name_;
  }

  const SpaceType& space() const
  {
    return space_;
  }

  const VectorType& vector() const
  {
    return vector_;
  }

  ConstLocalDiscreteFunctionType local_discrete_function(const EntityType& entity) const
  {
    assert(space_.grid_view()->indexSet().contains(entity));
    return ConstLocalDiscreteFunctionType(space_, vector_, entity);
  }

  virtual std::unique_ptr< LocalfunctionType > local_function(const EntityType& entity) const DS_OVERRIDE
  {
    return std::unique_ptr< ConstLocalDiscreteFunctionType >
        (new ConstLocalDiscreteFunctionType(local_discrete_function(entity)));
  }

  void visualize(const std::string filename,
                 const bool subsampling = true,
                 VTK::OutputType vtk_output_type = VTK::appendedraw) const
  {
    BaseType::template visualize< typename SpaceType::GridViewType >(*(space().grid_view()),
                                                                     filename,
                                                                     subsampling,
                                                                     vtk_output_type);
  }

protected:
  const SpaceType& space_;
private:
  const VectorType& vector_;
  const std::string name_;
}; // class ConstDiscreteFunction

template< class SpaceImp, class VectorImp >
class DiscreteFunction
  : public ConstDiscreteFunction< SpaceImp, VectorImp >
{
  typedef ConstDiscreteFunction< SpaceImp, VectorImp >  BaseType;
  typedef DiscreteFunction< SpaceImp, VectorImp >       ThisType;
public:
  typedef typename BaseType::SpaceType          SpaceType;
  typedef typename BaseType::VectorType         VectorType;
  typedef typename BaseType::EntityType         EntityType;
  typedef typename BaseType::LocalfunctionType  LocalfunctionType;

  typedef LocalDiscreteFunction< SpaceType, VectorType > LocalDiscreteFunctionType;

  DiscreteFunction(const SpaceType& sp,
                   VectorType& vec,
                   const std::string nm = "dune.gdt.discretefunction")
    : BaseType(sp, vec, nm)
    , vector_(vec)
  {}

  DiscreteFunction(const ThisType& other)
    : BaseType(other)
    , vector_(other.vector_)
  {}

  DiscreteFunction(ThisType&& source)
    : BaseType(std::move(source))
    , vector_(source.vector_)
  {}

  ThisType& operator=(const ThisType& other) = delete;

  ~DiscreteFunction() {}

  virtual ThisType* copy() const DS_OVERRIDE
  {
    return new ThisType(*this);
  }

  VectorType& vector()
  {
    return vector_;
  }

  using BaseType::local_discrete_function;

  LocalDiscreteFunctionType local_discrete_function(const EntityType& entity)
  {
    assert(space_.grid_view()->indexSet().contains(entity));
    return LocalDiscreteFunctionType(space_, vector_, entity);
  }

private:
  using BaseType::space_;
  VectorType& vector_;
}; // class DiscreteFunction

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_DISCRETEFUNCTION_DEFAULT_HH
<|endoftext|>


<commit_before>//===- Miscompilation.cpp - Debug program miscompilations -----------------===//
//
// This file implements program miscompilation debugging support.
//
//===----------------------------------------------------------------------===//

#include "BugDriver.h"
#include "SystemUtils.h"
#include "ListReducer.h"
#include "llvm/Pass.h"
#include "llvm/Module.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Transforms/Utils/Linker.h"

class ReduceMiscompilingPasses : public ListReducer<const PassInfo*> {
  BugDriver &BD;
public:
  ReduceMiscompilingPasses(BugDriver &bd) : BD(bd) {}

  virtual TestResult doTest(std::vector<const PassInfo*> &Prefix,
                            std::vector<const PassInfo*> &Suffix);
};

ReduceMiscompilingPasses::TestResult
ReduceMiscompilingPasses::doTest(std::vector<const PassInfo*> &Prefix,
                                 std::vector<const PassInfo*> &Suffix) {
  // First, run the program with just the Suffix passes.  If it is still broken
  // with JUST the kept passes, discard the prefix passes.
  std::cout << "Checking to see if '" << getPassesString(Suffix)
            << "' compile correctly: ";

  std::string BytecodeResult;
  if (BD.runPasses(Suffix, BytecodeResult, false/*delete*/, true/*quiet*/)) {
    std::cerr << BD.getToolName() << ": Error running this sequence of passes"
              << " on the input program!\n";
    exit(1);
  }

  // Check to see if the finished program matches the reference output...
  if (BD.diffProgram(BytecodeResult, "", true /*delete bytecode*/)) {
    std::cout << "nope.\n";
    return KeepSuffix;        // Miscompilation detected!
  }
  std::cout << "yup.\n";      // No miscompilation!

  if (Prefix.empty()) return NoFailure;

  // Next, see if the program is broken if we run the "prefix" passes first,
  // then separately run the "kept" passes.
  std::cout << "Checking to see if '" << getPassesString(Prefix)
            << "' compile correctly: ";

  // If it is not broken with the kept passes, it's possible that the prefix
  // passes must be run before the kept passes to break it.  If the program
  // WORKS after the prefix passes, but then fails if running the prefix AND
  // kept passes, we can update our bytecode file to include the result of the
  // prefix passes, then discard the prefix passes.
  //
  if (BD.runPasses(Prefix, BytecodeResult, false/*delete*/, true/*quiet*/)) {
    std::cerr << BD.getToolName() << ": Error running this sequence of passes"
              << " on the input program!\n";
    exit(1);
  }

  // If the prefix maintains the predicate by itself, only keep the prefix!
  if (BD.diffProgram(BytecodeResult)) {
    std::cout << "nope.\n";
    removeFile(BytecodeResult);
    return KeepPrefix;
  }
  std::cout << "yup.\n";      // No miscompilation!

  // Ok, so now we know that the prefix passes work, try running the suffix
  // passes on the result of the prefix passes.
  //
  Module *PrefixOutput = BD.ParseInputFile(BytecodeResult);
  if (PrefixOutput == 0) {
    std::cerr << BD.getToolName() << ": Error reading bytecode file '"
              << BytecodeResult << "'!\n";
    exit(1);
  }
  removeFile(BytecodeResult);  // No longer need the file on disk

  std::cout << "Checking to see if '" << getPassesString(Suffix)
            << "' passes compile correctly after the '"
            << getPassesString(Prefix) << "' passes: ";

  Module *OriginalInput = BD.Program;
  BD.Program = PrefixOutput;
  if (BD.runPasses(Suffix, BytecodeResult, false/*delete*/, true/*quiet*/)) {
    std::cerr << BD.getToolName() << ": Error running this sequence of passes"
              << " on the input program!\n";
    exit(1);
  }

  // Run the result...
  if (BD.diffProgram(BytecodeResult, "", true/*delete bytecode*/)) {
    std::cout << "nope.\n";
    delete OriginalInput;     // We pruned down the original input...
    return KeepSuffix;
  }

  // Otherwise, we must not be running the bad pass anymore.
  std::cout << "yup.\n";      // No miscompilation!
  BD.Program = OriginalInput; // Restore original program
  delete PrefixOutput;        // Free experiment
  return NoFailure;
}

class ReduceMiscompilingFunctions : public ListReducer<Function*> {
  BugDriver &BD;
public:
  ReduceMiscompilingFunctions(BugDriver &bd) : BD(bd) {}

  virtual TestResult doTest(std::vector<Function*> &Prefix,
                            std::vector<Function*> &Suffix) {
    if (TestFuncs(Suffix, false))
      return KeepSuffix;
    if (!Prefix.empty() && TestFuncs(Prefix, false))
      return KeepPrefix;
    return NoFailure;
  }

  bool TestFuncs(const std::vector<Function*> &Prefix, bool EmitBytecode);
};

bool ReduceMiscompilingFunctions::TestFuncs(const std::vector<Function*> &Funcs,
                                            bool EmitBytecode) {
  // Test to see if the function is misoptimized if we ONLY run it on the
  // functions listed in Funcs.
  if (!EmitBytecode) {
    std::cout << "Checking to see if the program is misoptimized when these "
              << "functions are run\nthrough the passes: ";
    BD.PrintFunctionList(Funcs);
    std::cout << "\n";
  } else {
    std::cout <<"Outputting reduced bytecode files which expose the problem:\n";
  }

  // First step: clone the module for the two halves of the program we want.
  Module *ToOptimize = CloneModule(BD.Program);

  // Second step: Make sure functions & globals are all external so that linkage
  // between the two modules will work.
  for (Module::iterator I = ToOptimize->begin(), E = ToOptimize->end();I!=E;++I)
    I->setLinkage(GlobalValue::ExternalLinkage);
  for (Module::giterator I = ToOptimize->gbegin(), E = ToOptimize->gend();
       I != E; ++I)
    I->setLinkage(GlobalValue::ExternalLinkage);

  // Third step: make a clone of the externalized program for the non-optimized
  // part.
  Module *ToNotOptimize = CloneModule(ToOptimize);

  // Fourth step: Remove the test functions from the ToNotOptimize module, and
  // all of the global variables.
  for (unsigned i = 0, e = Funcs.size(); i != e; ++i) {
    Function *TNOF = ToNotOptimize->getFunction(Funcs[i]->getName(),
                                                Funcs[i]->getFunctionType());
    assert(TNOF && "Function doesn't exist in module!");
    DeleteFunctionBody(TNOF);       // Function is now external in this module!
  }
  for (Module::giterator I = ToNotOptimize->gbegin(), E = ToNotOptimize->gend();
       I != E; ++I)
    I->setInitializer(0);  // Delete the initializer to make it external

  if (EmitBytecode) {
    std::cout << "  Non-optimized portion: ";
    std::swap(BD.Program, ToNotOptimize);
    BD.EmitProgressBytecode("tonotoptimize", true);
    std::swap(BD.Program, ToNotOptimize);
  }

  // Fifth step: Remove all functions from the ToOptimize module EXCEPT for the
  // ones specified in Funcs.  We know which ones these are because they are
  // non-external in ToOptimize, but external in ToNotOptimize.
  //
  for (Module::iterator I = ToOptimize->begin(), E = ToOptimize->end();I!=E;++I)
    if (!I->isExternal()) {
      Function *TNOF = ToNotOptimize->getFunction(I->getName(),
                                                  I->getFunctionType());
      assert(TNOF && "Function doesn't exist in ToNotOptimize module??");
      if (!TNOF->isExternal())
        DeleteFunctionBody(I);
    }

  if (EmitBytecode) {
    std::cout << "  Portion that is input to optimizer: ";
    std::swap(BD.Program, ToOptimize);
    BD.EmitProgressBytecode("tooptimize");
    std::swap(BD.Program, ToOptimize);
  }

  // Sixth step: Run the optimization passes on ToOptimize, producing a
  // transformed version of the functions being tested.
  Module *OldProgram = BD.Program;
  BD.Program = ToOptimize;

  if (!EmitBytecode)
    std::cout << "  Optimizing functions being tested: ";
  std::string BytecodeResult;
  if (BD.runPasses(BD.PassesToRun, BytecodeResult, false/*delete*/,
                   true/*quiet*/)) {
    std::cerr << BD.getToolName() << ": Error running this sequence of passes"
              << " on the input program!\n";
    exit(1);
  }

  if (!EmitBytecode)
    std::cout << "done.\n";

  delete BD.Program;   // Delete the old "ToOptimize" module
  BD.Program = BD.ParseInputFile(BytecodeResult);

  if (EmitBytecode) {
    std::cout << "  'tooptimize' after being optimized: ";
    BD.EmitProgressBytecode("optimized", true);
  }

  if (BD.Program == 0) {
    std::cerr << BD.getToolName() << ": Error reading bytecode file '"
              << BytecodeResult << "'!\n";
    exit(1);
  }
  removeFile(BytecodeResult);  // No longer need the file on disk

  // Seventh step: Link the optimized part of the program back to the
  // unoptimized part of the program.
  //
  if (LinkModules(BD.Program, ToNotOptimize, &BytecodeResult)) {
    std::cerr << BD.getToolName() << ": Error linking modules together:"
              << BytecodeResult << "\n";
    exit(1);
  }
  delete ToNotOptimize;  // We are done with this module...

  if (EmitBytecode) {
    std::cout << "  Program as tested: ";
    BD.EmitProgressBytecode("linked", true);
    delete BD.Program;
    BD.Program = OldProgram;
    return false;   // We don't need to actually execute the program here.
  }

  std::cout << "  Checking to see if the merged program executes correctly: ";

  // Eighth step: Execute the program.  If it does not match the expected
  // output, then 'Funcs' are being misoptimized!
  bool Broken = BD.diffProgram();

  delete BD.Program;  // Delete the hacked up program
  BD.Program = OldProgram;   // Restore the original

  std::cout << (Broken ? "nope.\n" : "yup.\n");
  return Broken;
}

/// debugMiscompilation - This method is used when the passes selected are not
/// crashing, but the generated output is semantically different from the
/// input.
///
bool BugDriver::debugMiscompilation() {

  if (diffProgram()) {
    std::cout << "\n*** Input program does not match reference diff!\n"
              << "    Must be problem with input source!\n";
    return false;  // Problem found
  }

  // Make sure something was miscompiled...
  if (!ReduceMiscompilingPasses(*this).reduceList(PassesToRun)) {
    std::cerr << "*** Optimized program matches reference output!  No problem "
	      << "detected...\nbugpoint can't help you with your problem!\n";
    return false;
  }

  std::cout << "\n*** Found miscompiling pass"
            << (PassesToRun.size() == 1 ? "" : "es") << ": "
            << getPassesString(PassesToRun) << "\n";
  EmitProgressBytecode("passinput");

  // Okay, now that we have reduced the list of passes which are causing the
  // failure, see if we can pin down which functions are being
  // miscompiled... first build a list of all of the non-external functions in
  // the program.
  std::vector<Function*> MiscompiledFunctions;
  for (Module::iterator I = Program->begin(), E = Program->end(); I != E; ++I)
    if (!I->isExternal())
      MiscompiledFunctions.push_back(I);

  // Do the reduction...
  ReduceMiscompilingFunctions(*this).reduceList(MiscompiledFunctions);

  std::cout << "\n*** The following functions are being miscompiled: ";
  PrintFunctionList(MiscompiledFunctions);
  std::cout << "\n";

  // Output a bunch of bytecode files for the user...
  ReduceMiscompilingFunctions(*this).TestFuncs(MiscompiledFunctions, true);

  return false;
}
<commit_msg>Do not attempt to reduce a test case if it is an empty set.<commit_after>//===- Miscompilation.cpp - Debug program miscompilations -----------------===//
//
// This file implements program miscompilation debugging support.
//
//===----------------------------------------------------------------------===//

#include "BugDriver.h"
#include "SystemUtils.h"
#include "ListReducer.h"
#include "llvm/Pass.h"
#include "llvm/Module.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Transforms/Utils/Linker.h"

class ReduceMiscompilingPasses : public ListReducer<const PassInfo*> {
  BugDriver &BD;
public:
  ReduceMiscompilingPasses(BugDriver &bd) : BD(bd) {}

  virtual TestResult doTest(std::vector<const PassInfo*> &Prefix,
                            std::vector<const PassInfo*> &Suffix);
};

ReduceMiscompilingPasses::TestResult
ReduceMiscompilingPasses::doTest(std::vector<const PassInfo*> &Prefix,
                                 std::vector<const PassInfo*> &Suffix) {
  // First, run the program with just the Suffix passes.  If it is still broken
  // with JUST the kept passes, discard the prefix passes.
  std::cout << "Checking to see if '" << getPassesString(Suffix)
            << "' compile correctly: ";

  std::string BytecodeResult;
  if (BD.runPasses(Suffix, BytecodeResult, false/*delete*/, true/*quiet*/)) {
    std::cerr << BD.getToolName() << ": Error running this sequence of passes"
              << " on the input program!\n";
    exit(1);
  }

  // Check to see if the finished program matches the reference output...
  if (BD.diffProgram(BytecodeResult, "", true /*delete bytecode*/)) {
    std::cout << "nope.\n";
    return KeepSuffix;        // Miscompilation detected!
  }
  std::cout << "yup.\n";      // No miscompilation!

  if (Prefix.empty()) return NoFailure;

  // Next, see if the program is broken if we run the "prefix" passes first,
  // then separately run the "kept" passes.
  std::cout << "Checking to see if '" << getPassesString(Prefix)
            << "' compile correctly: ";

  // If it is not broken with the kept passes, it's possible that the prefix
  // passes must be run before the kept passes to break it.  If the program
  // WORKS after the prefix passes, but then fails if running the prefix AND
  // kept passes, we can update our bytecode file to include the result of the
  // prefix passes, then discard the prefix passes.
  //
  if (BD.runPasses(Prefix, BytecodeResult, false/*delete*/, true/*quiet*/)) {
    std::cerr << BD.getToolName() << ": Error running this sequence of passes"
              << " on the input program!\n";
    exit(1);
  }

  // If the prefix maintains the predicate by itself, only keep the prefix!
  if (BD.diffProgram(BytecodeResult)) {
    std::cout << "nope.\n";
    removeFile(BytecodeResult);
    return KeepPrefix;
  }
  std::cout << "yup.\n";      // No miscompilation!

  // Ok, so now we know that the prefix passes work, try running the suffix
  // passes on the result of the prefix passes.
  //
  Module *PrefixOutput = BD.ParseInputFile(BytecodeResult);
  if (PrefixOutput == 0) {
    std::cerr << BD.getToolName() << ": Error reading bytecode file '"
              << BytecodeResult << "'!\n";
    exit(1);
  }
  removeFile(BytecodeResult);  // No longer need the file on disk

  std::cout << "Checking to see if '" << getPassesString(Suffix)
            << "' passes compile correctly after the '"
            << getPassesString(Prefix) << "' passes: ";

  Module *OriginalInput = BD.Program;
  BD.Program = PrefixOutput;
  if (BD.runPasses(Suffix, BytecodeResult, false/*delete*/, true/*quiet*/)) {
    std::cerr << BD.getToolName() << ": Error running this sequence of passes"
              << " on the input program!\n";
    exit(1);
  }

  // Run the result...
  if (BD.diffProgram(BytecodeResult, "", true/*delete bytecode*/)) {
    std::cout << "nope.\n";
    delete OriginalInput;     // We pruned down the original input...
    return KeepSuffix;
  }

  // Otherwise, we must not be running the bad pass anymore.
  std::cout << "yup.\n";      // No miscompilation!
  BD.Program = OriginalInput; // Restore original program
  delete PrefixOutput;        // Free experiment
  return NoFailure;
}

class ReduceMiscompilingFunctions : public ListReducer<Function*> {
  BugDriver &BD;
public:
  ReduceMiscompilingFunctions(BugDriver &bd) : BD(bd) {}

  virtual TestResult doTest(std::vector<Function*> &Prefix,
                            std::vector<Function*> &Suffix) {
    if (!Suffix.empty() && TestFuncs(Suffix, false))
      return KeepSuffix;
    if (!Prefix.empty() && TestFuncs(Prefix, false))
      return KeepPrefix;
    return NoFailure;
  }

  bool TestFuncs(const std::vector<Function*> &Prefix, bool EmitBytecode);
};

bool ReduceMiscompilingFunctions::TestFuncs(const std::vector<Function*> &Funcs,
                                            bool EmitBytecode) {
  // Test to see if the function is misoptimized if we ONLY run it on the
  // functions listed in Funcs.
  if (!EmitBytecode) {
    std::cout << "Checking to see if the program is misoptimized when these "
              << "functions are run\nthrough the passes: ";
    BD.PrintFunctionList(Funcs);
    std::cout << "\n";
  } else {
    std::cout <<"Outputting reduced bytecode files which expose the problem:\n";
  }

  // First step: clone the module for the two halves of the program we want.
  Module *ToOptimize = CloneModule(BD.Program);

  // Second step: Make sure functions & globals are all external so that linkage
  // between the two modules will work.
  for (Module::iterator I = ToOptimize->begin(), E = ToOptimize->end();I!=E;++I)
    I->setLinkage(GlobalValue::ExternalLinkage);
  for (Module::giterator I = ToOptimize->gbegin(), E = ToOptimize->gend();
       I != E; ++I)
    I->setLinkage(GlobalValue::ExternalLinkage);

  // Third step: make a clone of the externalized program for the non-optimized
  // part.
  Module *ToNotOptimize = CloneModule(ToOptimize);

  // Fourth step: Remove the test functions from the ToNotOptimize module, and
  // all of the global variables.
  for (unsigned i = 0, e = Funcs.size(); i != e; ++i) {
    Function *TNOF = ToNotOptimize->getFunction(Funcs[i]->getName(),
                                                Funcs[i]->getFunctionType());
    assert(TNOF && "Function doesn't exist in module!");
    DeleteFunctionBody(TNOF);       // Function is now external in this module!
  }
  for (Module::giterator I = ToNotOptimize->gbegin(), E = ToNotOptimize->gend();
       I != E; ++I)
    I->setInitializer(0);  // Delete the initializer to make it external

  if (EmitBytecode) {
    std::cout << "  Non-optimized portion: ";
    std::swap(BD.Program, ToNotOptimize);
    BD.EmitProgressBytecode("tonotoptimize", true);
    std::swap(BD.Program, ToNotOptimize);
  }

  // Fifth step: Remove all functions from the ToOptimize module EXCEPT for the
  // ones specified in Funcs.  We know which ones these are because they are
  // non-external in ToOptimize, but external in ToNotOptimize.
  //
  for (Module::iterator I = ToOptimize->begin(), E = ToOptimize->end();I!=E;++I)
    if (!I->isExternal()) {
      Function *TNOF = ToNotOptimize->getFunction(I->getName(),
                                                  I->getFunctionType());
      assert(TNOF && "Function doesn't exist in ToNotOptimize module??");
      if (!TNOF->isExternal())
        DeleteFunctionBody(I);
    }

  if (EmitBytecode) {
    std::cout << "  Portion that is input to optimizer: ";
    std::swap(BD.Program, ToOptimize);
    BD.EmitProgressBytecode("tooptimize");
    std::swap(BD.Program, ToOptimize);
  }

  // Sixth step: Run the optimization passes on ToOptimize, producing a
  // transformed version of the functions being tested.
  Module *OldProgram = BD.Program;
  BD.Program = ToOptimize;

  if (!EmitBytecode)
    std::cout << "  Optimizing functions being tested: ";
  std::string BytecodeResult;
  if (BD.runPasses(BD.PassesToRun, BytecodeResult, false/*delete*/,
                   true/*quiet*/)) {
    std::cerr << BD.getToolName() << ": Error running this sequence of passes"
              << " on the input program!\n";
    exit(1);
  }

  if (!EmitBytecode)
    std::cout << "done.\n";

  delete BD.Program;   // Delete the old "ToOptimize" module
  BD.Program = BD.ParseInputFile(BytecodeResult);

  if (EmitBytecode) {
    std::cout << "  'tooptimize' after being optimized: ";
    BD.EmitProgressBytecode("optimized", true);
  }

  if (BD.Program == 0) {
    std::cerr << BD.getToolName() << ": Error reading bytecode file '"
              << BytecodeResult << "'!\n";
    exit(1);
  }
  removeFile(BytecodeResult);  // No longer need the file on disk

  // Seventh step: Link the optimized part of the program back to the
  // unoptimized part of the program.
  //
  if (LinkModules(BD.Program, ToNotOptimize, &BytecodeResult)) {
    std::cerr << BD.getToolName() << ": Error linking modules together:"
              << BytecodeResult << "\n";
    exit(1);
  }
  delete ToNotOptimize;  // We are done with this module...

  if (EmitBytecode) {
    std::cout << "  Program as tested: ";
    BD.EmitProgressBytecode("linked", true);
    delete BD.Program;
    BD.Program = OldProgram;
    return false;   // We don't need to actually execute the program here.
  }

  std::cout << "  Checking to see if the merged program executes correctly: ";

  // Eighth step: Execute the program.  If it does not match the expected
  // output, then 'Funcs' are being misoptimized!
  bool Broken = BD.diffProgram();

  delete BD.Program;  // Delete the hacked up program
  BD.Program = OldProgram;   // Restore the original

  std::cout << (Broken ? "nope.\n" : "yup.\n");
  return Broken;
}

/// debugMiscompilation - This method is used when the passes selected are not
/// crashing, but the generated output is semantically different from the
/// input.
///
bool BugDriver::debugMiscompilation() {

  if (diffProgram()) {
    std::cout << "\n*** Input program does not match reference diff!\n"
              << "    Must be problem with input source!\n";
    return false;  // Problem found
  }

  // Make sure something was miscompiled...
  if (!ReduceMiscompilingPasses(*this).reduceList(PassesToRun)) {
    std::cerr << "*** Optimized program matches reference output!  No problem "
	      << "detected...\nbugpoint can't help you with your problem!\n";
    return false;
  }

  std::cout << "\n*** Found miscompiling pass"
            << (PassesToRun.size() == 1 ? "" : "es") << ": "
            << getPassesString(PassesToRun) << "\n";
  EmitProgressBytecode("passinput");

  // Okay, now that we have reduced the list of passes which are causing the
  // failure, see if we can pin down which functions are being
  // miscompiled... first build a list of all of the non-external functions in
  // the program.
  std::vector<Function*> MiscompiledFunctions;
  for (Module::iterator I = Program->begin(), E = Program->end(); I != E; ++I)
    if (!I->isExternal())
      MiscompiledFunctions.push_back(I);

  // Do the reduction...
  ReduceMiscompilingFunctions(*this).reduceList(MiscompiledFunctions);

  std::cout << "\n*** The following functions are being miscompiled: ";
  PrintFunctionList(MiscompiledFunctions);
  std::cout << "\n";

  // Output a bunch of bytecode files for the user...
  ReduceMiscompilingFunctions(*this).TestFuncs(MiscompiledFunctions, true);

  return false;
}
<|endoftext|>


<commit_before>#include <Eigen/Dense>
#include <Eigen/Sparse>

#include <iomanip>

#include "mvnormal.h"
#include "session.h"
#include "chol.h"
#include "linop.h"
#include "noisemodels.h"
#include "latentprior.h"
#include "data.h"

using namespace std;
using namespace Eigen;

namespace Macau {

ILatentPrior::ILatentPrior(BaseSession &m, int p, std::string name)
    : session(m), mode(p), name(name) {}

std::ostream &ILatentPrior::info(std::ostream &os, std::string indent)
{
    os << indent << mode << ": " << name << "\n";
    return os;
}

Model &ILatentPrior::model() { return session.model; }
Data &ILatentPrior::data() { return *session.data; }
INoiseModel &ILatentPrior::noise() { return *data().noise; }
MatrixXd &ILatentPrior::U() { return model().U(mode); }
MatrixXd &ILatentPrior::V() { return model().V(mode); }

void ILatentPrior::init()
{
    rrs.init(VectorNd::Zero(num_latent()));
    MMs.init(MatrixNNd::Zero(num_latent(), num_latent()));
}

void ILatentPrior::sample_latents()
{
    session.data->update_pnm(model(), mode);
#pragma omp parallel for schedule(guided)
    for(int n = 0; n < U().cols(); n++) {
#pragma omp task
        sample_latent(n);
    }
}

/**
 *  base class NormalPrior
 */

NormalPrior::NormalPrior(BaseSession &m, int p, std::string name)
    : ILatentPrior(m, p, name) {}

void NormalPrior::init() {
    ILatentPrior::init();

    initUU();

    const int K = num_latent();
    mu.resize(K);
    mu.setZero();

    Lambda.resize(K, K);
    Lambda.setIdentity();
    Lambda *= 10;

    // parameters of Inv-Whishart distribution
    WI.resize(K, K);
    WI.setIdentity();
    mu0.resize(K);
    mu0.setZero();
    b0 = 2;
    df = K;
}

void NormalPrior::initUU()
{
  Ucol.init(VectorNd::Zero(num_latent())),
  UUcol.init(MatrixNNd::Zero(num_latent(), num_latent()));
  UUcol.local() = U() * U().transpose();
  Ucol.local() = U().rowwise().sum();
}

void NormalPrior::sample_latents() {

    const int N = num_cols();
    const auto cov = UUcol.combine();
    const auto sum = Ucol.combine();
    tie(mu, Lambda) = CondNormalWishart(N, cov / N, sum / N, mu0, b0, WI, df);

    UUcol.reset();
    Ucol.reset();

    ILatentPrior::sample_latents();
}

void NormalPrior::sample_latent(int n)
{
    const auto &mu_u = getMu(n);

    VectorNd &rr = rrs.local();
    MatrixNNd &MM = MMs.local();

    rr.setZero();
    MM.setZero();

    // add pnm
    session.data->get_pnm(model(),mode,n,rr,MM);

    // add hyperparams
    rr.noalias() += Lambda * mu_u;
    MM.noalias() += Lambda;

    Eigen::LLT<MatrixXd> chol = MM.llt();
    if(chol.info() != Eigen::Success) {
        throw std::runtime_error("Cholesky Decomposition failed!");
    }

    chol.matrixL().solveInPlace(rr);
    rr.noalias() += nrandn(num_latent());
    chol.matrixU().solveInPlace(rr);

    U().col(n).noalias() = rr;
    Ucol.local().noalias() += rr;
    UUcol.local().noalias() += rr * rr.transpose();

}

void NormalPrior::save(std::string prefix, std::string suffix) {
  write_dense(prefix + "-U" + std::to_string(mode) + "-latentmean" + suffix, mu);
}

void NormalPrior::restore(std::string prefix, std::string suffix) {
  read_dense(prefix + "-U" + std::to_string(mode) + "-latentmean" + suffix, mu);
  initUU();
}

} // end namespace Macau
<commit_msg>Update hyper params AFTER sampling latents<commit_after>#include <Eigen/Dense>
#include <Eigen/Sparse>

#include <iomanip>

#include "mvnormal.h"
#include "session.h"
#include "chol.h"
#include "linop.h"
#include "noisemodels.h"
#include "latentprior.h"
#include "data.h"

using namespace std;
using namespace Eigen;

namespace Macau {

ILatentPrior::ILatentPrior(BaseSession &m, int p, std::string name)
    : session(m), mode(p), name(name) {}

std::ostream &ILatentPrior::info(std::ostream &os, std::string indent)
{
    os << indent << mode << ": " << name << "\n";
    return os;
}

Model &ILatentPrior::model() { return session.model; }
Data &ILatentPrior::data() { return *session.data; }
INoiseModel &ILatentPrior::noise() { return *data().noise; }
MatrixXd &ILatentPrior::U() { return model().U(mode); }
MatrixXd &ILatentPrior::V() { return model().V(mode); }

void ILatentPrior::init()
{
    rrs.init(VectorNd::Zero(num_latent()));
    MMs.init(MatrixNNd::Zero(num_latent(), num_latent()));
}

void ILatentPrior::sample_latents()
{
    session.data->update_pnm(model(), mode);
#pragma omp parallel for schedule(guided)
    for(int n = 0; n < U().cols(); n++) {
#pragma omp task
        sample_latent(n);
    }
}

/**
 *  base class NormalPrior
 */

NormalPrior::NormalPrior(BaseSession &m, int p, std::string name)
    : ILatentPrior(m, p, name) {}

void NormalPrior::init() {
    ILatentPrior::init();

    initUU();

    const int K = num_latent();
    mu.resize(K);
    mu.setZero();

    Lambda.resize(K, K);
    Lambda.setIdentity();
    Lambda *= 10;

    // parameters of Inv-Whishart distribution
    WI.resize(K, K);
    WI.setIdentity();
    mu0.resize(K);
    mu0.setZero();
    b0 = 2;
    df = K;
}

void NormalPrior::initUU()
{
    const int K = num_latent();
    Ucol.init(VectorNd::Zero(K));
    UUcol.init(MatrixNNd::Zero(K, K));
    UUcol.local() = U() * U().transpose();
    Ucol.local() = U().rowwise().sum();
}

void NormalPrior::sample_latents()
{
    ILatentPrior::sample_latents();

    const int N = num_cols();
    const auto cov = UUcol.combine_and_reset();
    const auto sum = Ucol.combine_and_reset();
    //tie(mu, Lambda) = CondNormalWishart(N, cov / N, sum / N, mu0, b0, WI, df);
    //tie(mu, Lambda) = CondNormalWishart(U(), mu0, b0, WI, df);

    SHOW(N);
    SHOW(mu.norm());
    SHOW(Lambda.norm());
}

void NormalPrior::sample_latent(int n)
{
    const auto &mu_u = getMu(n);

    VectorNd &rr = rrs.local();
    MatrixNNd &MM = MMs.local();

    rr.setZero();
    MM.setZero();

    // add pnm
    session.data->get_pnm(model(),mode,n,rr,MM);

    // add hyperparams
    rr.noalias() += Lambda * mu_u;
    MM.noalias() += Lambda;

    Eigen::LLT<MatrixXd> chol = MM.llt();
    if(chol.info() != Eigen::Success) {
        throw std::runtime_error("Cholesky Decomposition failed!");
    }

    chol.matrixL().solveInPlace(rr);
    rr.noalias() += nrandn(num_latent());
    chol.matrixU().solveInPlace(rr);

    U().col(n).noalias() = rr;
    Ucol.local().noalias() += rr;
    UUcol.local().noalias() += rr * rr.transpose();

}

void NormalPrior::save(std::string prefix, std::string suffix) {
  write_dense(prefix + "-U" + std::to_string(mode) + "-latentmean" + suffix, mu);
}

void NormalPrior::restore(std::string prefix, std::string suffix) {
  read_dense(prefix + "-U" + std::to_string(mode) + "-latentmean" + suffix, mu);
  initUU();
}

} // end namespace Macau
<|endoftext|>


<commit_before>#include "Runtime/GuiSys/CTextParser.hpp"

#include "Runtime/GuiSys/CFontImageDef.hpp"
#include "Runtime/GuiSys/CTextExecuteBuffer.hpp"

namespace urde {

static float u16stof(char16_t* str) {
  char cstr[16];
  int i;
  for (i = 0; i < 15 && str[i] != u'\0'; ++i)
    cstr[i] = str[i];
  cstr[i] = '\0';
  return strtof(cstr, nullptr);
}

CTextColor CTextParser::ParseColor(const char16_t* str, int len) {
  u8 r = GetColorValue(str + 1);
  u8 g = GetColorValue(str + 3);
  u8 b = GetColorValue(str + 5);
  u8 a = 0xff;
  if (len == 9)
    a = GetColorValue(str + 7);
  CTextColor ret;
  ret.fromRGBA8(r, g, b, a);
  return ret;
}

u8 CTextParser::GetColorValue(const char16_t* str) { return (FromHex(str[0]) << 4) + FromHex(str[1]); }

u32 CTextParser::FromHex(char16_t ch) {
  if (ch >= u'0' && ch <= u'9')
    return ch - u'0';

  if (ch >= u'A' && ch <= u'F')
    return ch - u'A' + 10;

  if (ch >= u'a' && ch <= u'f')
    return ch - u'a' + 10;

  return 0;
}

s32 CTextParser::ParseInt(const char16_t* str, int len, bool signVal) {
  bool neg = false;
  int procCur = 0;
  if (signVal && len && *str == u'-') {
    neg = true;
    procCur = 1;
  }

  int val = 0;
  while (len > procCur) {
    val *= 10;
    wchar_t ch = str[procCur];
    val += ch - u'0';
    ++procCur;
  }

  return neg ? -val : val;
}

bool CTextParser::Equals(const char16_t* str, int len, const char16_t* other) {
  for (int i = 0; *other && i < len; ++i, ++str, ++other) {
    if (*str != *other)
      return false;
  }
  return *other == u'\0';
}

bool CTextParser::BeginsWith(const char16_t* str, int len, const char16_t* other) {
  for (int i = 0; *other && i < len; ++i, ++str, ++other) {
    if (*str != *other)
      return false;
  }
  return true;
}

void CTextParser::ParseTag(CTextExecuteBuffer& out, const char16_t* str, int len,
                           const std::vector<std::pair<CAssetId, CAssetId>>* txtrMap) {
  if (BeginsWith(str, len, u"font=")) {
    TToken<CRasterFont> font = GetFont(str + 5, len - 5);
    out.AddFont(font);
  } else if (BeginsWith(str, len, u"image=")) {
    CFontImageDef image = GetImage(str + 6, len - 6, txtrMap);
    out.AddImage(image);
  } else if (BeginsWith(str, len, u"fg-color=")) {
    CTextColor color = ParseColor(str + 9, len - 9);
    out.AddColor(EColorType::Foreground, color);
  } else if (BeginsWith(str, len, u"main-color=")) {
    CTextColor color = ParseColor(str + 11, len - 11);
    out.AddColor(EColorType::Main, color);
  } else if (BeginsWith(str, len, u"geometry-color=")) {
    CTextColor color = ParseColor(str + 15, len - 15);
    out.AddColor(EColorType::Geometry, color);
  } else if (BeginsWith(str, len, u"outline-color=")) {
    CTextColor color = ParseColor(str + 14, len - 14);
    out.AddColor(EColorType::Outline, color);
  } else if (BeginsWith(str, len, u"color")) {
    const char16_t* valCur = str + 7;
    len -= 7;
    int val = str[6] - u'0';
    if (str[7] >= u'0' && str[7] <= u'9') {
      ++valCur;
      --len;
      val *= 10;
      val += str[7] - u'0';
    }

    if (Equals(valCur + 10, len - 10, u"no"))
      out.AddRemoveColorOverride(val);
    else {
      CTextColor color = ParseColor(str + 10, len - 10);
      out.AddColorOverride(val, color);
    }
  } else if (BeginsWith(str, len, u"line-spacing=")) {
    out.AddLineSpacing(ParseInt(str + 13, len - 13, true) / 100.0);
  } else if (BeginsWith(str, len, u"line-extra-space=")) {
    out.AddLineExtraSpace(ParseInt(str + 17, len - 17, true));
  } else if (BeginsWith(str, len, u"just=")) {
    if (Equals(str + 5, len - 5, u"left"))
      out.AddJustification(EJustification::Left);
    else if (Equals(str + 5, len - 5, u"center"))
      out.AddJustification(EJustification::Center);
    else if (Equals(str + 5, len - 5, u"right"))
      out.AddJustification(EJustification::Right);
    else if (Equals(str + 5, len - 5, u"full"))
      out.AddJustification(EJustification::Full);
    else if (Equals(str + 5, len - 5, u"nleft"))
      out.AddJustification(EJustification::NLeft);
    else if (Equals(str + 5, len - 5, u"ncenter"))
      out.AddJustification(EJustification::NCenter);
    else if (Equals(str + 5, len - 5, u"nright"))
      out.AddJustification(EJustification::NRight);
  } else if (BeginsWith(str, len, u"vjust=")) {
    if (Equals(str + 6, len - 6, u"top"))
      out.AddVerticalJustification(EVerticalJustification::Top);
    else if (Equals(str + 6, len - 6, u"center"))
      out.AddVerticalJustification(EVerticalJustification::Center);
    else if (Equals(str + 6, len - 6, u"bottom"))
      out.AddVerticalJustification(EVerticalJustification::Bottom);
    else if (Equals(str + 6, len - 6, u"full"))
      out.AddVerticalJustification(EVerticalJustification::Full);
    else if (Equals(str + 6, len - 6, u"ntop"))
      out.AddVerticalJustification(EVerticalJustification::NTop);
    else if (Equals(str + 6, len - 6, u"ncenter"))
      out.AddVerticalJustification(EVerticalJustification::NCenter);
    else if (Equals(str + 6, len - 6, u"nbottom"))
      out.AddVerticalJustification(EVerticalJustification::NBottom);
  } else if (Equals(str, len, u"push")) {
    out.AddPushState();
  } else if (Equals(str, len, u"pop")) {
    out.AddPopState();
  }
}

CFontImageDef CTextParser::GetImage(const char16_t* str, int len,
                                    const std::vector<std::pair<CAssetId, CAssetId>>* txtrMap) {
  int commaCount = 0;
  for (int i = 0; i < len; ++i)
    if (str[i] == u',')
      ++commaCount;

  if (commaCount) {
    std::u16string iterable(str, len);
    size_t tokenPos;
    size_t commaPos;
    commaPos = iterable.find(u',');
    iterable[commaPos] = u'\0';
    tokenPos = commaPos + 1;

    auto AdvanceCommaPos = [&]() {
      commaPos = iterable.find(u',', tokenPos);
      if (commaPos == std::u16string::npos)
        commaPos = iterable.size();
      iterable[commaPos] = u'\0';
    };

    auto AdvanceTokenPos = [&]() { tokenPos = commaPos + 1; };

    if (BeginsWith(str, len, u"A")) {
      /* Animated texture array */
      AdvanceCommaPos();
      float interval = u16stof(&iterable[tokenPos]);
      AdvanceTokenPos();

      std::vector<TToken<CTexture>> texs;
      texs.reserve(commaCount - 1);
      do {
        AdvanceCommaPos();
        texs.push_back(x0_store.GetObj({SBIG('TXTR'), GetAssetIdFromString(&iterable[tokenPos], len, txtrMap)}));
        AdvanceTokenPos();
      } while (commaPos != iterable.size());

      return CFontImageDef(texs, interval, zeus::CVector2f(1.f, 1.f));
    } else if (BeginsWith(str, len, u"SA")) {
      /* Scaled and animated texture array */
      AdvanceCommaPos();
      float interval = u16stof(&iterable[tokenPos]);
      AdvanceTokenPos();

      AdvanceCommaPos();
      float cropX = u16stof(&iterable[tokenPos]);
      AdvanceTokenPos();

      AdvanceCommaPos();
      float cropY = u16stof(&iterable[tokenPos]);
      AdvanceTokenPos();

      std::vector<TToken<CTexture>> texs;
      texs.reserve(commaCount - 3);
      do {
        AdvanceCommaPos();
        texs.push_back(x0_store.GetObj({SBIG('TXTR'), GetAssetIdFromString(&iterable[tokenPos], len, txtrMap)}));
        AdvanceTokenPos();
      } while (commaPos != iterable.size());

      return CFontImageDef(texs, interval, zeus::CVector2f(cropX, cropY));
    } else if (BeginsWith(str, len, u"SI")) {
      /* Scaled single texture */
      AdvanceCommaPos();
      float cropX = u16stof(&iterable[tokenPos]);
      AdvanceTokenPos();

      AdvanceCommaPos();
      float cropY = u16stof(&iterable[tokenPos]);
      AdvanceTokenPos();

      AdvanceCommaPos();
      TToken<CTexture> tex = x0_store.GetObj({SBIG('TXTR'), GetAssetIdFromString(&iterable[tokenPos], len, txtrMap)});
      AdvanceTokenPos();

      return CFontImageDef(tex, zeus::CVector2f(cropX, cropY));
    }
  }

  TToken<CTexture> tex = x0_store.GetObj({SBIG('TXTR'), GetAssetIdFromString(str, len, txtrMap)});
  return CFontImageDef(tex, zeus::CVector2f(1.f, 1.f));
}

CAssetId CTextParser::GetAssetIdFromString(const char16_t* str, int len,
                                           const std::vector<std::pair<CAssetId, CAssetId>>* txtrMap) {
  u8 r = GetColorValue(str);
  u8 g = GetColorValue(str + 2);
  u8 b = GetColorValue(str + 4);
  u8 a = GetColorValue(str + 6);
  CAssetId id = ((r << 24) | (g << 16) | (b << 8) | a) & 0xffffffff;

  if (len == 16) {
    r = GetColorValue(str + 8);
    g = GetColorValue(str + 10);
    b = GetColorValue(str + 12);
    a = GetColorValue(str + 14);
    id = (id.Value() << 32) | (((r << 24) | (g << 16) | (b << 8) | a) & 0xffffffff);
  }

  if (txtrMap) {
    auto search = rstl::binary_find(txtrMap->begin(), txtrMap->end(), id,
                                    [](const std::pair<CAssetId, CAssetId>& a) { return a.first; });
    if (search != txtrMap->end())
      id = search->second;
  }

  return id;
}

TToken<CRasterFont> CTextParser::GetFont(const char16_t* str, int len) {
  return x0_store.GetObj({SBIG('FONT'), GetAssetIdFromString(str, len, nullptr)});
}

void CTextParser::ParseText(CTextExecuteBuffer& out, const char16_t* str, int len,
                            const std::vector<std::pair<CAssetId, CAssetId>>* txtrMap) {
  int b = 0, e = 0;
  for (b = 0, e = 0; str[e] && (len == -1 || e < len);) {
    if (str[e] != u'&') {
      ++e;
      continue;
    }
    if ((len == -1 || e + 1 < len) && str[e + 1] != u'&') {
      if (e > b)
        out.AddString(str + b, e - b);
      ++e;
      b = e;

      while (str[e] && (len == -1 || e < len) && str[e] != u';')
        ++e;

      ParseTag(out, str + b, e - b, txtrMap);
      b = e + 1;
    } else {
      out.AddString(str + b, e + 1 - b);
      e += 2;
      b = e;
    }
  }

  if (e > b)
    out.AddString(str + b, e - b);
}

} // namespace urde
<commit_msg>CTextParser: Resolve double->float truncation within ParseTag()<commit_after>#include "Runtime/GuiSys/CTextParser.hpp"

#include "Runtime/GuiSys/CFontImageDef.hpp"
#include "Runtime/GuiSys/CTextExecuteBuffer.hpp"

namespace urde {

static float u16stof(char16_t* str) {
  char cstr[16];
  int i;
  for (i = 0; i < 15 && str[i] != u'\0'; ++i)
    cstr[i] = str[i];
  cstr[i] = '\0';
  return strtof(cstr, nullptr);
}

CTextColor CTextParser::ParseColor(const char16_t* str, int len) {
  u8 r = GetColorValue(str + 1);
  u8 g = GetColorValue(str + 3);
  u8 b = GetColorValue(str + 5);
  u8 a = 0xff;
  if (len == 9)
    a = GetColorValue(str + 7);
  CTextColor ret;
  ret.fromRGBA8(r, g, b, a);
  return ret;
}

u8 CTextParser::GetColorValue(const char16_t* str) { return (FromHex(str[0]) << 4) + FromHex(str[1]); }

u32 CTextParser::FromHex(char16_t ch) {
  if (ch >= u'0' && ch <= u'9')
    return ch - u'0';

  if (ch >= u'A' && ch <= u'F')
    return ch - u'A' + 10;

  if (ch >= u'a' && ch <= u'f')
    return ch - u'a' + 10;

  return 0;
}

s32 CTextParser::ParseInt(const char16_t* str, int len, bool signVal) {
  bool neg = false;
  int procCur = 0;
  if (signVal && len && *str == u'-') {
    neg = true;
    procCur = 1;
  }

  int val = 0;
  while (len > procCur) {
    val *= 10;
    wchar_t ch = str[procCur];
    val += ch - u'0';
    ++procCur;
  }

  return neg ? -val : val;
}

bool CTextParser::Equals(const char16_t* str, int len, const char16_t* other) {
  for (int i = 0; *other && i < len; ++i, ++str, ++other) {
    if (*str != *other)
      return false;
  }
  return *other == u'\0';
}

bool CTextParser::BeginsWith(const char16_t* str, int len, const char16_t* other) {
  for (int i = 0; *other && i < len; ++i, ++str, ++other) {
    if (*str != *other)
      return false;
  }
  return true;
}

void CTextParser::ParseTag(CTextExecuteBuffer& out, const char16_t* str, int len,
                           const std::vector<std::pair<CAssetId, CAssetId>>* txtrMap) {
  if (BeginsWith(str, len, u"font=")) {
    TToken<CRasterFont> font = GetFont(str + 5, len - 5);
    out.AddFont(font);
  } else if (BeginsWith(str, len, u"image=")) {
    CFontImageDef image = GetImage(str + 6, len - 6, txtrMap);
    out.AddImage(image);
  } else if (BeginsWith(str, len, u"fg-color=")) {
    CTextColor color = ParseColor(str + 9, len - 9);
    out.AddColor(EColorType::Foreground, color);
  } else if (BeginsWith(str, len, u"main-color=")) {
    CTextColor color = ParseColor(str + 11, len - 11);
    out.AddColor(EColorType::Main, color);
  } else if (BeginsWith(str, len, u"geometry-color=")) {
    CTextColor color = ParseColor(str + 15, len - 15);
    out.AddColor(EColorType::Geometry, color);
  } else if (BeginsWith(str, len, u"outline-color=")) {
    CTextColor color = ParseColor(str + 14, len - 14);
    out.AddColor(EColorType::Outline, color);
  } else if (BeginsWith(str, len, u"color")) {
    const char16_t* valCur = str + 7;
    len -= 7;
    int val = str[6] - u'0';
    if (str[7] >= u'0' && str[7] <= u'9') {
      ++valCur;
      --len;
      val *= 10;
      val += str[7] - u'0';
    }

    if (Equals(valCur + 10, len - 10, u"no"))
      out.AddRemoveColorOverride(val);
    else {
      CTextColor color = ParseColor(str + 10, len - 10);
      out.AddColorOverride(val, color);
    }
  } else if (BeginsWith(str, len, u"line-spacing=")) {
    out.AddLineSpacing(ParseInt(str + 13, len - 13, true) / 100.0f);
  } else if (BeginsWith(str, len, u"line-extra-space=")) {
    out.AddLineExtraSpace(ParseInt(str + 17, len - 17, true));
  } else if (BeginsWith(str, len, u"just=")) {
    if (Equals(str + 5, len - 5, u"left"))
      out.AddJustification(EJustification::Left);
    else if (Equals(str + 5, len - 5, u"center"))
      out.AddJustification(EJustification::Center);
    else if (Equals(str + 5, len - 5, u"right"))
      out.AddJustification(EJustification::Right);
    else if (Equals(str + 5, len - 5, u"full"))
      out.AddJustification(EJustification::Full);
    else if (Equals(str + 5, len - 5, u"nleft"))
      out.AddJustification(EJustification::NLeft);
    else if (Equals(str + 5, len - 5, u"ncenter"))
      out.AddJustification(EJustification::NCenter);
    else if (Equals(str + 5, len - 5, u"nright"))
      out.AddJustification(EJustification::NRight);
  } else if (BeginsWith(str, len, u"vjust=")) {
    if (Equals(str + 6, len - 6, u"top"))
      out.AddVerticalJustification(EVerticalJustification::Top);
    else if (Equals(str + 6, len - 6, u"center"))
      out.AddVerticalJustification(EVerticalJustification::Center);
    else if (Equals(str + 6, len - 6, u"bottom"))
      out.AddVerticalJustification(EVerticalJustification::Bottom);
    else if (Equals(str + 6, len - 6, u"full"))
      out.AddVerticalJustification(EVerticalJustification::Full);
    else if (Equals(str + 6, len - 6, u"ntop"))
      out.AddVerticalJustification(EVerticalJustification::NTop);
    else if (Equals(str + 6, len - 6, u"ncenter"))
      out.AddVerticalJustification(EVerticalJustification::NCenter);
    else if (Equals(str + 6, len - 6, u"nbottom"))
      out.AddVerticalJustification(EVerticalJustification::NBottom);
  } else if (Equals(str, len, u"push")) {
    out.AddPushState();
  } else if (Equals(str, len, u"pop")) {
    out.AddPopState();
  }
}

CFontImageDef CTextParser::GetImage(const char16_t* str, int len,
                                    const std::vector<std::pair<CAssetId, CAssetId>>* txtrMap) {
  int commaCount = 0;
  for (int i = 0; i < len; ++i)
    if (str[i] == u',')
      ++commaCount;

  if (commaCount) {
    std::u16string iterable(str, len);
    size_t tokenPos;
    size_t commaPos;
    commaPos = iterable.find(u',');
    iterable[commaPos] = u'\0';
    tokenPos = commaPos + 1;

    auto AdvanceCommaPos = [&]() {
      commaPos = iterable.find(u',', tokenPos);
      if (commaPos == std::u16string::npos)
        commaPos = iterable.size();
      iterable[commaPos] = u'\0';
    };

    auto AdvanceTokenPos = [&]() { tokenPos = commaPos + 1; };

    if (BeginsWith(str, len, u"A")) {
      /* Animated texture array */
      AdvanceCommaPos();
      float interval = u16stof(&iterable[tokenPos]);
      AdvanceTokenPos();

      std::vector<TToken<CTexture>> texs;
      texs.reserve(commaCount - 1);
      do {
        AdvanceCommaPos();
        texs.push_back(x0_store.GetObj({SBIG('TXTR'), GetAssetIdFromString(&iterable[tokenPos], len, txtrMap)}));
        AdvanceTokenPos();
      } while (commaPos != iterable.size());

      return CFontImageDef(texs, interval, zeus::CVector2f(1.f, 1.f));
    } else if (BeginsWith(str, len, u"SA")) {
      /* Scaled and animated texture array */
      AdvanceCommaPos();
      float interval = u16stof(&iterable[tokenPos]);
      AdvanceTokenPos();

      AdvanceCommaPos();
      float cropX = u16stof(&iterable[tokenPos]);
      AdvanceTokenPos();

      AdvanceCommaPos();
      float cropY = u16stof(&iterable[tokenPos]);
      AdvanceTokenPos();

      std::vector<TToken<CTexture>> texs;
      texs.reserve(commaCount - 3);
      do {
        AdvanceCommaPos();
        texs.push_back(x0_store.GetObj({SBIG('TXTR'), GetAssetIdFromString(&iterable[tokenPos], len, txtrMap)}));
        AdvanceTokenPos();
      } while (commaPos != iterable.size());

      return CFontImageDef(texs, interval, zeus::CVector2f(cropX, cropY));
    } else if (BeginsWith(str, len, u"SI")) {
      /* Scaled single texture */
      AdvanceCommaPos();
      float cropX = u16stof(&iterable[tokenPos]);
      AdvanceTokenPos();

      AdvanceCommaPos();
      float cropY = u16stof(&iterable[tokenPos]);
      AdvanceTokenPos();

      AdvanceCommaPos();
      TToken<CTexture> tex = x0_store.GetObj({SBIG('TXTR'), GetAssetIdFromString(&iterable[tokenPos], len, txtrMap)});
      AdvanceTokenPos();

      return CFontImageDef(tex, zeus::CVector2f(cropX, cropY));
    }
  }

  TToken<CTexture> tex = x0_store.GetObj({SBIG('TXTR'), GetAssetIdFromString(str, len, txtrMap)});
  return CFontImageDef(tex, zeus::CVector2f(1.f, 1.f));
}

CAssetId CTextParser::GetAssetIdFromString(const char16_t* str, int len,
                                           const std::vector<std::pair<CAssetId, CAssetId>>* txtrMap) {
  u8 r = GetColorValue(str);
  u8 g = GetColorValue(str + 2);
  u8 b = GetColorValue(str + 4);
  u8 a = GetColorValue(str + 6);
  CAssetId id = ((r << 24) | (g << 16) | (b << 8) | a) & 0xffffffff;

  if (len == 16) {
    r = GetColorValue(str + 8);
    g = GetColorValue(str + 10);
    b = GetColorValue(str + 12);
    a = GetColorValue(str + 14);
    id = (id.Value() << 32) | (((r << 24) | (g << 16) | (b << 8) | a) & 0xffffffff);
  }

  if (txtrMap) {
    auto search = rstl::binary_find(txtrMap->begin(), txtrMap->end(), id,
                                    [](const std::pair<CAssetId, CAssetId>& a) { return a.first; });
    if (search != txtrMap->end())
      id = search->second;
  }

  return id;
}

TToken<CRasterFont> CTextParser::GetFont(const char16_t* str, int len) {
  return x0_store.GetObj({SBIG('FONT'), GetAssetIdFromString(str, len, nullptr)});
}

void CTextParser::ParseText(CTextExecuteBuffer& out, const char16_t* str, int len,
                            const std::vector<std::pair<CAssetId, CAssetId>>* txtrMap) {
  int b = 0, e = 0;
  for (b = 0, e = 0; str[e] && (len == -1 || e < len);) {
    if (str[e] != u'&') {
      ++e;
      continue;
    }
    if ((len == -1 || e + 1 < len) && str[e + 1] != u'&') {
      if (e > b)
        out.AddString(str + b, e - b);
      ++e;
      b = e;

      while (str[e] && (len == -1 || e < len) && str[e] != u';')
        ++e;

      ParseTag(out, str + b, e - b, txtrMap);
      b = e + 1;
    } else {
      out.AddString(str + b, e + 1 - b);
      e += 2;
      b = e;
    }
  }

  if (e > b)
    out.AddString(str + b, e - b);
}

} // namespace urde
<|endoftext|>


<commit_before>// Filename: showBase.cxx
// Created by:  shochet (02Feb00)
//
////////////////////////////////////////////////////////////////////

#include "showBase.h"

#include <throw_event.h>
#include <camera.h>
#include <renderRelation.h>
#include <namedNode.h>
#include <renderModeTransition.h>
#include <renderModeAttribute.h>
#include <textureTransition.h>
#include <textureAttribute.h>
#include <interactiveGraphicsPipe.h>
#include <graphicsWindow.h>
#include <chancfg.h>
#include <cullFaceTransition.h>
#include <cullFaceAttribute.h>
#include <dftraverser.h>
#include <renderBuffer.h>
#include <clockObject.h>
#include <animControl.h>
#include <nodeRelation.h>
#include <dataGraphTraversal.h>
#include <depthTestTransition.h>
#include <depthTestAttribute.h>
#include <depthWriteTransition.h>
#include <depthWriteAttribute.h>
#include <lightTransition.h>
#include <materialTransition.h>
#include <camera.h>
#include <frustum.h>
#include <orthoProjection.h>
#include <appTraverser.h>
#include <get_config_path.h>
#include <allAttributesWrapper.h>
#include <dataGraphTraversal.h>

ConfigureDef(config_showbase);
ConfigureFn(config_showbase) {
}

DSearchPath &
get_particle_path() {
  static DSearchPath *particle_path = NULL;
  return get_config_path("particle-path", particle_path);
}

// Default channel config
std::string chan_config = "single";
std::string window_title = "Panda3D";

void render_frame(GraphicsPipe *pipe,
		  NodeAttributes &initial_state) {
  int num_windows = pipe->get_num_windows();
  for (int w = 0; w < num_windows; w++) {
    GraphicsWindow *win = pipe->get_window(w);
    win->get_gsg()->render_frame(initial_state);
  }
  ClockObject::get_global_clock()->tick();
  throw_event("NewFrame");
}

class WindowCallback : public GraphicsWindow::Callback {
public:
  WindowCallback(GraphicsPipe *pipe, Node *render,
		 NodeAttributes *initial_state) :
    _pipe(pipe),
    _render(render),
    _initial_state(initial_state),
    _app_traverser(RenderRelation::get_class_type()) { }
  virtual ~WindowCallback() { }

  virtual void draw(bool) {
    _app_traverser.traverse(_render);
    render_frame(_pipe, *_initial_state);
  }

  virtual void idle(void) {
  }

  PT(GraphicsPipe) _pipe;
  PT(Node) _render;
  NodeAttributes *_initial_state;
  AppTraverser _app_traverser;
};

PT(GraphicsPipe) make_graphics_pipe() {
  PT(GraphicsPipe) main_pipe;

  // load display modules
  GraphicsPipe::resolve_modules();

  nout << "Known pipe types:" << endl;
  GraphicsPipe::get_factory().write_types(nout, 2);

  // Create a window
  main_pipe = GraphicsPipe::get_factory().
    make_instance(InteractiveGraphicsPipe::get_class_type());

  if (main_pipe == (GraphicsPipe*)0L) {
    nout << "No interactive pipe is available!  Check your Configrc!\n";
    return NULL;
  }

  nout << "Opened a '" << main_pipe->get_type().get_name()
       << "' interactive graphics pipe." << endl;
  return main_pipe;
}

PT(GraphicsWindow) make_graphics_window(GraphicsPipe *pipe,
					NamedNode *render,
					NamedNode *camera,
					NodeAttributes &initial_state) {
  PT(GraphicsWindow) main_win;
  ChanCfgOverrides override;

  // Turn on backface culling
  CullFaceAttribute *cfa = new CullFaceAttribute;
  cfa->set_mode(CullFaceProperty::M_cull_clockwise);
  initial_state.set_attribute(CullFaceTransition::get_class_type(), cfa);
  DepthTestAttribute *dta = new DepthTestAttribute;
  initial_state.set_attribute(DepthTestTransition::get_class_type(), dta);
  DepthWriteAttribute *dwa = new DepthWriteAttribute;
  initial_state.set_attribute(DepthWriteTransition::get_class_type(), dwa);

  override.setField(ChanCfgOverrides::Mask,
		    ((unsigned int)(W_DOUBLE|W_DEPTH|W_MULTISAMPLE)));

  std::string title = config_showbase.GetString("window-title", window_title);
  override.setField(ChanCfgOverrides::Title, title);

  std::string conf = config_showbase.GetString("chan-config", chan_config);
  main_win = ChanConfig(pipe, conf, camera, render, override);
  assert(main_win != (GraphicsWindow*)0L);

  WindowCallback *wcb =
    new WindowCallback(pipe, render, &initial_state);

  // Set draw and idle callbacks
  main_win->set_draw_callback(wcb);
  main_win->set_idle_callback(wcb);

  return main_win;
}

// Create a scene graph, associated with the indicated window, that
// can contain 2-d geometry and will be rendered on top of the
// existing 3-d window.  Returns the top node of the scene graph.
NodePath
setup_panda_2d(GraphicsWindow *win, const string &graph_name) {
  PT(Node) render2d_top;

  render2d_top = new NamedNode(graph_name + "_top");
  Node *render2d = new NamedNode(graph_name);
  RenderRelation *render2d_arc = new RenderRelation(render2d_top, render2d);

  // Set up some overrides to turn off certain properties which we
  // probably won't need for 2-d objects.

  // It's particularly important to turn off the depth test, since
  // we'll be keeping the same depth buffer already filled by the
  // previously-drawn 3-d scene--we don't want to pay for a clear
  // operation, but we also don't want to collide with that depth
  // buffer.
  render2d_arc->set_transition(new DepthTestTransition(DepthTestProperty::M_none), 1);
  render2d_arc->set_transition(new DepthWriteTransition(DepthWriteTransition::off()), 1);
  render2d_arc->set_transition(new LightTransition(LightTransition::all_off()), 1);
  render2d_arc->set_transition(new MaterialTransition(MaterialTransition::off()), 1);
  render2d_arc->set_transition(new CullFaceTransition(CullFaceProperty::M_cull_none), 1);

  // Create a 2-d camera.
  Camera *cam2d = new Camera("cam2d");
  new RenderRelation(render2d, cam2d);

  Frustumf frustum2d;
  frustum2d.make_ortho(-1000,1000);
  cam2d->set_projection(OrthoProjection(frustum2d));

  add_render_layer(win, render2d_top, cam2d);

  NodePath render2d_np = NodePath();
  render2d_np.extend_by(render2d_arc);
  return render2d_np;
}

// Create an auxiliary scene graph starting at the indicated node,
// layered on top of the previously-created layers.
void
add_render_layer(GraphicsWindow *win, Node *render_top, Camera *camera) {
  GraphicsChannel *chan = win->get_channel(0);
  nassertv(chan != (GraphicsChannel *)NULL);

  GraphicsLayer *layer = chan->make_layer();
  nassertv(layer != (GraphicsLayer *)NULL);

  DisplayRegion *dr = layer->make_display_region();
  nassertv(dr != (DisplayRegion *)NULL);
  camera->set_scene(render_top);
  dr->set_camera(camera);
}

void
toggle_wireframe(NodeAttributes &initial_state) {
  static bool wireframe_mode = false;

  wireframe_mode = !wireframe_mode;
  if (!wireframe_mode) {
    // Set the normal, filled mode on the render arc.
    RenderModeAttribute *rma = new RenderModeAttribute;
    rma->set_mode(RenderModeProperty::M_filled);
    CullFaceAttribute *cfa = new CullFaceAttribute;
    cfa->set_mode(CullFaceProperty::M_cull_clockwise);
    initial_state.set_attribute(RenderModeTransition::get_class_type(), rma);
    initial_state.set_attribute(CullFaceTransition::get_class_type(), cfa);

  } else {
    // Set the initial state up for wireframe mode.
    RenderModeAttribute *rma = new RenderModeAttribute;
    rma->set_mode(RenderModeProperty::M_wireframe);
    CullFaceAttribute *cfa = new CullFaceAttribute;
    cfa->set_mode(CullFaceProperty::M_cull_none);
    initial_state.set_attribute(RenderModeTransition::get_class_type(), rma);
    initial_state.set_attribute(CullFaceTransition::get_class_type(), cfa);
  }
}

void
toggle_backface(NodeAttributes &initial_state) {
  static bool backface_mode = false;

  // Toggle the state variable
  backface_mode = !backface_mode;

  if (backface_mode) {
    // Turn backface culling off
    CullFaceAttribute *cfa = new CullFaceAttribute;
    cfa->set_mode(CullFaceProperty::M_cull_none);
    initial_state.set_attribute(CullFaceTransition::get_class_type(), cfa);
  } else {
    // Turn backface culling on
    CullFaceAttribute *cfa = new CullFaceAttribute;
    cfa->set_mode(CullFaceProperty::M_cull_clockwise);
    initial_state.set_attribute(CullFaceTransition::get_class_type(), cfa);
  }
}

void toggle_texture(NodeAttributes &initial_state) {
  static bool textures_enabled = true;

  textures_enabled = !textures_enabled;
  if (textures_enabled) {
    // Remove the override from the initial state.
    initial_state.clear_attribute(TextureTransition::get_class_type());
  } else {
    // Set an override on the initial state to disable texturing.
    TextureAttribute *ta = new TextureAttribute;
    ta->set_priority(100);
    initial_state.set_attribute(TextureTransition::get_class_type(), ta);
  }
}

void take_snapshot(GraphicsWindow *win, const string &name) {
  GraphicsStateGuardian* gsg = win->get_gsg();
  const RenderBuffer& rb = gsg->get_render_buffer(RenderBuffer::T_front);

  //  CPT(DisplayRegion) dr = gsg->get_current_display_region();
  CPT(DisplayRegion) dr = win->get_channel(0)->get_layer(0)->get_dr(0);
  nassertv(dr != (DisplayRegion *)NULL);

  int width = dr->get_pixel_width();
  int height = dr->get_pixel_height();

  PixelBuffer p(width, height, 3, 1, PixelBuffer::T_unsigned_byte,
		PixelBuffer::F_rgb);

  p.copy(gsg, dr, rb);
  p.write(name.c_str());
}

// Returns the configure object for accessing config variables from a
// scripting language.
ConfigShowbase &
get_config_showbase() {
  return config_showbase;
}

<commit_msg>trivial<commit_after>// Filename: showBase.cxx
// Created by:  shochet (02Feb00)
//
////////////////////////////////////////////////////////////////////

#include "showBase.h"

#include <throw_event.h>
#include <camera.h>
#include <renderRelation.h>
#include <namedNode.h>
#include <renderModeTransition.h>
#include <renderModeAttribute.h>
#include <textureTransition.h>
#include <textureAttribute.h>
#include <interactiveGraphicsPipe.h>
#include <graphicsWindow.h>
#include <chancfg.h>
#include <cullFaceTransition.h>
#include <cullFaceAttribute.h>
#include <dftraverser.h>
#include <renderBuffer.h>
#include <clockObject.h>
#include <animControl.h>
#include <nodeRelation.h>
#include <dataGraphTraversal.h>
#include <depthTestTransition.h>
#include <depthTestAttribute.h>
#include <depthWriteTransition.h>
#include <depthWriteAttribute.h>
#include <lightTransition.h>
#include <materialTransition.h>
#include <camera.h>
#include <frustum.h>
#include <orthoProjection.h>
#include <appTraverser.h>
#include <get_config_path.h>
#include <allAttributesWrapper.h>
#include <dataGraphTraversal.h>

ConfigureDef(config_showbase);
ConfigureFn(config_showbase) {
}

DSearchPath &
get_particle_path() {
  static DSearchPath *particle_path = NULL;
  return get_config_path("particle-path", particle_path);
}

// Default channel config
std::string chan_config = "single";
std::string window_title = "Panda3D";

void render_frame(GraphicsPipe *pipe,
		  NodeAttributes &initial_state) {
  int num_windows = pipe->get_num_windows();
  for (int w = 0; w < num_windows; w++) {
    GraphicsWindow *win = pipe->get_window(w);
    win->get_gsg()->render_frame(initial_state);
  }
  ClockObject::get_global_clock()->tick();
  throw_event("NewFrame");
}

class WindowCallback : public GraphicsWindow::Callback {
public:
  WindowCallback(GraphicsPipe *pipe, Node *render,
		 NodeAttributes *initial_state) :
    _pipe(pipe),
    _render(render),
    _initial_state(initial_state),
    _app_traverser(RenderRelation::get_class_type()) { }
  virtual ~WindowCallback() { }

  virtual void draw(bool) {
    _app_traverser.traverse(_render);
    render_frame(_pipe, *_initial_state);
  }

  virtual void idle(void) {
  }

  PT(GraphicsPipe) _pipe;
  PT(Node) _render;
  NodeAttributes *_initial_state;
  AppTraverser _app_traverser;
};

PT(GraphicsPipe) make_graphics_pipe() {
  PT(GraphicsPipe) main_pipe;

  // load display modules
  GraphicsPipe::resolve_modules();

  nout << "Known pipe types:" << endl;
  GraphicsPipe::get_factory().write_types(nout, 2);

  // Create a window
  main_pipe = GraphicsPipe::get_factory().
    make_instance(InteractiveGraphicsPipe::get_class_type());

  if (main_pipe == (GraphicsPipe*)0L) {
    nout << "No interactive pipe is available!  Check your Configrc!\n";
    return NULL;
  }

  nout << "Opened a '" << main_pipe->get_type().get_name()
       << "' interactive graphics pipe." << endl;
  return main_pipe;
}

PT(GraphicsWindow) make_graphics_window(GraphicsPipe *pipe,
					NamedNode *render,
					NamedNode *camera,
					NodeAttributes &initial_state) {
  PT(GraphicsWindow) main_win;
  ChanCfgOverrides override;

  // Turn on backface culling
  CullFaceAttribute *cfa = new CullFaceAttribute;
  cfa->set_mode(CullFaceProperty::M_cull_clockwise);
  initial_state.set_attribute(CullFaceTransition::get_class_type(), cfa);
  DepthTestAttribute *dta = new DepthTestAttribute;
  initial_state.set_attribute(DepthTestTransition::get_class_type(), dta);
  DepthWriteAttribute *dwa = new DepthWriteAttribute;
  initial_state.set_attribute(DepthWriteTransition::get_class_type(), dwa);

  override.setField(ChanCfgOverrides::Mask,
		    ((unsigned int)(W_DOUBLE|W_DEPTH|W_MULTISAMPLE)));

  std::string title = config_showbase.GetString("window-title", window_title);
  override.setField(ChanCfgOverrides::Title, title);

  std::string conf = config_showbase.GetString("chan-config", chan_config);
  main_win = ChanConfig(pipe, conf, camera, render, override);
  assert(main_win != (GraphicsWindow*)0L);

  WindowCallback *wcb =
    new WindowCallback(pipe, render, &initial_state);

  // Set draw and idle callbacks
  main_win->set_draw_callback(wcb);
  main_win->set_idle_callback(wcb);

  return main_win;
}

// Create a scene graph, associated with the indicated window, that
// can contain 2-d geometry and will be rendered on top of the
// existing 3-d window.  Returns the top node of the scene graph.
NodePath
setup_panda_2d(GraphicsWindow *win, const string &graph_name) {
  PT(Node) render2d_top;

  render2d_top = new NamedNode(graph_name + "_top");
  Node *render2d = new NamedNode(graph_name);
  RenderRelation *render2d_arc = new RenderRelation(render2d_top, render2d);

  // Set up some overrides to turn off certain properties which we
  // probably won't need for 2-d objects.

  // It's particularly important to turn off the depth test, since
  // we'll be keeping the same depth buffer already filled by the
  // previously-drawn 3-d scene--we don't want to pay for a clear
  // operation, but we also don't want to collide with that depth
  // buffer.
  render2d_arc->set_transition(new DepthTestTransition(DepthTestProperty::M_none), 1);
  render2d_arc->set_transition(new DepthWriteTransition(DepthWriteTransition::off()), 1);
  render2d_arc->set_transition(new LightTransition(LightTransition::all_off()), 1);
  render2d_arc->set_transition(new MaterialTransition(MaterialTransition::off()), 1);
  render2d_arc->set_transition(new CullFaceTransition(CullFaceProperty::M_cull_none), 1);

  // Create a 2-d camera.
  Camera *cam2d = new Camera("cam2d");
  new RenderRelation(render2d, cam2d);

  Frustumf frustum2d;
  frustum2d.make_ortho(-1000,1000);
  cam2d->set_projection(OrthoProjection(frustum2d));

  add_render_layer(win, render2d_top, cam2d);

  NodePath render2d_np = NodePath();
  render2d_np.extend_by(render2d_arc);
  return render2d_np;
}

// Create an auxiliary scene graph starting at the indicated node,
// layered on top of the previously-created layers.
void
add_render_layer(GraphicsWindow *win, Node *render_top, Camera *camera) {
  GraphicsChannel *chan = win->get_channel(0);
  nassertv(chan != (GraphicsChannel *)NULL);

  GraphicsLayer *layer = chan->make_layer();
  nassertv(layer != (GraphicsLayer *)NULL);

  DisplayRegion *dr = layer->make_display_region();
  nassertv(dr != (DisplayRegion *)NULL);
  camera->set_scene(render_top);
  dr->set_camera(camera);
}

void
toggle_wireframe(NodeAttributes &initial_state) {
  static bool wireframe_mode = false;

  wireframe_mode = !wireframe_mode;
  if (!wireframe_mode) {
    // Set the normal, filled mode on the render arc.
    RenderModeAttribute *rma = new RenderModeAttribute;
    rma->set_mode(RenderModeProperty::M_filled);
    CullFaceAttribute *cfa = new CullFaceAttribute;
    cfa->set_mode(CullFaceProperty::M_cull_clockwise);
    initial_state.set_attribute(RenderModeTransition::get_class_type(), rma);
    initial_state.set_attribute(CullFaceTransition::get_class_type(), cfa);

  } else {
    // Set the initial state up for wireframe mode.
    RenderModeAttribute *rma = new RenderModeAttribute;
    rma->set_mode(RenderModeProperty::M_wireframe);
    CullFaceAttribute *cfa = new CullFaceAttribute;
    cfa->set_mode(CullFaceProperty::M_cull_none);
    initial_state.set_attribute(RenderModeTransition::get_class_type(), rma);
    initial_state.set_attribute(CullFaceTransition::get_class_type(), cfa);
  }
}

void
toggle_backface(NodeAttributes &initial_state) {
  static bool backface_mode = false;

  // Toggle the state variable
  backface_mode = !backface_mode;

  if (backface_mode) {
    // Turn backface culling off
    CullFaceAttribute *cfa = new CullFaceAttribute;
    cfa->set_mode(CullFaceProperty::M_cull_none);
    initial_state.set_attribute(CullFaceTransition::get_class_type(), cfa);
  } else {
    // Turn backface culling on
    CullFaceAttribute *cfa = new CullFaceAttribute;
    cfa->set_mode(CullFaceProperty::M_cull_clockwise);
    initial_state.set_attribute(CullFaceTransition::get_class_type(), cfa);
  }
}

void toggle_texture(NodeAttributes &initial_state) {
  static bool textures_enabled = true;

  textures_enabled = !textures_enabled;
  if (textures_enabled) {
    // Remove the override from the initial state.
    initial_state.clear_attribute(TextureTransition::get_class_type());
  } else {
    // Set an override on the initial state to disable texturing.
    TextureAttribute *ta = new TextureAttribute;
    ta->set_priority(100);
    initial_state.set_attribute(TextureTransition::get_class_type(), ta);
  }
}

void take_snapshot(GraphicsWindow *win, const string &name) {
  GraphicsStateGuardian* gsg = win->get_gsg();
  const RenderBuffer& rb = gsg->get_render_buffer(RenderBuffer::T_front);

  //  CPT(DisplayRegion) dr = gsg->get_current_display_region();
  CPT(DisplayRegion) dr = win->get_channel(0)->get_layer(0)->get_dr(0);
  nassertv(dr != (DisplayRegion *)NULL);

  int width = dr->get_pixel_width();
  int height = dr->get_pixel_height();

  PixelBuffer p(width, height, 3, 1, PixelBuffer::T_unsigned_byte,
		PixelBuffer::F_rgb);

  p.copy(gsg, dr, rb);
  p.write(name);
}

// Returns the configure object for accessing config variables from a
// scripting language.
ConfigShowbase &
get_config_showbase() {
  return config_showbase;
}

<|endoftext|>