<commit_before>//= RValues.cpp - Abstract RValues for Path-Sens. Value Tracking -*- C++ -*-==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines SVal, Loc, and NonLoc, classes that represent
//  abstract r-values for use with path-sensitive value tracking.
//
//===----------------------------------------------------------------------===//

#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Basic/IdentifierTable.h"
using namespace clang;
using namespace ento;
using llvm::APSInt;

//===----------------------------------------------------------------------===//
// Symbol iteration within an SVal.
//===----------------------------------------------------------------------===//

//===----------------------------------------------------------------------===//
// Utility methods.
//===----------------------------------------------------------------------===//

bool SVal::hasConjuredSymbol() const {
  if (const nonloc::SymbolVal* SV = dyn_cast<nonloc::SymbolVal>(this)) {
    SymbolRef sym = SV->getSymbol();
    if (isa<SymbolConjured>(sym))
      return true;
  }

  if (const loc::MemRegionVal *RV = dyn_cast<loc::MemRegionVal>(this)) {
    const MemRegion *R = RV->getRegion();
    if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) {
      SymbolRef sym = SR->getSymbol();
      if (isa<SymbolConjured>(sym))
        return true;
    }
  }

  return false;
}

const FunctionDecl *SVal::getAsFunctionDecl() const {
  if (const loc::MemRegionVal* X = dyn_cast<loc::MemRegionVal>(this)) {
    const MemRegion* R = X->getRegion();
    if (const FunctionTextRegion *CTR = R->getAs<FunctionTextRegion>())
      return CTR->getDecl();
  }

  return 0;
}

/// \brief If this SVal is a location (subclasses Loc) and wraps a symbol,
/// return that SymbolRef.  Otherwise return 0.
///
/// Implicit casts (ex: void* -> char*) can turn Symbolic region into Element
/// region. If that is the case, gets the underlining region.
SymbolRef SVal::getAsLocSymbol() const {
  // FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
  if (const nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(this))
    return X->getLoc().getAsLocSymbol();

  if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this)) {
    const MemRegion *R = X->stripCasts();
    if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R))
      return SymR->getSymbol();
  }
  return 0;
}

/// Get the symbol in the SVal or its base region.
SymbolRef SVal::getLocSymbolInBase() const {
  const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this);

  if (!X)
    return 0;

  const MemRegion *R = X->getRegion();

  while (const SubRegion *SR = dyn_cast<SubRegion>(R)) {
    if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(SR))
      return SymR->getSymbol();
    else
      R = SR->getSuperRegion();
  }

  return 0;
}

// TODO: The next 3 functions have to be simplified.

/// \brief If this SVal wraps a symbol return that SymbolRef.
///  Otherwise return 0.
SymbolRef SVal::getAsSymbol() const {
  // FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
  if (const nonloc::SymbolVal *X = dyn_cast<nonloc::SymbolVal>(this))
    return X->getSymbol();

  if (const nonloc::SymbolVal *X = dyn_cast<nonloc::SymbolVal>(this))
    if (SymbolRef Y = X->getSymbol())
      return Y;

  return getAsLocSymbol();
}

/// getAsSymbolicExpression - If this Sval wraps a symbolic expression then
///  return that expression.  Otherwise return NULL.
const SymExpr *SVal::getAsSymbolicExpression() const {
  if (const nonloc::SymbolVal *X = dyn_cast<nonloc::SymbolVal>(this))
    return X->getSymbol();

  return getAsSymbol();
}

const SymExpr* SVal::getAsSymExpr() const {
  const SymExpr* Sym = getAsSymbol();
  if (!Sym)
    Sym = getAsSymbolicExpression();
  return Sym;
}

const MemRegion *SVal::getAsRegion() const {
  if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this))
    return X->getRegion();

  if (const nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(this)) {
    return X->getLoc().getAsRegion();
  }

  return 0;
}

const MemRegion *loc::MemRegionVal::stripCasts() const {
  const MemRegion *R = getRegion();
  return R ?  R->StripCasts() : NULL;
}

const void *nonloc::LazyCompoundVal::getStore() const {
  return static_cast<const LazyCompoundValData*>(Data)->getStore();
}

const TypedRegion *nonloc::LazyCompoundVal::getRegion() const {
  return static_cast<const LazyCompoundValData*>(Data)->getRegion();
}

//===----------------------------------------------------------------------===//
// Other Iterators.
//===----------------------------------------------------------------------===//

nonloc::CompoundVal::iterator nonloc::CompoundVal::begin() const {
  return getValue()->begin();
}

nonloc::CompoundVal::iterator nonloc::CompoundVal::end() const {
  return getValue()->end();
}

//===----------------------------------------------------------------------===//
// Useful predicates.
//===----------------------------------------------------------------------===//

bool SVal::isConstant() const {
  return isa<nonloc::ConcreteInt>(this) || isa<loc::ConcreteInt>(this);
}

bool SVal::isConstant(int I) const {
  if (isa<loc::ConcreteInt>(*this))
    return cast<loc::ConcreteInt>(*this).getValue() == I;
  else if (isa<nonloc::ConcreteInt>(*this))
    return cast<nonloc::ConcreteInt>(*this).getValue() == I;
  else
    return false;
}

bool SVal::isZeroConstant() const {
  return isConstant(0);
}

//===----------------------------------------------------------------------===//
// Transfer function dispatch for Non-Locs.
//===----------------------------------------------------------------------===//

SVal nonloc::ConcreteInt::evalBinOp(SValBuilder &svalBuilder,
                                    BinaryOperator::Opcode Op,
                                    const nonloc::ConcreteInt& R) const {
  const llvm::APSInt* X =
    svalBuilder.getBasicValueFactory().evalAPSInt(Op, getValue(), R.getValue());

  if (X)
    return nonloc::ConcreteInt(*X);
  else
    return UndefinedVal();
}

nonloc::ConcreteInt
nonloc::ConcreteInt::evalComplement(SValBuilder &svalBuilder) const {
  return svalBuilder.makeIntVal(~getValue());
}

nonloc::ConcreteInt
nonloc::ConcreteInt::evalMinus(SValBuilder &svalBuilder) const {
  return svalBuilder.makeIntVal(-getValue());
}

//===----------------------------------------------------------------------===//
// Transfer function dispatch for Locs.
//===----------------------------------------------------------------------===//

SVal loc::ConcreteInt::evalBinOp(BasicValueFactory& BasicVals,
                                 BinaryOperator::Opcode Op,
                                 const loc::ConcreteInt& R) const {

  assert (Op == BO_Add || Op == BO_Sub ||
          (Op >= BO_LT && Op <= BO_NE));

  const llvm::APSInt* X = BasicVals.evalAPSInt(Op, getValue(), R.getValue());

  if (X)
    return loc::ConcreteInt(*X);
  else
    return UndefinedVal();
}

//===----------------------------------------------------------------------===//
// Pretty-Printing.
//===----------------------------------------------------------------------===//

void SVal::dump() const { dumpToStream(llvm::errs()); }

void SVal::dumpToStream(raw_ostream &os) const {
  switch (getBaseKind()) {
    case UnknownKind:
      os << "Unknown";
      break;
    case NonLocKind:
      cast<NonLoc>(this)->dumpToStream(os);
      break;
    case LocKind:
      cast<Loc>(this)->dumpToStream(os);
      break;
    case UndefinedKind:
      os << "Undefined";
      break;
  }
}

void NonLoc::dumpToStream(raw_ostream &os) const {
  switch (getSubKind()) {
    case nonloc::ConcreteIntKind: {
      const nonloc::ConcreteInt& C = *cast<nonloc::ConcreteInt>(this);
      if (C.getValue().isUnsigned())
        os << C.getValue().getZExtValue();
      else
        os << C.getValue().getSExtValue();
      os << ' ' << (C.getValue().isUnsigned() ? 'U' : 'S')
         << C.getValue().getBitWidth() << 'b';
      break;
    }
    case nonloc::SymbolValKind: {
      os << cast<nonloc::SymbolVal>(this)->getSymbol();
      break;
    }
    case nonloc::LocAsIntegerKind: {
      const nonloc::LocAsInteger& C = *cast<nonloc::LocAsInteger>(this);
      os << C.getLoc() << " [as " << C.getNumBits() << " bit integer]";
      break;
    }
    case nonloc::CompoundValKind: {
      const nonloc::CompoundVal& C = *cast<nonloc::CompoundVal>(this);
      os << "compoundVal{";
      bool first = true;
      for (nonloc::CompoundVal::iterator I=C.begin(), E=C.end(); I!=E; ++I) {
        if (first) {
          os << ' '; first = false;
        }
        else
          os << ", ";

        (*I).dumpToStream(os);
      }
      os << "}";
      break;
    }
    case nonloc::LazyCompoundValKind: {
      const nonloc::LazyCompoundVal &C = *cast<nonloc::LazyCompoundVal>(this);
      os << "lazyCompoundVal{" << const_cast<void *>(C.getStore())
         << ',' << C.getRegion()
         << '}';
      break;
    }
    default:
      assert (false && "Pretty-printed not implemented for this NonLoc.");
      break;
  }
}

void Loc::dumpToStream(raw_ostream &os) const {
  switch (getSubKind()) {
    case loc::ConcreteIntKind:
      os << cast<loc::ConcreteInt>(this)->getValue().getZExtValue() << " (Loc)";
      break;
    case loc::GotoLabelKind:
      os << "&&" << cast<loc::GotoLabel>(this)->getLabel()->getName();
      break;
    case loc::MemRegionKind:
      os << '&' << cast<loc::MemRegionVal>(this)->getRegion()->getString();
      break;
    case loc::ObjCPropRefKind: {
      const ObjCPropertyRefExpr *E = cast<loc::ObjCPropRef>(this)->getPropRefExpr();
      os << "objc-prop{";
      if (E->isSuperReceiver())
        os << "super.";
      else if (E->getBase())
        os << "<base>.";

      if (E->isImplicitProperty())
        os << E->getImplicitPropertyGetter()->getSelector().getAsString();
      else
        os << E->getExplicitProperty()->getName();

      os << "}";
      break;
    }
    default:
      llvm_unreachable("Pretty-printing not implemented for this Loc.");
  }
}
<commit_msg>[analyzer] Remove redundant if statement (pointed out by Ted).<commit_after>//= RValues.cpp - Abstract RValues for Path-Sens. Value Tracking -*- C++ -*-==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines SVal, Loc, and NonLoc, classes that represent
//  abstract r-values for use with path-sensitive value tracking.
//
//===----------------------------------------------------------------------===//

#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Basic/IdentifierTable.h"
using namespace clang;
using namespace ento;
using llvm::APSInt;

//===----------------------------------------------------------------------===//
// Symbol iteration within an SVal.
//===----------------------------------------------------------------------===//

//===----------------------------------------------------------------------===//
// Utility methods.
//===----------------------------------------------------------------------===//

bool SVal::hasConjuredSymbol() const {
  if (const nonloc::SymbolVal* SV = dyn_cast<nonloc::SymbolVal>(this)) {
    SymbolRef sym = SV->getSymbol();
    if (isa<SymbolConjured>(sym))
      return true;
  }

  if (const loc::MemRegionVal *RV = dyn_cast<loc::MemRegionVal>(this)) {
    const MemRegion *R = RV->getRegion();
    if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) {
      SymbolRef sym = SR->getSymbol();
      if (isa<SymbolConjured>(sym))
        return true;
    }
  }

  return false;
}

const FunctionDecl *SVal::getAsFunctionDecl() const {
  if (const loc::MemRegionVal* X = dyn_cast<loc::MemRegionVal>(this)) {
    const MemRegion* R = X->getRegion();
    if (const FunctionTextRegion *CTR = R->getAs<FunctionTextRegion>())
      return CTR->getDecl();
  }

  return 0;
}

/// \brief If this SVal is a location (subclasses Loc) and wraps a symbol,
/// return that SymbolRef.  Otherwise return 0.
///
/// Implicit casts (ex: void* -> char*) can turn Symbolic region into Element
/// region. If that is the case, gets the underlining region.
SymbolRef SVal::getAsLocSymbol() const {
  // FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
  if (const nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(this))
    return X->getLoc().getAsLocSymbol();

  if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this)) {
    const MemRegion *R = X->stripCasts();
    if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R))
      return SymR->getSymbol();
  }
  return 0;
}

/// Get the symbol in the SVal or its base region.
SymbolRef SVal::getLocSymbolInBase() const {
  const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this);

  if (!X)
    return 0;

  const MemRegion *R = X->getRegion();

  while (const SubRegion *SR = dyn_cast<SubRegion>(R)) {
    if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(SR))
      return SymR->getSymbol();
    else
      R = SR->getSuperRegion();
  }

  return 0;
}

// TODO: The next 3 functions have to be simplified.

/// \brief If this SVal wraps a symbol return that SymbolRef.
///  Otherwise return 0.
SymbolRef SVal::getAsSymbol() const {
  // FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
  if (const nonloc::SymbolVal *X = dyn_cast<nonloc::SymbolVal>(this))
    return X->getSymbol();

  return getAsLocSymbol();
}

/// getAsSymbolicExpression - If this Sval wraps a symbolic expression then
///  return that expression.  Otherwise return NULL.
const SymExpr *SVal::getAsSymbolicExpression() const {
  if (const nonloc::SymbolVal *X = dyn_cast<nonloc::SymbolVal>(this))
    return X->getSymbol();

  return getAsSymbol();
}

const SymExpr* SVal::getAsSymExpr() const {
  const SymExpr* Sym = getAsSymbol();
  if (!Sym)
    Sym = getAsSymbolicExpression();
  return Sym;
}

const MemRegion *SVal::getAsRegion() const {
  if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this))
    return X->getRegion();

  if (const nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(this)) {
    return X->getLoc().getAsRegion();
  }

  return 0;
}

const MemRegion *loc::MemRegionVal::stripCasts() const {
  const MemRegion *R = getRegion();
  return R ?  R->StripCasts() : NULL;
}

const void *nonloc::LazyCompoundVal::getStore() const {
  return static_cast<const LazyCompoundValData*>(Data)->getStore();
}

const TypedRegion *nonloc::LazyCompoundVal::getRegion() const {
  return static_cast<const LazyCompoundValData*>(Data)->getRegion();
}

//===----------------------------------------------------------------------===//
// Other Iterators.
//===----------------------------------------------------------------------===//

nonloc::CompoundVal::iterator nonloc::CompoundVal::begin() const {
  return getValue()->begin();
}

nonloc::CompoundVal::iterator nonloc::CompoundVal::end() const {
  return getValue()->end();
}

//===----------------------------------------------------------------------===//
// Useful predicates.
//===----------------------------------------------------------------------===//

bool SVal::isConstant() const {
  return isa<nonloc::ConcreteInt>(this) || isa<loc::ConcreteInt>(this);
}

bool SVal::isConstant(int I) const {
  if (isa<loc::ConcreteInt>(*this))
    return cast<loc::ConcreteInt>(*this).getValue() == I;
  else if (isa<nonloc::ConcreteInt>(*this))
    return cast<nonloc::ConcreteInt>(*this).getValue() == I;
  else
    return false;
}

bool SVal::isZeroConstant() const {
  return isConstant(0);
}

//===----------------------------------------------------------------------===//
// Transfer function dispatch for Non-Locs.
//===----------------------------------------------------------------------===//

SVal nonloc::ConcreteInt::evalBinOp(SValBuilder &svalBuilder,
                                    BinaryOperator::Opcode Op,
                                    const nonloc::ConcreteInt& R) const {
  const llvm::APSInt* X =
    svalBuilder.getBasicValueFactory().evalAPSInt(Op, getValue(), R.getValue());

  if (X)
    return nonloc::ConcreteInt(*X);
  else
    return UndefinedVal();
}

nonloc::ConcreteInt
nonloc::ConcreteInt::evalComplement(SValBuilder &svalBuilder) const {
  return svalBuilder.makeIntVal(~getValue());
}

nonloc::ConcreteInt
nonloc::ConcreteInt::evalMinus(SValBuilder &svalBuilder) const {
  return svalBuilder.makeIntVal(-getValue());
}

//===----------------------------------------------------------------------===//
// Transfer function dispatch for Locs.
//===----------------------------------------------------------------------===//

SVal loc::ConcreteInt::evalBinOp(BasicValueFactory& BasicVals,
                                 BinaryOperator::Opcode Op,
                                 const loc::ConcreteInt& R) const {

  assert (Op == BO_Add || Op == BO_Sub ||
          (Op >= BO_LT && Op <= BO_NE));

  const llvm::APSInt* X = BasicVals.evalAPSInt(Op, getValue(), R.getValue());

  if (X)
    return loc::ConcreteInt(*X);
  else
    return UndefinedVal();
}

//===----------------------------------------------------------------------===//
// Pretty-Printing.
//===----------------------------------------------------------------------===//

void SVal::dump() const { dumpToStream(llvm::errs()); }

void SVal::dumpToStream(raw_ostream &os) const {
  switch (getBaseKind()) {
    case UnknownKind:
      os << "Unknown";
      break;
    case NonLocKind:
      cast<NonLoc>(this)->dumpToStream(os);
      break;
    case LocKind:
      cast<Loc>(this)->dumpToStream(os);
      break;
    case UndefinedKind:
      os << "Undefined";
      break;
  }
}

void NonLoc::dumpToStream(raw_ostream &os) const {
  switch (getSubKind()) {
    case nonloc::ConcreteIntKind: {
      const nonloc::ConcreteInt& C = *cast<nonloc::ConcreteInt>(this);
      if (C.getValue().isUnsigned())
        os << C.getValue().getZExtValue();
      else
        os << C.getValue().getSExtValue();
      os << ' ' << (C.getValue().isUnsigned() ? 'U' : 'S')
         << C.getValue().getBitWidth() << 'b';
      break;
    }
    case nonloc::SymbolValKind: {
      os << cast<nonloc::SymbolVal>(this)->getSymbol();
      break;
    }
    case nonloc::LocAsIntegerKind: {
      const nonloc::LocAsInteger& C = *cast<nonloc::LocAsInteger>(this);
      os << C.getLoc() << " [as " << C.getNumBits() << " bit integer]";
      break;
    }
    case nonloc::CompoundValKind: {
      const nonloc::CompoundVal& C = *cast<nonloc::CompoundVal>(this);
      os << "compoundVal{";
      bool first = true;
      for (nonloc::CompoundVal::iterator I=C.begin(), E=C.end(); I!=E; ++I) {
        if (first) {
          os << ' '; first = false;
        }
        else
          os << ", ";

        (*I).dumpToStream(os);
      }
      os << "}";
      break;
    }
    case nonloc::LazyCompoundValKind: {
      const nonloc::LazyCompoundVal &C = *cast<nonloc::LazyCompoundVal>(this);
      os << "lazyCompoundVal{" << const_cast<void *>(C.getStore())
         << ',' << C.getRegion()
         << '}';
      break;
    }
    default:
      assert (false && "Pretty-printed not implemented for this NonLoc.");
      break;
  }
}

void Loc::dumpToStream(raw_ostream &os) const {
  switch (getSubKind()) {
    case loc::ConcreteIntKind:
      os << cast<loc::ConcreteInt>(this)->getValue().getZExtValue() << " (Loc)";
      break;
    case loc::GotoLabelKind:
      os << "&&" << cast<loc::GotoLabel>(this)->getLabel()->getName();
      break;
    case loc::MemRegionKind:
      os << '&' << cast<loc::MemRegionVal>(this)->getRegion()->getString();
      break;
    case loc::ObjCPropRefKind: {
      const ObjCPropertyRefExpr *E = cast<loc::ObjCPropRef>(this)->getPropRefExpr();
      os << "objc-prop{";
      if (E->isSuperReceiver())
        os << "super.";
      else if (E->getBase())
        os << "<base>.";

      if (E->isImplicitProperty())
        os << E->getImplicitPropertyGetter()->getSelector().getAsString();
      else
        os << E->getExplicitProperty()->getName();

      os << "}";
      break;
    }
    default:
      llvm_unreachable("Pretty-printing not implemented for this Loc.");
  }
}
<|endoftext|>


<commit_before>//===- MipsInstrInfo.cpp - Mips Instruction Information ---------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Bruno Cardoso Lopes and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the Mips implementation of the TargetInstrInfo class.
//
//===----------------------------------------------------------------------===//

#include "Mips.h"
#include "MipsInstrInfo.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "MipsGenInstrInfo.inc"

using namespace llvm;

// TODO: Add the subtarget support on this constructor
MipsInstrInfo::MipsInstrInfo(MipsTargetMachine &tm)
  : TargetInstrInfo(MipsInsts, sizeof(MipsInsts)/sizeof(MipsInsts[0])),
    TM(tm), RI(*this) {}

static bool isZeroImm(const MachineOperand &op) {
  return op.isImmediate() && op.getImmedValue() == 0;
}

/// Return true if the instruction is a register to register move and
/// leave the source and dest operands in the passed parameters.
bool MipsInstrInfo::
isMoveInstr(const MachineInstr &MI, unsigned &SrcReg, unsigned &DstReg) const
{
  //  addu  $dst, $src, $zero || addu  $dst, $zero, $src
  //  or    $dst, $src, $zero || or    $dst, $zero, $src
  if ((MI.getOpcode() == Mips::ADDu) || (MI.getOpcode() == Mips::OR))
  {
    if (MI.getOperand(1).getReg() == Mips::ZERO) {
      DstReg = MI.getOperand(0).getReg();
      SrcReg = MI.getOperand(2).getReg();
      return true;
    } else if (MI.getOperand(2).getReg() == Mips::ZERO) {
      DstReg = MI.getOperand(0).getReg();
      SrcReg = MI.getOperand(1).getReg();
      return true;
    }
  }

  //  addiu $dst, $src, 0
  if (MI.getOpcode() == Mips::ADDiu)
  {
    if ((MI.getOperand(1).isRegister()) && (isZeroImm(MI.getOperand(2)))) {
      DstReg = MI.getOperand(0).getReg();
      SrcReg = MI.getOperand(1).getReg();
      return true;
    }
  }
  return false;
}

/// isLoadFromStackSlot - If the specified machine instruction is a direct
/// load from a stack slot, return the virtual or physical register number of
/// the destination along with the FrameIndex of the loaded stack slot.  If
/// not, return 0.  This predicate must return 0 if the instruction has
/// any side effects other than loading from the stack slot.
unsigned MipsInstrInfo::
isLoadFromStackSlot(MachineInstr *MI, int &FrameIndex) const
{
  // TODO: add lhu, lbu ???
  if (MI->getOpcode() == Mips::LW)
  {
    if ((MI->getOperand(2).isFrameIndex()) && // is a stack slot
        (MI->getOperand(1).isImmediate()) &&  // the imm is zero
        (isZeroImm(MI->getOperand(1))))
    {
      FrameIndex = MI->getOperand(2).getFrameIndex();
      return MI->getOperand(0).getReg();
    }
  }

  return 0;
}

/// isStoreToStackSlot - If the specified machine instruction is a direct
/// store to a stack slot, return the virtual or physical register number of
/// the source reg along with the FrameIndex of the loaded stack slot.  If
/// not, return 0.  This predicate must return 0 if the instruction has
/// any side effects other than storing to the stack slot.
unsigned MipsInstrInfo::
isStoreToStackSlot(MachineInstr *MI, int &FrameIndex) const
{
  // TODO: add sb, sh ???
  if (MI->getOpcode() == Mips::SW) {
    if ((MI->getOperand(0).isFrameIndex()) && // is a stack slot
        (MI->getOperand(1).isImmediate()) &&  // the imm is zero
        (isZeroImm(MI->getOperand(1))))
    {
      FrameIndex = MI->getOperand(0).getFrameIndex();
      return MI->getOperand(2).getReg();
    }
  }
  return 0;
}

unsigned MipsInstrInfo::
InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
             MachineBasicBlock *FBB, const std::vector<MachineOperand> &Cond)
             const
{
  // TODO: add Mips::J here.
  assert(0 && "Cant handle any kind of branches!");
  return 1;
}
<commit_msg>Added Branch Analysis support  Added InsertNoop support<commit_after>//===- MipsInstrInfo.cpp - Mips Instruction Information ---------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Bruno Cardoso Lopes and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the Mips implementation of the TargetInstrInfo class.
//
//===----------------------------------------------------------------------===//

#include "Mips.h"
#include "MipsInstrInfo.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "MipsGenInstrInfo.inc"

using namespace llvm;

// TODO: Add the subtarget support on this constructor
MipsInstrInfo::MipsInstrInfo(MipsTargetMachine &tm)
  : TargetInstrInfo(MipsInsts, sizeof(MipsInsts)/sizeof(MipsInsts[0])),
    TM(tm), RI(*this) {}

static bool isZeroImm(const MachineOperand &op) {
  return op.isImmediate() && op.getImmedValue() == 0;
}

/// Return true if the instruction is a register to register move and
/// leave the source and dest operands in the passed parameters.
bool MipsInstrInfo::
isMoveInstr(const MachineInstr &MI, unsigned &SrcReg, unsigned &DstReg) const
{
  //  addu  $dst, $src, $zero || addu  $dst, $zero, $src
  //  or    $dst, $src, $zero || or    $dst, $zero, $src
  if ((MI.getOpcode() == Mips::ADDu) || (MI.getOpcode() == Mips::OR))
  {
    if (MI.getOperand(1).getReg() == Mips::ZERO) {
      DstReg = MI.getOperand(0).getReg();
      SrcReg = MI.getOperand(2).getReg();
      return true;
    } else if (MI.getOperand(2).getReg() == Mips::ZERO) {
      DstReg = MI.getOperand(0).getReg();
      SrcReg = MI.getOperand(1).getReg();
      return true;
    }
  }

  //  addiu $dst, $src, 0
  if (MI.getOpcode() == Mips::ADDiu)
  {
    if ((MI.getOperand(1).isRegister()) && (isZeroImm(MI.getOperand(2)))) {
      DstReg = MI.getOperand(0).getReg();
      SrcReg = MI.getOperand(1).getReg();
      return true;
    }
  }
  return false;
}

/// isLoadFromStackSlot - If the specified machine instruction is a direct
/// load from a stack slot, return the virtual or physical register number of
/// the destination along with the FrameIndex of the loaded stack slot.  If
/// not, return 0.  This predicate must return 0 if the instruction has
/// any side effects other than loading from the stack slot.
unsigned MipsInstrInfo::
isLoadFromStackSlot(MachineInstr *MI, int &FrameIndex) const
{
  if (MI->getOpcode() == Mips::LW)
  {
    if ((MI->getOperand(2).isFrameIndex()) && // is a stack slot
        (MI->getOperand(1).isImmediate()) &&  // the imm is zero
        (isZeroImm(MI->getOperand(1))))
    {
      FrameIndex = MI->getOperand(2).getFrameIndex();
      return MI->getOperand(0).getReg();
    }
  }

  return 0;
}

/// isStoreToStackSlot - If the specified machine instruction is a direct
/// store to a stack slot, return the virtual or physical register number of
/// the source reg along with the FrameIndex of the loaded stack slot.  If
/// not, return 0.  This predicate must return 0 if the instruction has
/// any side effects other than storing to the stack slot.
unsigned MipsInstrInfo::
isStoreToStackSlot(MachineInstr *MI, int &FrameIndex) const
{
  if (MI->getOpcode() == Mips::SW) {
    if ((MI->getOperand(0).isFrameIndex()) && // is a stack slot
        (MI->getOperand(1).isImmediate()) &&  // the imm is zero
        (isZeroImm(MI->getOperand(1))))
    {
      FrameIndex = MI->getOperand(0).getFrameIndex();
      return MI->getOperand(2).getReg();
    }
  }
  return 0;
}

/// insertNoop - If data hazard condition is found insert the target nop
/// instruction.
void MipsInstrInfo::
insertNoop(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI) const
{
  BuildMI(MBB, MI, get(Mips::NOP));
}

//===----------------------------------------------------------------------===//
// Branch Analysis
//===----------------------------------------------------------------------===//

/// GetCondFromBranchOpc - Return the Mips CC that matches
/// the correspondent Branch instruction opcode.
static Mips::CondCode GetCondFromBranchOpc(unsigned BrOpc)
{
  switch (BrOpc) {
  default: return Mips::COND_INVALID;
  case Mips::BEQ  : return Mips::COND_E;
  case Mips::BNE  : return Mips::COND_NE;
  case Mips::BGTZ : return Mips::COND_GZ;
  case Mips::BGEZ : return Mips::COND_GEZ;
  case Mips::BLTZ : return Mips::COND_LZ;
  case Mips::BLEZ : return Mips::COND_LEZ;
  }
}

/// GetCondBranchFromCond - Return the Branch instruction
/// opcode that matches the cc.
unsigned Mips::GetCondBranchFromCond(Mips::CondCode CC)
{
  switch (CC) {
  default: assert(0 && "Illegal condition code!");
  case Mips::COND_E   : return Mips::BEQ;
  case Mips::COND_NE  : return Mips::BNE;
  case Mips::COND_GZ  : return Mips::BGTZ;
  case Mips::COND_GEZ : return Mips::BGEZ;
  case Mips::COND_LZ  : return Mips::BLTZ;
  case Mips::COND_LEZ : return Mips::BLEZ;
  }
}

/// GetOppositeBranchCondition - Return the inverse of the specified
/// condition, e.g. turning COND_E to COND_NE.
Mips::CondCode Mips::GetOppositeBranchCondition(Mips::CondCode CC)
{
  switch (CC) {
  default: assert(0 && "Illegal condition code!");
  case Mips::COND_E   : return Mips::COND_NE;
  case Mips::COND_NE  : return Mips::COND_E;
  case Mips::COND_GZ  : return Mips::COND_LEZ;
  case Mips::COND_GEZ : return Mips::COND_LZ;
  case Mips::COND_LZ  : return Mips::COND_GEZ;
  case Mips::COND_LEZ : return Mips::COND_GZ;
  }
}

bool MipsInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB,
                                  MachineBasicBlock *&TBB,
                                  MachineBasicBlock *&FBB,
                                  std::vector<MachineOperand> &Cond) const
{
  // If the block has no terminators, it just falls into the block after it.
  MachineBasicBlock::iterator I = MBB.end();
  if (I == MBB.begin() || !isUnpredicatedTerminator(--I))
    return false;

  // Get the last instruction in the block.
  MachineInstr *LastInst = I;

  // If there is only one terminator instruction, process it.
  unsigned LastOpc = LastInst->getOpcode();
  if (I == MBB.begin() || !isUnpredicatedTerminator(--I)) {
    if (!isBranch(LastInst->getOpcode()))
      return true;

    // Unconditional branch
    if (LastOpc == Mips::J) {
      TBB = LastInst->getOperand(0).getMachineBasicBlock();
      return false;
    }

    Mips::CondCode BranchCode = GetCondFromBranchOpc(LastInst->getOpcode());
    if (BranchCode == Mips::COND_INVALID)
      return true;  // Can't handle indirect branch.

    // Conditional branch
    // Block ends with fall-through condbranch.
    if (LastOpc != Mips::COND_INVALID) {
      int LastNumOp = LastInst->getNumOperands();

      TBB = LastInst->getOperand(LastNumOp-1).getMachineBasicBlock();
      Cond.push_back(MachineOperand::CreateImm(BranchCode));

      for (int i=0; i<LastNumOp-1; i++) {
        Cond.push_back(LastInst->getOperand(i));
      }

      return false;
    }
  }

  // Get the instruction before it if it is a terminator.
  MachineInstr *SecondLastInst = I;

  // If there are three terminators, we don't know what sort of block this is.
  if (SecondLastInst && I != MBB.begin() && isUnpredicatedTerminator(--I))
    return true;

  // If the block ends with Mips::J and a Mips::BNE/Mips::BEQ, handle it.
  unsigned SecondLastOpc    = SecondLastInst->getOpcode();
  Mips::CondCode BranchCode = GetCondFromBranchOpc(SecondLastOpc);

  if (SecondLastOpc != Mips::COND_INVALID && LastOpc == Mips::J) {
    int SecondNumOp = SecondLastInst->getNumOperands();

    TBB = SecondLastInst->getOperand(SecondNumOp-1).getMachineBasicBlock();
    Cond.push_back(MachineOperand::CreateImm(BranchCode));

    for (int i=0; i<SecondNumOp-1; i++) {
      Cond.push_back(SecondLastInst->getOperand(i));
    }

    FBB = LastInst->getOperand(0).getMachineBasicBlock();
    return false;
  }

  // If the block ends with two unconditional branches, handle it. The last
  // one is not executed, so remove it.
  if ((SecondLastOpc == Mips::J) && (LastOpc == Mips::J)) {
    TBB = SecondLastInst->getOperand(0).getMachineBasicBlock();
    I = LastInst;
    I->eraseFromParent();
    return false;
  }

  // Otherwise, can't handle this.
  return true;
}

unsigned MipsInstrInfo::
InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
             MachineBasicBlock *FBB, const std::vector<MachineOperand> &Cond)
             const
{
  // Shouldn't be a fall through.
  assert(TBB && "InsertBranch must not be told to insert a fallthrough");
  assert((Cond.size() == 3 || Cond.size() == 2 || Cond.size() == 0) &&
         "Mips branch conditions can have two|three components!");

  if (FBB == 0) { // One way branch.
    if (Cond.empty()) {
      // Unconditional branch?
      BuildMI(&MBB, get(Mips::J)).addMBB(TBB);
    } else {
      // Conditional branch.
      unsigned Opc = GetCondBranchFromCond((Mips::CondCode)Cond[0].getImm());
      const TargetInstrDescriptor &TID = get(Opc);

      if (TID.numOperands == 3)
        BuildMI(&MBB, TID).addReg(Cond[1].getReg())
                          .addReg(Cond[2].getReg())
                          .addMBB(TBB);
      else
        BuildMI(&MBB, TID).addReg(Cond[1].getReg())
                          .addMBB(TBB);

    }
    return 1;
  }

  // Two-way Conditional branch.
  unsigned Opc = GetCondBranchFromCond((Mips::CondCode)Cond[0].getImm());
  const TargetInstrDescriptor &TID = get(Opc);

  if (TID.numOperands == 3)
    BuildMI(&MBB, TID).addReg(Cond[1].getReg())
                      .addReg(Cond[2].getReg())
                      .addMBB(TBB);
  else
    BuildMI(&MBB, TID).addReg(Cond[1].getReg())
                      .addMBB(TBB);

  BuildMI(&MBB, get(Mips::J)).addMBB(FBB);
  return 2;
}

unsigned MipsInstrInfo::
RemoveBranch(MachineBasicBlock &MBB) const
{
  MachineBasicBlock::iterator I = MBB.end();
  if (I == MBB.begin()) return 0;
  --I;
  if (I->getOpcode() != Mips::J &&
      GetCondFromBranchOpc(I->getOpcode()) == Mips::COND_INVALID)
    return 0;

  // Remove the branch.
  I->eraseFromParent();

  I = MBB.end();

  if (I == MBB.begin()) return 1;
  --I;
  if (GetCondFromBranchOpc(I->getOpcode()) == Mips::COND_INVALID)
    return 1;

  // Remove the branch.
  I->eraseFromParent();
  return 2;
}

/// BlockHasNoFallThrough - Analyse if MachineBasicBlock does not
/// fall-through into its successor block.
bool MipsInstrInfo::
BlockHasNoFallThrough(MachineBasicBlock &MBB) const
{
  if (MBB.empty()) return false;

  switch (MBB.back().getOpcode()) {
  case Mips::RET:     // Return.
  case Mips::JR:      // Indirect branch.
  case Mips::J:       // Uncond branch.
    return true;
  default: return false;
  }
}

/// ReverseBranchCondition - Return the inverse opcode of the
/// specified Branch instruction.
bool MipsInstrInfo::
ReverseBranchCondition(std::vector<MachineOperand> &Cond) const
{
  assert( (Cond.size() == 3 || Cond.size() == 2) &&
          "Invalid Mips branch condition!");
  Cond[0].setImm(GetOppositeBranchCondition((Mips::CondCode)Cond[0].getImm()));
  return false;
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2006-2016  Music Technology Group - Universitat Pompeu Fabra
 *
 * This file is part of Essentia
 *
 * Essentia is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation (FSF), either version 3 of the License, or (at your
 * option) any later version.
 *
 * This program 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 General Public License for more
 * details.
 *
 * You should have received a copy of the Affero GNU General Public License
 * version 3 along with this program.  If not, see http://www.gnu.org/licenses/
 */

#include "oddtoevenharmonicenergyratio.h"
#include <limits>

using namespace std;
using namespace essentia;
using namespace standard;

const char* OddToEvenHarmonicEnergyRatio::name = "OddToEvenHarmonicEnergyRatio";
const char* OddToEvenHarmonicEnergyRatio::description = DOC("This algorithm computes the ratio between a signal's odd and even harmonic energy given the signal's harmonic peaks. The odd to even harmonic energy ratio is a measure allowing to distinguish odd-harmonic-energy predominant sounds (such as from a clarinet) from equally important even-harmonic-energy sounds (such as from a trumpet). The required harmonic frequencies and magnitudes can be computed by the HarmonicPeaks algorithm.\n"
"In the case when the even energy is zero, which may happen when only even harmonics where found or when only one peak was found, the algorithm outputs the maximum real number possible. Therefore, this algorithm should be used in conjunction with the harmonic peaks algorithm.\n"
"If no peaks are supplied, the algorithm outputs a value of one, assuming either the spectrum was flat or it was silent.\n"
"\n"
"An exception is thrown if the input frequency and magnitude vectors have different size. Finally, an exception is thrown if the frequency and magnitude vectors are not ordered by ascending frequency.\n"
"\n"
"References:\n"
"  [1] K. D. Martin and Y. E. Kim, \"Musical instrument identification:\n"
"  A pattern-recognition approach,\" The Journal of the Acoustical Society of\n"
"  America, vol. 104, no. 3, pp. 1768–1768, 1998.\n\n"
"  [2] K. Ringgenberg et al., \"Musical Instrument Recognition,\"\n"
"  http://cnx.org/content/col10313/1.3/pdf");

void OddToEvenHarmonicEnergyRatio::compute() {

  const vector<Real>& frequencies = _frequencies.get();
  const vector<Real>& magnitudes = _magnitudes.get();
  Real& oddtoevenharmonicenergyratio = _oddtoevenharmonicenergyratio.get();

  if (magnitudes.size() != frequencies.size()) {
    throw EssentiaException("OddToEvenHarmonicEnergyRatio: frequency and magnitude vectors have different size");
  }
  if (frequencies.empty()) {
    // if no peaks supplied then we assume the spectrum was flat or completely
    // silent, in which case it makes sense to throw a ratio = 1.0.
    oddtoevenharmonicenergyratio = 1.0;
    return;
  }

  Real even_energy = 0.0;
  Real odd_energy = 0.0;
  Real prevFreq = frequencies[0];

  for (int i=0; i<int(frequencies.size()); i++) {
    if (frequencies[i] < prevFreq) {
      throw EssentiaException("OddToEvenHarmonicEnergyRatio: harmonic peaks are not ordered by ascending frequency");
    }
    prevFreq = frequencies[i];

    if (i%2 == 0) even_energy += magnitudes[i] * magnitudes[i];
    else           odd_energy += magnitudes[i] * magnitudes[i];
  }

  if (even_energy == 0.0) {
     oddtoevenharmonicenergyratio = numeric_limits<Real>::max();
  }
  else {
     oddtoevenharmonicenergyratio = odd_energy / even_energy;
  }
}
<commit_msg>Temporarily fix to avoid Inf values in OddToEvenHarmonicEnergyRatio<commit_after>/*
 * Copyright (C) 2006-2016  Music Technology Group - Universitat Pompeu Fabra
 *
 * This file is part of Essentia
 *
 * Essentia is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation (FSF), either version 3 of the License, or (at your
 * option) any later version.
 *
 * This program 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 General Public License for more
 * details.
 *
 * You should have received a copy of the Affero GNU General Public License
 * version 3 along with this program.  If not, see http://www.gnu.org/licenses/
 */

#include "oddtoevenharmonicenergyratio.h"
#include <limits>

using namespace std;
using namespace essentia;
using namespace standard;

const char* OddToEvenHarmonicEnergyRatio::name = "OddToEvenHarmonicEnergyRatio";
const char* OddToEvenHarmonicEnergyRatio::description = DOC("This algorithm computes the ratio between a signal's odd and even harmonic energy given the signal's harmonic peaks. The odd to even harmonic energy ratio is a measure allowing to distinguish odd-harmonic-energy predominant sounds (such as from a clarinet) from equally important even-harmonic-energy sounds (such as from a trumpet). The required harmonic frequencies and magnitudes can be computed by the HarmonicPeaks algorithm.\n"
"In the case when the even energy is zero, which may happen when only even harmonics where found or when only one peak was found, the algorithm outputs the maximum real number possible. Therefore, this algorithm should be used in conjunction with the harmonic peaks algorithm.\n"
"If no peaks are supplied, the algorithm outputs a value of one, assuming either the spectrum was flat or it was silent.\n"
"\n"
"An exception is thrown if the input frequency and magnitude vectors have different size. Finally, an exception is thrown if the frequency and magnitude vectors are not ordered by ascending frequency.\n"
"\n"
"References:\n"
"  [1] K. D. Martin and Y. E. Kim, \"Musical instrument identification:\n"
"  A pattern-recognition approach,\" The Journal of the Acoustical Society of\n"
"  America, vol. 104, no. 3, pp. 1768–1768, 1998.\n\n"
"  [2] K. Ringgenberg et al., \"Musical Instrument Recognition,\"\n"
"  http://cnx.org/content/col10313/1.3/pdf");

void OddToEvenHarmonicEnergyRatio::compute() {

  const vector<Real>& frequencies = _frequencies.get();
  const vector<Real>& magnitudes = _magnitudes.get();
  Real& oddtoevenharmonicenergyratio = _oddtoevenharmonicenergyratio.get();

  if (magnitudes.size() != frequencies.size()) {
    throw EssentiaException("OddToEvenHarmonicEnergyRatio: frequency and magnitude vectors have different size");
  }
  if (frequencies.empty()) {
    // if no peaks supplied then we assume the spectrum was flat or completely
    // silent, in which case it makes sense to throw a ratio = 1.0.
    oddtoevenharmonicenergyratio = 1.0;
    return;
  }

  Real even_energy = 0.0;
  Real odd_energy = 0.0;
  Real prevFreq = frequencies[0];

  for (int i=0; i<int(frequencies.size()); i++) {
    if (frequencies[i] < prevFreq) {
      throw EssentiaException("OddToEvenHarmonicEnergyRatio: harmonic peaks are not ordered by ascending frequency");
    }
    prevFreq = frequencies[i];

    if (i%2 == 0) even_energy += magnitudes[i] * magnitudes[i];
    else           odd_energy += magnitudes[i] * magnitudes[i];
  }

  if (even_energy == 0.0) {
     oddtoevenharmonicenergyratio = numeric_limits<Real>::max();
  }
  else {
     oddtoevenharmonicenergyratio = odd_energy / even_energy;
  }
  if (oddtoevenharmonicenergyratio >= 1000.) {
    cerr << "DEBUG: clipping oddtoevenharmonicenergyratio to max value" << endl;
    oddtoevenharmonicenergyratio = 1000.;
  }
}
<|endoftext|>


<commit_before>
#include "../../the_debuginator.h"

//#include <time.h>
#include <stdio.h>
#include <string.h>

#include "game.h"

//static void on_boxes_activated(DebuginatorItem* item, void* value, const char* value_title) {
//	(void)value;
//	GameData* data = (GameData*)item->user_data;
//	if (strcmp(value_title, "Add box") == 0 && data->boxes_n < 256) {
//		GameBox* box = &data->boxes[data->boxes_n++];
//		box->randomize();
//	}
//	else if (strcmp(value_title, "Clear all boxes") == 0 && data->boxes_n < 256) {
//		data->boxes_n = 0;
//	}
//
//	sprintf_s(data->box_string, "Box count: %d", data->boxes_n);
//}

static void debug_menu_setup(TheDebuginator* debuginator, GameData* data) {
	(void)data;
	debuginator_load_item(debuginator, "SDL Demo/Load test", "True");
	{
		static const char* string_titles[5] = { "String A", "String B", "String C", "String D", "String E" };
		debuginator_create_array_item(debuginator, NULL, "SDL Demo/String Test",
			"Multiple strings.", NULL, NULL,
			string_titles, NULL, 5, 0);
	}
	//debuginator_create_bool_item(debuginator, "SDL Demo/Draw boxes", "Whether to draw the animated boxes or not.", &data->draw_boxes);

	/*
	{
		static const char* string_titles[3] = { "Clear all boxes", "Add box", data->box_string };
		debuginator_create_array_item(debuginator, NULL, "SDL Demo/Boxes",
			"Box things", on_boxes_activated, data,
			string_titles, NULL, 3, 0);	}

	debuginator_create_bool_item(debuginator, "SimpleBool 1", "Change a bool.", &data->mybool);
	debuginator_create_bool_item(debuginator, "Folder/SimpleBool 2", "Change a bool.", &data->mybool);
	debuginator_create_bool_item(debuginator, "Folder/SimpleBool 3", "Change a bool.", &data->mybool);
	debuginator_create_bool_item(debuginator, "Folder/Subfolder/SimpleBool 4 with a really long long title", "Change a bool.", &data->mybool);
	debuginator_create_bool_item(debuginator, "SDL Demo/Load test", "Change a bool.", &data->mybool);

	debuginator_new_folder_item(debuginator, NULL, "Folder 2", 0);
	*/
/*
	char folder[64] = { 0 };
	char item[64] = { 0 };
	for (int i = 0; i < 5; i++) {
		for (int j = 0; j < 5; j++) {
			sprintf_s(folder, 64, "Game/Test%02d/GameBool%02d", i, j);
			debuginator_create_bool_item(debuginator, folder, "Change a bool.", &data->mybool);
		}
	}*/
}

static GameData s_game_data;

GameData* game_init(GuiHandle gui, TheDebuginator* debuginator) {
	memset(&s_game_data, 0, sizeof(s_game_data));
	s_game_data.gui = gui;
	s_game_data.window_size.x = 800; // TODO fix
	s_game_data.window_size.y = 600;
	debug_menu_setup(debuginator, &s_game_data);

	return &s_game_data;
}

void game_update(GameData* game_data, float dt) {

	// bouncing boxes
	if (game_data->draw_boxes) {
		for (size_t box_i = 0; box_i < game_data->boxes_n; box_i++) {
			GameBox* box = &game_data->boxes[box_i];
			box->pos.x += box->velocity.x * (float)dt;
			box->pos.y += box->velocity.y * (float)dt;
			if (box->pos.x < 0 && box->velocity.x < 0 || box->pos.x + box->size.x > game_data->window_size.x && box->velocity.x > 0) {
				box->velocity.x *= -1;
			}
			if (box->pos.y - box->size.y < 0 && box->velocity.y < 0 || box->pos.y + box->size.y > game_data->window_size.y && box->velocity.y > 0) {
				box->velocity.y *= -1;
			}
			gui_draw_rect_filled(game_data->gui, box->pos, box->size, box->color);
		}
	}
}
<commit_msg>Readded menu items.<commit_after>
#include "../../the_debuginator.h"

//#include <time.h>
#include <stdio.h>
#include <string.h>

#include "game.h"

static void on_boxes_activated(DebuginatorItem* item, void* value, const char* value_title) {
	(void)value;
	GameData* data = (GameData*)item->user_data;
	if (strcmp(value_title, "Add box") == 0 && data->boxes_n < 256) {
		GameBox* box = &data->boxes[data->boxes_n++];
		box->randomize();
	}
	else if (strcmp(value_title, "Clear all boxes") == 0 && data->boxes_n < 256) {
		data->boxes_n = 0;
	}

	sprintf_s(data->box_string, "Box count: %d", data->boxes_n);
}

static void debug_menu_setup(TheDebuginator* debuginator, GameData* data) {
	(void)data;
	debuginator_load_item(debuginator, "SDL Demo/Load test", "True");
	{
		static const char* string_titles[5] = { "String A", "String B", "String C", "String D", "String E" };
		debuginator_create_array_item(debuginator, NULL, "SDL Demo/String Test",
			"Multiple strings.", NULL, NULL,
			string_titles, NULL, 5, 0);
	}

	debuginator_create_bool_item(debuginator, "SDL Demo/Draw boxes", "Whether to draw the animated boxes or not.", &data->draw_boxes);

	{
		static const char* string_titles[3] = { "Clear all boxes", "Add box", data->box_string };
		debuginator_create_array_item(debuginator, NULL, "SDL Demo/Boxes",
			"Box things", on_boxes_activated, data,
			string_titles, NULL, 3, 0);	}

	debuginator_create_bool_item(debuginator, "SimpleBool 1", "Change a bool.", &data->mybool);
	debuginator_create_bool_item(debuginator, "Folder/SimpleBool 2", "Change a bool.", &data->mybool);
	debuginator_create_bool_item(debuginator, "Folder/SimpleBool 3", "Change a bool.", &data->mybool);
	debuginator_create_bool_item(debuginator, "Folder/Subfolder/SimpleBool 4 with a really long long title", "Change a bool.", &data->mybool);
	debuginator_create_bool_item(debuginator, "SDL Demo/Load test", "Change a bool.", &data->mybool);

	debuginator_new_folder_item(debuginator, NULL, "Folder 2", 0);

	char folder[64] = { 0 };
	char item[64] = { 0 };
	for (int i = 0; i < 5; i++) {
		for (int j = 0; j < 5; j++) {
			sprintf_s(folder, 64, "Game/Test%02d/GameBool%02d", i, j);
			debuginator_create_bool_item(debuginator, folder, "Change a bool.", &data->mybool);
		}
	}
}

static GameData s_game_data;

GameData* game_init(GuiHandle gui, TheDebuginator* debuginator) {
	memset(&s_game_data, 0, sizeof(s_game_data));
	s_game_data.gui = gui;
	s_game_data.window_size.x = 800; // TODO fix
	s_game_data.window_size.y = 600;
	debug_menu_setup(debuginator, &s_game_data);

	return &s_game_data;
}

void game_update(GameData* game_data, float dt) {

	// bouncing boxes
	if (game_data->draw_boxes) {
		for (size_t box_i = 0; box_i < game_data->boxes_n; box_i++) {
			GameBox* box = &game_data->boxes[box_i];
			box->pos.x += box->velocity.x * (float)dt;
			box->pos.y += box->velocity.y * (float)dt;
			if (box->pos.x < 0 && box->velocity.x < 0 || box->pos.x + box->size.x > game_data->window_size.x && box->velocity.x > 0) {
				box->velocity.x *= -1;
			}
			if (box->pos.y - box->size.y < 0 && box->velocity.y < 0 || box->pos.y + box->size.y > game_data->window_size.y && box->velocity.y > 0) {
				box->velocity.y *= -1;
			}
			gui_draw_rect_filled(game_data->gui, box->pos, box->size, box->color);
		}
	}
}
<|endoftext|>


<commit_before>#include "ffi.h"

ForeignCaller::ForeignCaller() {
}

ForeignCaller::~ForeignCaller() {
}

Persistent<FunctionTemplate> ForeignCaller::foreign_caller_template;

Handle<FunctionTemplate> ForeignCaller::MakeTemplate()
{
    HandleScope scope;
    Handle<FunctionTemplate> t = FunctionTemplate::New(New);

    Local<ObjectTemplate> inst = t->InstanceTemplate();
    inst->SetInternalFieldCount(1);

    return scope.Close(t);
}

void ForeignCaller::Initialize(Handle<Object> target)
{
    HandleScope scope;

    if (foreign_caller_template.IsEmpty()) {
        foreign_caller_template = Persistent<FunctionTemplate>::New(MakeTemplate());
    }

    Handle<FunctionTemplate> t = foreign_caller_template;

    NODE_SET_PROTOTYPE_METHOD(t, "exec", Exec);

    target->Set(String::NewSymbol("ForeignCaller"), t->GetFunction());
}

Handle<Value> ForeignCaller::New(const Arguments& args)
{
    HandleScope     scope;
    ForeignCaller   *self = new ForeignCaller();

    if (args.Length() == 5) {
        Pointer *cif    = ObjectWrap::Unwrap<Pointer>(args[0]->ToObject());
        Pointer *fn     = ObjectWrap::Unwrap<Pointer>(args[1]->ToObject());
        Pointer *fnargs = ObjectWrap::Unwrap<Pointer>(args[2]->ToObject());
        Pointer *res    = ObjectWrap::Unwrap<Pointer>(args[3]->ToObject());

        self->m_cif     = (ffi_cif *)cif->GetPointer();
        self->m_fn      = (void (*)(void))fn->GetPointer();
        self->m_res     = (void *)res->GetPointer();
        self->m_fnargs  = (void **)fnargs->GetPointer();

        self->m_async   = args[4]->BooleanValue();
    }
    else {
        return THROW_ERROR_EXCEPTION("Not enough arguments");
    }

    // TODO: Figure out how to throw an exception here for zero args but not
    // break WrapPointer's NewInstance() call.

    self->Wrap(args.This());
    return args.This();
}

Handle<Value> ForeignCaller::Exec(const Arguments& args)
{
    HandleScope     scope;
    ForeignCaller   *self = ObjectWrap::Unwrap<ForeignCaller>(args.This());

    if (self->m_async) {
        HandleScope scope;
        AsyncCallParams *p = new AsyncCallParams();

        // cuter way of doing this?
        p->cif  = self->m_cif;
        p->ptr  = self->m_fn;
        p->res  = self->m_res;
        p->args = self->m_fnargs;

        // get the events.EventEmitter constructor
        Local<Object> global = Context::GetCurrent()->Global();
        Local<Object> events = global->Get(String::NewSymbol("process"))->ToObject();
        Local<Function> emitterConstructor = Local<Function>::Cast(events->Get(String::NewSymbol("EventEmitter")));

        // construct a new process.Promise object
        p->emitter = Persistent<Object>::New(emitterConstructor->NewInstance());

        ev_ref(EV_DEFAULT_UC);
        eio_custom(ForeignCaller::AsyncFFICall, EIO_PRI_DEFAULT, ForeignCaller::FinishAsyncFFICall, p);

        return scope.Close(p->emitter);
    }
    else {
        ffi_call(
            self->m_cif,
            self->m_fn,
            self->m_res,
            self->m_fnargs
        );
    }

    return Undefined();
}

int ForeignCaller::AsyncFFICall(eio_req *req)
{
    AsyncCallParams *p = (AsyncCallParams *)req->data;
    ffi_call(p->cif, p->ptr, p->res, p->args);
    return 0;
}

int ForeignCaller::FinishAsyncFFICall(eio_req *req)
{
    AsyncCallParams *p = (AsyncCallParams *)req->data;
    Local<Value> argv[1];

    argv[0] = Local<Value>::New(String::New("success"));

    // emit a success event
    Local<Function> emit = Local<Function>::Cast(p->emitter->Get(String::NewSymbol("emit")));
    emit->Call(p->emitter, 1, argv);

    // unref the event loop (ref'd in FFICall)
    ev_unref(EV_DEFAULT_UC);

    // dispose of our persistent handle to the EventEmitter object
    p->emitter.Dispose();

    // free up our memory (allocated in FFICall)
    delete p;

    return 0;
}<commit_msg>Fixed senseless comment<commit_after>#include "ffi.h"

ForeignCaller::ForeignCaller() {
}

ForeignCaller::~ForeignCaller() {
}

Persistent<FunctionTemplate> ForeignCaller::foreign_caller_template;

Handle<FunctionTemplate> ForeignCaller::MakeTemplate()
{
    HandleScope scope;
    Handle<FunctionTemplate> t = FunctionTemplate::New(New);

    Local<ObjectTemplate> inst = t->InstanceTemplate();
    inst->SetInternalFieldCount(1);

    return scope.Close(t);
}

void ForeignCaller::Initialize(Handle<Object> target)
{
    HandleScope scope;

    if (foreign_caller_template.IsEmpty()) {
        foreign_caller_template = Persistent<FunctionTemplate>::New(MakeTemplate());
    }

    Handle<FunctionTemplate> t = foreign_caller_template;

    NODE_SET_PROTOTYPE_METHOD(t, "exec", Exec);

    target->Set(String::NewSymbol("ForeignCaller"), t->GetFunction());
}

Handle<Value> ForeignCaller::New(const Arguments& args)
{
    HandleScope     scope;
    ForeignCaller   *self = new ForeignCaller();

    if (args.Length() == 5) {
        Pointer *cif    = ObjectWrap::Unwrap<Pointer>(args[0]->ToObject());
        Pointer *fn     = ObjectWrap::Unwrap<Pointer>(args[1]->ToObject());
        Pointer *fnargs = ObjectWrap::Unwrap<Pointer>(args[2]->ToObject());
        Pointer *res    = ObjectWrap::Unwrap<Pointer>(args[3]->ToObject());

        self->m_cif     = (ffi_cif *)cif->GetPointer();
        self->m_fn      = (void (*)(void))fn->GetPointer();
        self->m_res     = (void *)res->GetPointer();
        self->m_fnargs  = (void **)fnargs->GetPointer();

        self->m_async   = args[4]->BooleanValue();
    }
    else {
        return THROW_ERROR_EXCEPTION("Not enough arguments");
    }

    self->Wrap(args.This());
    return args.This();
}

Handle<Value> ForeignCaller::Exec(const Arguments& args)
{
    HandleScope     scope;
    ForeignCaller   *self = ObjectWrap::Unwrap<ForeignCaller>(args.This());

    if (self->m_async) {
        HandleScope scope;
        AsyncCallParams *p = new AsyncCallParams();

        // cuter way of doing this?
        p->cif  = self->m_cif;
        p->ptr  = self->m_fn;
        p->res  = self->m_res;
        p->args = self->m_fnargs;

        // get the events.EventEmitter constructor
        Local<Object> global = Context::GetCurrent()->Global();
        Local<Object> events = global->Get(String::NewSymbol("process"))->ToObject();
        Local<Function> emitterConstructor = Local<Function>::Cast(events->Get(String::NewSymbol("EventEmitter")));

        // construct a new process.Promise object
        p->emitter = Persistent<Object>::New(emitterConstructor->NewInstance());

        ev_ref(EV_DEFAULT_UC);
        eio_custom(ForeignCaller::AsyncFFICall, EIO_PRI_DEFAULT, ForeignCaller::FinishAsyncFFICall, p);

        return scope.Close(p->emitter);
    }
    else {
        ffi_call(
            self->m_cif,
            self->m_fn,
            self->m_res,
            self->m_fnargs
        );
    }

    return Undefined();
}

int ForeignCaller::AsyncFFICall(eio_req *req)
{
    AsyncCallParams *p = (AsyncCallParams *)req->data;
    ffi_call(p->cif, p->ptr, p->res, p->args);
    return 0;
}

int ForeignCaller::FinishAsyncFFICall(eio_req *req)
{
    AsyncCallParams *p = (AsyncCallParams *)req->data;
    Local<Value> argv[1];

    argv[0] = Local<Value>::New(String::New("success"));

    // emit a success event
    Local<Function> emit = Local<Function>::Cast(p->emitter->Get(String::NewSymbol("emit")));
    emit->Call(p->emitter, 1, argv);

    // unref the event loop (ref'd in FFICall)
    ev_unref(EV_DEFAULT_UC);

    // dispose of our persistent handle to the EventEmitter object
    p->emitter.Dispose();

    // free up our memory (allocated in FFICall)
    delete p;

    return 0;
}<|endoftext|>


<commit_before>/* -*-c++-*- */
/**
 * osgAudio - OpenSceneGraph Audio Library
 * (C) Copyright 2009-2011 by Kenneth Mark Bryden
 * (programming by Chris 'Xenon' Hanson, AlphaPixel, LLC xenon at alphapixel.com)
 * based on a fork of:
 * Osg AL - OpenSceneGraph Audio Library
 * Copyright (C) 2004 VRlab, Ume University
 *
 * 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.1 of the License, or (at your option) any later version.
 * Please see COPYING file for special static-link exemption to LGPL.
 *
 * 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.
 */

#include <osgAudio/AudioEnvironment.h>
#include <openalpp/AudioEnvironment.h>

using namespace osgAudio;

/**
* Used when translating the distance model between osgAudio and openAL++
*/
static openalpp::DistanceModel _openalppDistanceModelTranslate[] = {
	openalpp::None,openalpp::InverseDistance,openalpp::InverseDistanceClamped,openalpp::Linear
	};
static osgAudio::DistanceModel _osgAudioDistanceModelTranslate[] = {
	None,InverseDistance,InverseDistanceClamped,Linear
};

AudioEnvironment::AudioEnvironment()
: _dummyUnitScale(1.0f);
{
}

AudioEnvironment* AudioEnvironment::instance()
{
	static AudioEnvironment* s_audioEnvironment = new AudioEnvironment();
	return s_audioEnvironment;
}

void AudioEnvironment::init( bool displayInitMsgs ) throw (InitError)
{
    try
    {
        _openalppAudioEnvironment = new openalpp::AudioEnvironment( displayInitMsgs);
    }
    catch(openalpp::InitError error)
    {
        throw InitError(error.what());
    }
}

void AudioEnvironment::init(int frequency,int refresh,bool synchronous,bool displayInitMsgs)
throw (InitError)
{
	try
    {
        _openalppAudioEnvironment = new openalpp::AudioEnvironment (frequency, refresh, synchronous, displayInitMsgs);
	}
	catch(openalpp::InitError error)
    {
        throw InitError(error.what());
    }
}

void AudioEnvironment::init(int frequency,int refresh) throw (InitError)
{
	try
    {
        _openalppAudioEnvironment = new openalpp::AudioEnvironment (frequency, refresh);
	}
	catch(openalpp::InitError error)
    {
        throw InitError(error.what());
    }
}

AudioEnvironment::~AudioEnvironment()
{
	if(_openalppAudioEnvironment.valid())
	{
		_openalppAudioEnvironment = NULL; // deletes it
	} // if
} // AudioEnvironment::~AudioEnvironment

void AudioEnvironment::setSoundVelocity(float speed) throw(ValueError,FatalError){
	try {
	_openalppAudioEnvironment->setSoundVelocity (speed);
	}
	catch(openalpp::ValueError error) { throw ValueError(error.what()); }
	catch(openalpp::FatalError error) { throw FatalError(error.what()); }
}

float AudioEnvironment::getSoundVelocity() throw (FatalError) {
	float speed;
	try {
	speed = _openalppAudioEnvironment->getSoundVelocity();
	}
	catch(openalpp::FatalError error) { throw FatalError(error.what()); }
	return speed;
}

void AudioEnvironment::setDopplerFactor(float factor)
throw (ValueError,FatalError) {
	try {
	_openalppAudioEnvironment->setDopplerFactor (factor);
	}
	catch(openalpp::ValueError error) { throw ValueError(error.what()); }
	catch(openalpp::FatalError error) { throw FatalError(error.what()); }
}

float AudioEnvironment::getDopplerFactor() throw (FatalError) {
	float factor;
	try {
	factor = _openalppAudioEnvironment->getDopplerFactor();
	}
	catch(openalpp::FatalError error) { throw FatalError(error.what()); }
	return factor;
}

void AudioEnvironment::setUnitScale(float scale) throw (ValueError,FatalError) {
	_dummyUnitScale = scale;
}

float AudioEnvironment::getUnitScale() throw (FatalError) {
	return(_dummyUnitScale);
}

void AudioEnvironment::setGain(float gain) {
	try {
	_openalppAudioEnvironment->setGain (gain);
	}
	catch(openalpp::ValueError error) { throw ValueError(error.what()); }
	catch(openalpp::FatalError error) { throw FatalError(error.what()); }
}

float AudioEnvironment::getGain() throw (FatalError) {
	float gain;
	try {
	gain = _openalppAudioEnvironment->getGain();
	}
	catch(openalpp::FatalError error) { throw FatalError(error.what()); }
	return gain;
}

void AudioEnvironment::setDistanceModel(DistanceModel model)
throw (FatalError){
	try {
	_openalppAudioEnvironment->setDistanceModel (_openalppDistanceModelTranslate[model]);
	}
	catch(openalpp::FatalError error) { throw FatalError(error.what()); }
}

DistanceModel AudioEnvironment::getDistanceModel() throw (FatalError) {
	DistanceModel dmodel;
	try {
	dmodel = _osgAudioDistanceModelTranslate[_openalppAudioEnvironment->getDistanceModel()];
	}
	catch(openalpp::FatalError error) { throw FatalError(error.what()); }
	return dmodel;
}

void AudioEnvironment::initiateReverb() throw (InitError) {
	try {
	_openalppAudioEnvironment->initiateReverb();
	}
	catch(openalpp::InitError error) { throw InitError(error.what()); }
}

<commit_msg>Fix for OpenAL build.<commit_after>/* -*-c++-*- */
/**
 * osgAudio - OpenSceneGraph Audio Library
 * (C) Copyright 2009-2011 by Kenneth Mark Bryden
 * (programming by Chris 'Xenon' Hanson, AlphaPixel, LLC xenon at alphapixel.com)
 * based on a fork of:
 * Osg AL - OpenSceneGraph Audio Library
 * Copyright (C) 2004 VRlab, Ume University
 *
 * 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.1 of the License, or (at your option) any later version.
 * Please see COPYING file for special static-link exemption to LGPL.
 *
 * 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.
 */

#include <osgAudio/AudioEnvironment.h>
#include <openalpp/AudioEnvironment.h>

using namespace osgAudio;

/**
* Used when translating the distance model between osgAudio and openAL++
*/
static openalpp::DistanceModel _openalppDistanceModelTranslate[] = {
	openalpp::None,openalpp::InverseDistance,openalpp::InverseDistanceClamped,openalpp::Linear
	};
static osgAudio::DistanceModel _osgAudioDistanceModelTranslate[] = {
	None,InverseDistance,InverseDistanceClamped,Linear
};

AudioEnvironment::AudioEnvironment()
: _dummyUnitScale(1.0f)
{
}

AudioEnvironment* AudioEnvironment::instance()
{
	static AudioEnvironment* s_audioEnvironment = new AudioEnvironment();
	return s_audioEnvironment;
}

void AudioEnvironment::init( bool displayInitMsgs ) throw (InitError)
{
    try
    {
        _openalppAudioEnvironment = new openalpp::AudioEnvironment( displayInitMsgs);
    }
    catch(openalpp::InitError error)
    {
        throw InitError(error.what());
    }
}

void AudioEnvironment::init(int frequency,int refresh,bool synchronous,bool displayInitMsgs)
throw (InitError)
{
	try
    {
        _openalppAudioEnvironment = new openalpp::AudioEnvironment (frequency, refresh, synchronous, displayInitMsgs);
	}
	catch(openalpp::InitError error)
    {
        throw InitError(error.what());
    }
}

void AudioEnvironment::init(int frequency,int refresh) throw (InitError)
{
	try
    {
        _openalppAudioEnvironment = new openalpp::AudioEnvironment (frequency, refresh);
	}
	catch(openalpp::InitError error)
    {
        throw InitError(error.what());
    }
}

AudioEnvironment::~AudioEnvironment()
{
	if(_openalppAudioEnvironment.valid())
	{
		_openalppAudioEnvironment = NULL; // deletes it
	} // if
} // AudioEnvironment::~AudioEnvironment

void AudioEnvironment::setSoundVelocity(float speed) throw(ValueError,FatalError){
	try {
	_openalppAudioEnvironment->setSoundVelocity (speed);
	}
	catch(openalpp::ValueError error) { throw ValueError(error.what()); }
	catch(openalpp::FatalError error) { throw FatalError(error.what()); }
}

float AudioEnvironment::getSoundVelocity() throw (FatalError) {
	float speed;
	try {
	speed = _openalppAudioEnvironment->getSoundVelocity();
	}
	catch(openalpp::FatalError error) { throw FatalError(error.what()); }
	return speed;
}

void AudioEnvironment::setDopplerFactor(float factor)
throw (ValueError,FatalError) {
	try {
	_openalppAudioEnvironment->setDopplerFactor (factor);
	}
	catch(openalpp::ValueError error) { throw ValueError(error.what()); }
	catch(openalpp::FatalError error) { throw FatalError(error.what()); }
}

float AudioEnvironment::getDopplerFactor() throw (FatalError) {
	float factor;
	try {
	factor = _openalppAudioEnvironment->getDopplerFactor();
	}
	catch(openalpp::FatalError error) { throw FatalError(error.what()); }
	return factor;
}

void AudioEnvironment::setUnitScale(float scale) throw (ValueError,FatalError) {
	_dummyUnitScale = scale;
}

float AudioEnvironment::getUnitScale() throw (FatalError) {
	return(_dummyUnitScale);
}

void AudioEnvironment::setGain(float gain) {
	try {
	_openalppAudioEnvironment->setGain (gain);
	}
	catch(openalpp::ValueError error) { throw ValueError(error.what()); }
	catch(openalpp::FatalError error) { throw FatalError(error.what()); }
}

float AudioEnvironment::getGain() throw (FatalError) {
	float gain;
	try {
	gain = _openalppAudioEnvironment->getGain();
	}
	catch(openalpp::FatalError error) { throw FatalError(error.what()); }
	return gain;
}

void AudioEnvironment::setDistanceModel(DistanceModel model)
throw (FatalError){
	try {
	_openalppAudioEnvironment->setDistanceModel (_openalppDistanceModelTranslate[model]);
	}
	catch(openalpp::FatalError error) { throw FatalError(error.what()); }
}

DistanceModel AudioEnvironment::getDistanceModel() throw (FatalError) {
	DistanceModel dmodel;
	try {
	dmodel = _osgAudioDistanceModelTranslate[_openalppAudioEnvironment->getDistanceModel()];
	}
	catch(openalpp::FatalError error) { throw FatalError(error.what()); }
	return dmodel;
}

void AudioEnvironment::initiateReverb() throw (InitError) {
	try {
	_openalppAudioEnvironment->initiateReverb();
	}
	catch(openalpp::InitError error) { throw InitError(error.what()); }
}

<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <fstream>
#include <cstdint>

template <typename T>
std::ostream& operator<<(std::ostream&, const BinarySearchTree<T>&);

template <class T>
struct Node
{
	T data;
	Node<T>* left;
	Node<T>* right;
};

template <class T>
class BinaryTree
{
private:
	Node<T> *root;
	uint16_t CountElements = 0;
public:
	BinaryTree();
	~BinaryTree();
	void deleteNode(Node<T>* temp);
	void insert_node(const T&);
	void print()const;
	Node<T>*root_();
	Node<T> *find_node(const T&, Node<T>*)const;
	void output(ostream&, Node<T>*)const;
	void reading(const std::string&);
	void writing(const std::string&)const;
	bool search_result(const T& value)const;
	Node<T>* get_pointer(const T& value, Node<T>* temp)const;
	ostream& show(std::ostream&, const Node<T>*, unsigned int);
	friend std::ostream& operator<< <> (std::ostream&, BinaryTree<T>*);

};

template<typename T>
BinaryTree<T>::BinaryTree()
{
	root = nullptr;
}

template<typename T>
BinaryTree<T>::~BinaryTree()
{
	deleteNode(root);
}

template<typename T>
Node<T> *BinaryTree<T>::get_pointer(const T& value, Node<T>* temp)const
{
	if (temp == 0 || value == temp->data)
		return temp;
	if (value > temp->data)
		return get_pointer(value, temp->right);
	else return get_pointer(value, temp->left);
}

template<typename T>
bool BinaryTree<T>::search_result(const T& value)const
{
	return get_pointer(value, root);
}

template<typename T>
void BinaryTree<T>::deleteNode(Node<T>* temp)
{
	if (!temp)
		return;
	if (temp->left)
	{
		deleteNode(temp->left);
		temp->left = nullptr;
	}

	if (temp->right)
	{
		deleteNode(temp->right);
		temp->right = nullptr;
	}
	delete temp;
}

template<typename T>
void BinaryTree<T>::insert_node(const T&x)
{
	if (find_node(x, root_())) return;
	Node<T>* MyTree = new Node<T>;
	MyTree->data = x;
	MyTree->left = MyTree->right = 0;
	Node<T>* buff = root;
	Node<T>* temp = root;
	while (temp)
	{
		buff = temp;
		if (x < temp->data)
			temp = temp->left;
		else
			temp = temp->right;
	}
	if (!buff)
		root = MyTree;
	else
	{
		if (x < buff->data)
			buff->left = MyTree;
		else
			buff->right = MyTree;
	}
	++CountElements;
}

template<typename T>
Node<T>* BinaryTree<T>::find_node(const T& value, Node<T>* temp) const
{
	if (temp == 0 || value == temp->data)
		return temp;
	if (value > temp->data)
		return find_node(value, temp->right);
	else
		return find_node(value, temp->left);
}

template<typename T>
void BinaryTree<T>::reading(const std::string& filename)
{
	ifstream fin(filename);
	if (root != nullptr)
		deleteNode(root);

	int k;
	fin >> k;
	T temp;
	for (int i = 0; i < k; ++i)
	{
		fin >> temp;
		insert_node(temp);
	}
	fin.close();
}

template<typename T>
void BinaryTree<T>::writing(const std::string& filename)const
{
	ofstream file_1(filename);
	file_1 << CountElements << "\t";
	output(file_1, root);
	file_1.close();
}

template <typename T>
std::ostream& show(std::ostream& ost, const Node<T>* temp, unsigned int level)
{
	show(ost, temp->right, level + 1);
	for (unsigned int i = 0; i < level; i++)
		ost << "\t";
	ost << temp->data << std::endl;
	show(ost, temp->left, level + 1);
	return ost;
}

template <typename T>
ostream& operator<<(std::ostream& ost, BinaryTree<T>& temp)
{
	show(ost, temp.root, 0);
	return ost;
}
<commit_msg>Update BinaryTree.hpp<commit_after>#include <iostream>
#include <string>
#include <fstream>
#include <cstdint>

using namespace std;

template <typename T>
std::ostream& operator<<(std::ostream&, const BinarySearchTree<T>&);

template <class T>
struct Node
{
	T data;
	Node<T>* left;
	Node<T>* right;
};

template <class T>
class BinaryTree
{
private:
	Node<T> *root;
	uint16_t CountElements = 0;
public:
	BinaryTree();
	~BinaryTree();
	void deleteNode(Node<T>* temp);
	void insert_node(const T&);
	void print()const;
	Node<T>*root_();
	Node<T> *find_node(const T&, Node<T>*)const;
	void output(ostream&, Node<T>*)const;
	void reading(const std::string&);
	void writing(const std::string&)const;
	bool search_result(const T& value)const;
	Node<T>* get_pointer(const T& value, Node<T>* temp)const;
	ostream& show(std::ostream&, const Node<T>*, unsigned int);
	friend std::ostream& operator<< <> (std::ostream&, BinaryTree<T>*);

};

template<typename T>
BinaryTree<T>::BinaryTree()
{
	root = nullptr;
}

template<typename T>
BinaryTree<T>::~BinaryTree()
{
	deleteNode(root);
}

template<typename T>
Node<T> *BinaryTree<T>::get_pointer(const T& value, Node<T>* temp)const
{
	if (temp == 0 || value == temp->data)
		return temp;
	if (value > temp->data)
		return get_pointer(value, temp->right);
	else return get_pointer(value, temp->left);
}

template<typename T>
bool BinaryTree<T>::search_result(const T& value)const
{
	return get_pointer(value, root);
}

template<typename T>
void BinaryTree<T>::deleteNode(Node<T>* temp)
{
	if (!temp)
		return;
	if (temp->left)
	{
		deleteNode(temp->left);
		temp->left = nullptr;
	}

	if (temp->right)
	{
		deleteNode(temp->right);
		temp->right = nullptr;
	}
	delete temp;
}

template<typename T>
void BinaryTree<T>::insert_node(const T&x)
{
	if (find_node(x, root_())) return;
	Node<T>* MyTree = new Node<T>;
	MyTree->data = x;
	MyTree->left = MyTree->right = 0;
	Node<T>* buff = root;
	Node<T>* temp = root;
	while (temp)
	{
		buff = temp;
		if (x < temp->data)
			temp = temp->left;
		else
			temp = temp->right;
	}
	if (!buff)
		root = MyTree;
	else
	{
		if (x < buff->data)
			buff->left = MyTree;
		else
			buff->right = MyTree;
	}
	++CountElements;
}

template<typename T>
Node<T>* BinaryTree<T>::find_node(const T& value, Node<T>* temp) const
{
	if (temp == 0 || value == temp->data)
		return temp;
	if (value > temp->data)
		return find_node(value, temp->right);
	else
		return find_node(value, temp->left);
}

template<typename T>
void BinaryTree<T>::reading(const std::string& filename)
{
	ifstream fin(filename);
	if (root != nullptr)
		deleteNode(root);

	int k;
	fin >> k;
	T temp;
	for (int i = 0; i < k; ++i)
	{
		fin >> temp;
		insert_node(temp);
	}
	fin.close();
}

template<typename T>
void BinaryTree<T>::writing(const std::string& filename)const
{
	ofstream file_1(filename);
	file_1 << CountElements << "\t";
	output(file_1, root);
	file_1.close();
}

template <typename T>
std::ostream& show(std::ostream& ost, const Node<T>* temp, unsigned int level)
{
	show(ost, temp->right, level + 1);
	for (unsigned int i = 0; i < level; i++)
		ost << "\t";
	ost << temp->data << std::endl;
	show(ost, temp->left, level + 1);
	return ost;
}

template <typename T>
ostream& operator<<(std::ostream& ost, BinaryTree<T>& temp)
{
	show(ost, temp.root, 0);
	return ost;
}
<|endoftext|>


<commit_before>#include "src/fillers.h"
#include "src/utils.h"

/* ***** */
void gfx_flatFill(const gfx_Triangle *t, gfx_drawBuffer *buffer, enum TriangleType type)
{
    const gfx_Vertex *v0 = &t->vertices[0];
    const gfx_Vertex *v1 = &t->vertices[1];
    const gfx_Vertex *v2 = &t->vertices[2];
    double y, invDy, dxLeft, dxRight, xLeft, xRight, prestep;
    int currLine, numScanlines, x0, x1, yDir = 1;
    // variables used if depth test is enabled
    float startInvZ, endInvZ, invZ0, invZ1, invZ2, invY02;

    if(type == FLAT_BOTTOM)
    {
        invDy  = 1.0 / (v2->position.y - v0->position.y);
        numScanlines = ceil(v2->position.y) - ceil(v0->position.y);
        prestep = ceil(v0->position.y) - v0->position.y;
        // todo: handle line sizes of height < 1
        if(v2->position.y - v0->position.y < 1) return;
    }
    else
    {
        invDy  = 1.0 / (v0->position.y - v2->position.y);
        yDir = -1;
        numScanlines = ceil(v0->position.y) - ceil(v2->position.y);
        prestep = ceil(v2->position.y) - v2->position.y;
        // todo: handle line sizes of height < 1
        if(v0->position.y - v2->position.y < 1) return;
    }

    dxLeft  = (v2->position.x - v0->position.x) * invDy;
    dxRight = (v1->position.x - v0->position.x) * invDy;
    xLeft   = v0->position.x + dxLeft * prestep;
    xRight  = v0->position.x + dxRight * prestep;

    // skip the unnecessary divisions if there's no depth testing
    if(buffer->drawOpts.depthFunc != DF_ALWAYS)
    {
        invZ0  = 1.f / v0->position.z;
        invZ1  = 1.f / v1->position.z;
        invZ2  = 1.f / v2->position.z;
        invY02 = 1.f / (v0->position.y - v2->position.y);
    }

    for(currLine = 0, y = ceil(v0->position.y); currLine <= numScanlines; y += yDir)
    {
        x0 = ceil(xLeft);
        x1 = ceil(xRight);

        // interpolate 1/z only if depth testing is enabled
        if(buffer->drawOpts.depthFunc != DF_ALWAYS)
        {
            float r1  = (v0->position.y - y) * invY02;
            startInvZ = LERP(invZ0, invZ2, r1);
            endInvZ   = LERP(invZ0, invZ1, r1);
            gfx_drawLine(x0, y, 1.f/startInvZ, x1, y, 1.f/endInvZ, t->color, buffer);
        }
        else
            gfx_drawLine(x0, y, 0.f, x1, y, 0.f, t->color, buffer);

        if(++currLine < numScanlines)
        {
            xLeft  += dxLeft;
            xRight += dxRight;
        }
    }
}

/* ***** */
void gfx_perspectiveTextureMap(const gfx_Triangle *t, gfx_drawBuffer *buffer, enum TriangleType type)
{
    const gfx_Vertex *v0 = &t->vertices[0];
    const gfx_Vertex *v1 = &t->vertices[1];
    const gfx_Vertex *v2 = &t->vertices[2];
    double x, y, invDy, dxLeft, dxRight, prestep, yDir = 1;
    double startX, endX, startXPrestep, endXPrestep;
    int   useColorKey = buffer->drawOpts.colorKey != -1 ? 1 : 0;
    int   texW = t->texture->width - 1;
    int   texH = t->texture->height - 1;
    int   texArea = texW * texH;
    int   currLine, numScanlines;
    float invZ0, invZ1, invZ2, invY02 = 1.f;

    if(type == FLAT_BOTTOM)
    {
        invDy  = 1.0 / (v2->position.y - v0->position.y);
        numScanlines = ceil(v2->position.y) - ceil(v0->position.y);
        prestep = ceil(v0->position.y) - v0->position.y;
        // todo: handle line sizes of height < 1
        if(v2->position.y - v0->position.y < 1) return;
    }
    else
    {
        invDy  = 1.0 / (v0->position.y - v2->position.y);
        yDir = -1;
        numScanlines = ceil(v0->position.y) - ceil(v2->position.y);
        prestep = ceil(v2->position.y) - v2->position.y;
        // todo: handle line sizes of height < 1
        if(v0->position.y - v2->position.y < 1) return;
    }

    dxLeft  = (v2->position.x - v0->position.x) * invDy;
    dxRight = (v1->position.x - v0->position.x) * invDy;
    startX  = v0->position.x;
    endX    = startX;
    startXPrestep = v0->position.x + dxLeft * prestep;
    endXPrestep   = v0->position.x + dxRight * prestep;

    invZ0  = 1.f / v0->position.z;
    invZ1  = 1.f / v1->position.z;
    invZ2  = 1.f / v2->position.z;
    invY02 = 1.f / (v0->position.y - v2->position.y);

    for(currLine = 0, y = v0->position.y; currLine <= numScanlines; y += yDir)
    {
        float startInvZ, endInvZ, r1, invLineLength = 0.f;
        float startU = texW, startV = texH, endU = texW, endV = texH;

        r1 = (v0->position.y - y) * invY02;
        startInvZ = LERP(invZ0, invZ2, r1);
        endInvZ   = LERP(invZ0, invZ1, r1);

        startU *= LERP(v0->uv.u * invZ0, v2->uv.u * invZ2, r1);
        startV *= LERP(v0->uv.v * invZ0, v2->uv.v * invZ2, r1);
        endU   *= LERP(v0->uv.u * invZ0, v1->uv.u * invZ1, r1);
        endV   *= LERP(v0->uv.v * invZ0, v1->uv.v * invZ1, r1);

        if(startX != endX)
            invLineLength = 1.f / (endX - startX);

        for(x = startXPrestep; x <= endXPrestep; ++x)
        {
            // interpolate 1/z for each pixel in the scanline
            float r = (x - startX) * invLineLength;
            float lerpInvZ = LERP(startInvZ, endInvZ, r);
            float z = 1.f/lerpInvZ;
            float u = z * LERP(startU, endU, r);
            float v = z * LERP(startV, endV, r);

            // fetch texture data with a texArea modulus for proper effect in case u or v are > 1
            unsigned char pixel = t->texture->data[((int)u + ((int)v * t->texture->height)) % texArea];

            if(!useColorKey || (useColorKey && pixel != (unsigned char)buffer->drawOpts.colorKey))
            {
                // DF_ALWAYS = no depth test
                if(buffer->drawOpts.depthFunc == DF_ALWAYS)
                    gfx_drawPixel(ceil(x), ceil(y), pixel, buffer);
                else
                    gfx_drawPixelWithDepth(ceil(x), ceil(y), lerpInvZ, pixel, buffer);
            }
        }

        startX += dxLeft;
        endX   += dxRight;

        if(++currLine < numScanlines)
        {
            startXPrestep += dxLeft;
            endXPrestep   += dxRight;
        }
    }
}

/* ***** */
void gfx_affineTextureMap(const gfx_Triangle *t, gfx_drawBuffer *buffer, enum TriangleType type)
{
    const gfx_Vertex *v0 = &t->vertices[0];
    const gfx_Vertex *v1 = &t->vertices[1];
    const gfx_Vertex *v2 = &t->vertices[2];
    double x, y, invDy, dxLeft, dxRight, prestep, yDir = 1;
    double startU, startV, invDx, du, dv, startX, endX;
    float duLeft, dvLeft, duRight, dvRight;
    float texW = t->texture->width - 1;
    float texH = t->texture->height - 1;
    int   useColorKey = buffer->drawOpts.colorKey != -1 ? 1 : 0;
    int   texArea = texW * texH;
    int   currLine, numScanlines;
    // variables used only if depth test is enabled
    float invZ0, invZ1, invZ2, invY02 = 1.f;

    if(type == FLAT_BOTTOM)
    {
        invDy  = 1.f / (v2->position.y - v0->position.y);
        numScanlines = ceil(v2->position.y) - ceil(v0->position.y);
        prestep = ceil(v0->position.y) - v0->position.y;
        // todo: handle line sizes of height < 1
        if(v2->position.y - v0->position.y < 1) return;
    }
    else
    {
        invDy  = 1.f / (v0->position.y - v2->position.y);
        yDir = -1;
        numScanlines = ceil(v0->position.y) - ceil(v2->position.y);
        prestep = ceil(v2->position.y) - v2->position.y;
        // todo: handle line sizes of height < 1
        if(v0->position.y - v2->position.y < 1) return;
    }

    dxLeft  = (v2->position.x - v0->position.x) * invDy;
    dxRight = (v1->position.x - v0->position.x) * invDy;

    duLeft  = texW * (v2->uv.u - v0->uv.u) * invDy;
    dvLeft  = texH * (v2->uv.v - v0->uv.v) * invDy;
    duRight = texW * (v1->uv.u - v0->uv.u) * invDy;
    dvRight = texH * (v1->uv.v - v0->uv.v) * invDy;

    startU = texW * v0->uv.u + duLeft * prestep;
    startV = texH * v0->uv.v + dvLeft * prestep;
    // With triangles the texture gradients (u,v slopes over the triangle surface)
    // are guaranteed to be constant, so we need to calculate du and dv only once.
    invDx = 1.f / (dxRight - dxLeft);
    du = (duRight - duLeft) * invDx;
    dv = (dvRight - dvLeft) * invDx;
    startX = v0->position.x + dxLeft * prestep;
    endX   = v0->position.x + dxRight * prestep;

    // skip the unnecessary divisions if there's no depth testing
    if(buffer->drawOpts.depthFunc != DF_ALWAYS)
    {
        invZ0  = 1.f / v0->position.z;
        invZ1  = 1.f / v1->position.z;
        invZ2  = 1.f / v2->position.z;
        invY02 = 1.f / (v0->position.y - v2->position.y);
    }

    for(currLine = 0, y = v0->position.y; currLine <= numScanlines; y += yDir)
    {
        float u = startU;
        float v = startV;
        // variables used only if depth test is enabled
        float startInvZ, endInvZ, invLineLength = 0.f;

        // interpolate 1/z only if depth testing is enabled
        if(buffer->drawOpts.depthFunc != DF_ALWAYS)
        {
            float r1  = (v0->position.y - y) * invY02;
            startInvZ = LERP(invZ0, invZ2, r1);
            endInvZ   = LERP(invZ0, invZ1, r1);

            if(startX != endX)
                invLineLength = 1.f / (endX - startX);
        }

        for(x = startX; x <= endX; ++x)
        {
            // fetch texture data with a texArea modulus for proper effect in case u or v are > 1
            unsigned char pixel = t->texture->data[((int)u + ((int)v * t->texture->height)) % texArea];

            if(!useColorKey || (useColorKey && pixel != (unsigned char)buffer->drawOpts.colorKey))
            {
                // DF_ALWAYS = no depth test
                if(buffer->drawOpts.depthFunc == DF_ALWAYS)
                    gfx_drawPixel(ceil(x), ceil(y), pixel, buffer);
                else
                {
                    float r = (x - startX) * invLineLength;
                    float lerpInvZ = LERP(startInvZ, endInvZ, r);
                    gfx_drawPixelWithDepth(ceil(x), ceil(y), lerpInvZ, pixel, buffer);
                }
            }
            u += du;
            v += dv;
        }

        if(++currLine < numScanlines)
        {
            startX += dxLeft;
            endX   += dxRight;
            startU += duLeft;
            startV += dvLeft;
        }
    }
}
<commit_msg>use correct startX and endX values for affine texture map<commit_after>#include "src/fillers.h"
#include "src/utils.h"

/* ***** */
void gfx_flatFill(const gfx_Triangle *t, gfx_drawBuffer *buffer, enum TriangleType type)
{
    const gfx_Vertex *v0 = &t->vertices[0];
    const gfx_Vertex *v1 = &t->vertices[1];
    const gfx_Vertex *v2 = &t->vertices[2];
    double y, invDy, dxLeft, dxRight, xLeft, xRight, prestep;
    int currLine, numScanlines, x0, x1, yDir = 1;
    // variables used if depth test is enabled
    float startInvZ, endInvZ, invZ0, invZ1, invZ2, invY02;

    if(type == FLAT_BOTTOM)
    {
        invDy  = 1.0 / (v2->position.y - v0->position.y);
        numScanlines = ceil(v2->position.y) - ceil(v0->position.y);
        prestep = ceil(v0->position.y) - v0->position.y;
        // todo: handle line sizes of height < 1
        if(v2->position.y - v0->position.y < 1) return;
    }
    else
    {
        invDy  = 1.0 / (v0->position.y - v2->position.y);
        yDir = -1;
        numScanlines = ceil(v0->position.y) - ceil(v2->position.y);
        prestep = ceil(v2->position.y) - v2->position.y;
        // todo: handle line sizes of height < 1
        if(v0->position.y - v2->position.y < 1) return;
    }

    dxLeft  = (v2->position.x - v0->position.x) * invDy;
    dxRight = (v1->position.x - v0->position.x) * invDy;
    xLeft   = v0->position.x + dxLeft * prestep;
    xRight  = v0->position.x + dxRight * prestep;

    // skip the unnecessary divisions if there's no depth testing
    if(buffer->drawOpts.depthFunc != DF_ALWAYS)
    {
        invZ0  = 1.f / v0->position.z;
        invZ1  = 1.f / v1->position.z;
        invZ2  = 1.f / v2->position.z;
        invY02 = 1.f / (v0->position.y - v2->position.y);
    }

    for(currLine = 0, y = ceil(v0->position.y); currLine <= numScanlines; y += yDir)
    {
        x0 = ceil(xLeft);
        x1 = ceil(xRight);

        // interpolate 1/z only if depth testing is enabled
        if(buffer->drawOpts.depthFunc != DF_ALWAYS)
        {
            float r1  = (v0->position.y - y) * invY02;
            startInvZ = LERP(invZ0, invZ2, r1);
            endInvZ   = LERP(invZ0, invZ1, r1);
            gfx_drawLine(x0, y, 1.f/startInvZ, x1, y, 1.f/endInvZ, t->color, buffer);
        }
        else
            gfx_drawLine(x0, y, 0.f, x1, y, 0.f, t->color, buffer);

        if(++currLine < numScanlines)
        {
            xLeft  += dxLeft;
            xRight += dxRight;
        }
    }
}

/* ***** */
void gfx_perspectiveTextureMap(const gfx_Triangle *t, gfx_drawBuffer *buffer, enum TriangleType type)
{
    const gfx_Vertex *v0 = &t->vertices[0];
    const gfx_Vertex *v1 = &t->vertices[1];
    const gfx_Vertex *v2 = &t->vertices[2];
    double x, y, invDy, dxLeft, dxRight, prestep, yDir = 1;
    double startX, endX, startXPrestep, endXPrestep;
    int   useColorKey = buffer->drawOpts.colorKey != -1 ? 1 : 0;
    int   texW = t->texture->width - 1;
    int   texH = t->texture->height - 1;
    int   texArea = texW * texH;
    int   currLine, numScanlines;
    float invZ0, invZ1, invZ2, invY02 = 1.f;

    if(type == FLAT_BOTTOM)
    {
        invDy  = 1.0 / (v2->position.y - v0->position.y);
        numScanlines = ceil(v2->position.y) - ceil(v0->position.y);
        prestep = ceil(v0->position.y) - v0->position.y;
        // todo: handle line sizes of height < 1
        if(v2->position.y - v0->position.y < 1) return;
    }
    else
    {
        invDy  = 1.0 / (v0->position.y - v2->position.y);
        yDir = -1;
        numScanlines = ceil(v0->position.y) - ceil(v2->position.y);
        prestep = ceil(v2->position.y) - v2->position.y;
        // todo: handle line sizes of height < 1
        if(v0->position.y - v2->position.y < 1) return;
    }

    dxLeft  = (v2->position.x - v0->position.x) * invDy;
    dxRight = (v1->position.x - v0->position.x) * invDy;
    startX  = v0->position.x;
    endX    = startX;
    startXPrestep = v0->position.x + dxLeft * prestep;
    endXPrestep   = v0->position.x + dxRight * prestep;

    invZ0  = 1.f / v0->position.z;
    invZ1  = 1.f / v1->position.z;
    invZ2  = 1.f / v2->position.z;
    invY02 = 1.f / (v0->position.y - v2->position.y);

    for(currLine = 0, y = v0->position.y; currLine <= numScanlines; y += yDir)
    {
        float startInvZ, endInvZ, r1, invLineLength = 0.f;
        float startU = texW, startV = texH, endU = texW, endV = texH;

        r1 = (v0->position.y - y) * invY02;
        startInvZ = LERP(invZ0, invZ2, r1);
        endInvZ   = LERP(invZ0, invZ1, r1);

        startU *= LERP(v0->uv.u * invZ0, v2->uv.u * invZ2, r1);
        startV *= LERP(v0->uv.v * invZ0, v2->uv.v * invZ2, r1);
        endU   *= LERP(v0->uv.u * invZ0, v1->uv.u * invZ1, r1);
        endV   *= LERP(v0->uv.v * invZ0, v1->uv.v * invZ1, r1);

        if(startX != endX)
            invLineLength = 1.f / (endX - startX);

        for(x = startXPrestep; x <= endXPrestep; ++x)
        {
            // interpolate 1/z for each pixel in the scanline
            float r = (x - startX) * invLineLength;
            float lerpInvZ = LERP(startInvZ, endInvZ, r);
            float z = 1.f/lerpInvZ;
            float u = z * LERP(startU, endU, r);
            float v = z * LERP(startV, endV, r);

            // fetch texture data with a texArea modulus for proper effect in case u or v are > 1
            unsigned char pixel = t->texture->data[((int)u + ((int)v * t->texture->height)) % texArea];

            if(!useColorKey || (useColorKey && pixel != (unsigned char)buffer->drawOpts.colorKey))
            {
                // DF_ALWAYS = no depth test
                if(buffer->drawOpts.depthFunc == DF_ALWAYS)
                    gfx_drawPixel(ceil(x), ceil(y), pixel, buffer);
                else
                    gfx_drawPixelWithDepth(ceil(x), ceil(y), lerpInvZ, pixel, buffer);
            }
        }

        startX += dxLeft;
        endX   += dxRight;

        if(++currLine < numScanlines)
        {
            startXPrestep += dxLeft;
            endXPrestep   += dxRight;
        }
    }
}

/* ***** */
void gfx_affineTextureMap(const gfx_Triangle *t, gfx_drawBuffer *buffer, enum TriangleType type)
{
    const gfx_Vertex *v0 = &t->vertices[0];
    const gfx_Vertex *v1 = &t->vertices[1];
    const gfx_Vertex *v2 = &t->vertices[2];
    double x, y, invDy, dxLeft, dxRight, prestep, yDir = 1;
    double startU, startV, invDx, du, dv;
    double startX, endX, startXPrestep, endXPrestep;
    float duLeft, dvLeft, duRight, dvRight;
    float texW = t->texture->width - 1;
    float texH = t->texture->height - 1;
    int   useColorKey = buffer->drawOpts.colorKey != -1 ? 1 : 0;
    int   texArea = texW * texH;
    int   currLine, numScanlines;
    // variables used only if depth test is enabled
    float invZ0, invZ1, invZ2, invY02 = 1.f;

    if(type == FLAT_BOTTOM)
    {
        invDy  = 1.f / (v2->position.y - v0->position.y);
        numScanlines = ceil(v2->position.y) - ceil(v0->position.y);
        prestep = ceil(v0->position.y) - v0->position.y;
        // todo: handle line sizes of height < 1
        if(v2->position.y - v0->position.y < 1) return;
    }
    else
    {
        invDy  = 1.f / (v0->position.y - v2->position.y);
        yDir = -1;
        numScanlines = ceil(v0->position.y) - ceil(v2->position.y);
        prestep = ceil(v2->position.y) - v2->position.y;
        // todo: handle line sizes of height < 1
        if(v0->position.y - v2->position.y < 1) return;
    }

    dxLeft  = (v2->position.x - v0->position.x) * invDy;
    dxRight = (v1->position.x - v0->position.x) * invDy;

    duLeft  = texW * (v2->uv.u - v0->uv.u) * invDy;
    dvLeft  = texH * (v2->uv.v - v0->uv.v) * invDy;
    duRight = texW * (v1->uv.u - v0->uv.u) * invDy;
    dvRight = texH * (v1->uv.v - v0->uv.v) * invDy;

    startU = texW * v0->uv.u + duLeft * prestep;
    startV = texH * v0->uv.v + dvLeft * prestep;
    // With triangles the texture gradients (u,v slopes over the triangle surface)
    // are guaranteed to be constant, so we need to calculate du and dv only once.
    invDx = 1.f / (dxRight - dxLeft);
    du = (duRight - duLeft) * invDx;
    dv = (dvRight - dvLeft) * invDx;
    startX = v0->position.x;
    endX   = startX;
    startXPrestep = v0->position.x + dxLeft * prestep;
    endXPrestep   = v0->position.x + dxRight * prestep;

    // skip the unnecessary divisions if there's no depth testing
    if(buffer->drawOpts.depthFunc != DF_ALWAYS)
    {
        invZ0  = 1.f / v0->position.z;
        invZ1  = 1.f / v1->position.z;
        invZ2  = 1.f / v2->position.z;
        invY02 = 1.f / (v0->position.y - v2->position.y);
    }

    for(currLine = 0, y = v0->position.y; currLine <= numScanlines; y += yDir)
    {
        float u = startU;
        float v = startV;
        // variables used only if depth test is enabled
        float startInvZ, endInvZ, invLineLength = 0.f;

        // interpolate 1/z only if depth testing is enabled
        if(buffer->drawOpts.depthFunc != DF_ALWAYS)
        {
            float r1  = (v0->position.y - y) * invY02;
            startInvZ = LERP(invZ0, invZ2, r1);
            endInvZ   = LERP(invZ0, invZ1, r1);

            if(startX != endX)
                invLineLength = 1.f / (endX - startX);
        }

        for(x = startXPrestep; x <= endXPrestep; ++x)
        {
            // fetch texture data with a texArea modulus for proper effect in case u or v are > 1
            unsigned char pixel = t->texture->data[((int)u + ((int)v * t->texture->height)) % texArea];

            if(!useColorKey || (useColorKey && pixel != (unsigned char)buffer->drawOpts.colorKey))
            {
                // DF_ALWAYS = no depth test
                if(buffer->drawOpts.depthFunc == DF_ALWAYS)
                    gfx_drawPixel(ceil(x), ceil(y), pixel, buffer);
                else
                {
                    float r = (x - startX) * invLineLength;
                    float lerpInvZ = LERP(startInvZ, endInvZ, r);
                    gfx_drawPixelWithDepth(ceil(x), ceil(y), lerpInvZ, pixel, buffer);
                }
            }
            u += du;
            v += dv;
        }

        startX += dxLeft;
        endX   += dxRight;

        if(++currLine < numScanlines)
        {
            startXPrestep += dxLeft;
            endXPrestep   += dxRight;
            startU += duLeft;
            startV += dvLeft;
        }
    }
}
<|endoftext|>