<commit_before>//===- X86EvexToVex.cpp ---------------------------------------------------===//
// Compress EVEX instructions to VEX encoding when possible to reduce code size
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
/// \file
/// This file defines the pass that goes over all AVX-512 instructions which
/// are encoded using the EVEX prefix and if possible replaces them by their
/// corresponding VEX encoding which is usually shorter by 2 bytes.
/// EVEX instructions may be encoded via the VEX prefix when the AVX-512
/// instruction has a corresponding AVX/AVX2 opcode and when it does not
/// use the xmm or the mask registers or xmm/ymm registers wuith indexes
/// higher than 15.
/// The pass applies code reduction on the generated code for AVX-512 instrs.
//
//===----------------------------------------------------------------------===//

#include "InstPrinter/X86InstComments.h"
#include "MCTargetDesc/X86BaseInfo.h"
#include "X86.h"
#include "X86InstrInfo.h"
#include "X86Subtarget.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/MC/MCInstrDesc.h"
#include "llvm/Pass.h"
#include <cassert>
#include <cstdint>

using namespace llvm;

// Including the generated EVEX2VEX tables.
struct X86EvexToVexCompressTableEntry {
  uint16_t EvexOpcode;
  uint16_t VexOpcode;
};
#include "X86GenEVEX2VEXTables.inc"

#define EVEX2VEX_DESC "Compressing EVEX instrs to VEX encoding when possible"
#define EVEX2VEX_NAME "x86-evex-to-vex-compress"

#define DEBUG_TYPE EVEX2VEX_NAME

namespace {

class EvexToVexInstPass : public MachineFunctionPass {

  /// X86EvexToVexCompressTable - Evex to Vex encoding opcode map.
  using EvexToVexTableType = DenseMap<unsigned, uint16_t>;
  EvexToVexTableType EvexToVex128Table;
  EvexToVexTableType EvexToVex256Table;

  /// For EVEX instructions that can be encoded using VEX encoding, replace
  /// them by the VEX encoding in order to reduce size.
  bool CompressEvexToVexImpl(MachineInstr &MI) const;

  /// For initializing the hash map tables of all AVX-512 EVEX
  /// corresponding to AVX/AVX2 opcodes.
  void AddTableEntry(EvexToVexTableType &EvexToVexTable, uint16_t EvexOp,
                     uint16_t VexOp);

public:
  static char ID;

  EvexToVexInstPass() : MachineFunctionPass(ID) {
    initializeEvexToVexInstPassPass(*PassRegistry::getPassRegistry());

    // Initialize the EVEX to VEX 128 table map.
    for (X86EvexToVexCompressTableEntry Entry : X86EvexToVex128CompressTable) {
      AddTableEntry(EvexToVex128Table, Entry.EvexOpcode, Entry.VexOpcode);
    }

    // Initialize the EVEX to VEX 256 table map.
    for (X86EvexToVexCompressTableEntry Entry : X86EvexToVex256CompressTable) {
      AddTableEntry(EvexToVex256Table, Entry.EvexOpcode, Entry.VexOpcode);
    }
  }

  StringRef getPassName() const override { return EVEX2VEX_DESC; }

  /// Loop over all of the basic blocks, replacing EVEX instructions
  /// by equivalent VEX instructions when possible for reducing code size.
  bool runOnMachineFunction(MachineFunction &MF) override;

  // This pass runs after regalloc and doesn't support VReg operands.
  MachineFunctionProperties getRequiredProperties() const override {
    return MachineFunctionProperties().set(
        MachineFunctionProperties::Property::NoVRegs);
  }

private:
  /// Machine instruction info used throughout the class.
  const X86InstrInfo *TII;
};

} // end anonymous namespace

char EvexToVexInstPass::ID = 0;

bool EvexToVexInstPass::runOnMachineFunction(MachineFunction &MF) {
  TII = MF.getSubtarget<X86Subtarget>().getInstrInfo();

  const X86Subtarget &ST = MF.getSubtarget<X86Subtarget>();
  if (!ST.hasAVX512())
    return false;

  bool Changed = false;

  /// Go over all basic blocks in function and replace
  /// EVEX encoded instrs by VEX encoding when possible.
  for (MachineBasicBlock &MBB : MF) {

    // Traverse the basic block.
    for (MachineInstr &MI : MBB)
      Changed |= CompressEvexToVexImpl(MI);
  }

  return Changed;
}

void EvexToVexInstPass::AddTableEntry(EvexToVexTableType &EvexToVexTable,
                                      uint16_t EvexOp, uint16_t VexOp) {
  EvexToVexTable[EvexOp] = VexOp;
}

// For EVEX instructions that can be encoded using VEX encoding
// replace them by the VEX encoding in order to reduce size.
bool EvexToVexInstPass::CompressEvexToVexImpl(MachineInstr &MI) const {
  // VEX format.
  // # of bytes: 0,2,3  1      1      0,1   0,1,2,4  0,1
  //  [Prefixes] [VEX]  OPCODE ModR/M [SIB] [DISP]  [IMM]
  //
  // EVEX format.
  //  # of bytes: 4    1      1      1      4       / 1         1
  //  [Prefixes]  EVEX Opcode ModR/M [SIB] [Disp32] / [Disp8*N] [Immediate]

  const MCInstrDesc &Desc = MI.getDesc();

  // Check for EVEX instructions only.
  if ((Desc.TSFlags & X86II::EncodingMask) != X86II::EVEX)
    return false;

  // Check for EVEX instructions with mask or broadcast as in these cases
  // the EVEX prefix is needed in order to carry this information
  // thus preventing the transformation to VEX encoding.
  if (Desc.TSFlags & (X86II::EVEX_K | X86II::EVEX_B))
    return false;

  // Check for non EVEX_V512 instrs only.
  // EVEX_V512 instr: bit EVEX_L2 = 1; bit VEX_L = 0.
  if ((Desc.TSFlags & X86II::EVEX_L2) && !(Desc.TSFlags & X86II::VEX_L))
    return false;

  // EVEX_V128 instr: bit EVEX_L2 = 0, bit VEX_L = 0.
  bool IsEVEX_V128 =
      (!(Desc.TSFlags & X86II::EVEX_L2) && !(Desc.TSFlags & X86II::VEX_L));

  // EVEX_V256 instr: bit EVEX_L2 = 0, bit VEX_L = 1.
  bool IsEVEX_V256 =
      (!(Desc.TSFlags & X86II::EVEX_L2) && (Desc.TSFlags & X86II::VEX_L));

  unsigned NewOpc = 0;

  // Check for EVEX_V256 instructions.
  if (IsEVEX_V256) {
    // Search for opcode in the EvexToVex256 table.
    auto It = EvexToVex256Table.find(MI.getOpcode());
    if (It != EvexToVex256Table.end())
      NewOpc = It->second;
  }
  // Check for EVEX_V128 or Scalar instructions.
  else if (IsEVEX_V128) {
    // Search for opcode in the EvexToVex128 table.
    auto It = EvexToVex128Table.find(MI.getOpcode());
    if (It != EvexToVex128Table.end())
      NewOpc = It->second;
  }

  if (!NewOpc)
    return false;

  auto isHiRegIdx = [](unsigned Reg) {
    // Check for XMM register with indexes between 16 - 31.
    if (Reg >= X86::XMM16 && Reg <= X86::XMM31)
      return true;

    // Check for YMM register with indexes between 16 - 31.
    if (Reg >= X86::YMM16 && Reg <= X86::YMM31)
      return true;

    return false;
  };

  // Check that operands are not ZMM regs or
  // XMM/YMM regs with hi indexes between 16 - 31.
  for (const MachineOperand &MO : MI.explicit_operands()) {
    if (!MO.isReg())
      continue;

    unsigned Reg = MO.getReg();

    assert (!(Reg >= X86::ZMM0 && Reg <= X86::ZMM31));

    if (isHiRegIdx(Reg))
      return false;
  }

  const MCInstrDesc &MCID = TII->get(NewOpc);
  MI.setDesc(MCID);
  MI.setAsmPrinterFlag(AC_EVEX_2_VEX);
  return true;
}

INITIALIZE_PASS(EvexToVexInstPass, EVEX2VEX_NAME, EVEX2VEX_DESC, false, false)

FunctionPass *llvm::createX86EvexToVexInsts() {
  return new EvexToVexInstPass();
}
<commit_msg>[X86] Fix typo in comment. NFC<commit_after>//===- X86EvexToVex.cpp ---------------------------------------------------===//
// Compress EVEX instructions to VEX encoding when possible to reduce code size
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
/// \file
/// This file defines the pass that goes over all AVX-512 instructions which
/// are encoded using the EVEX prefix and if possible replaces them by their
/// corresponding VEX encoding which is usually shorter by 2 bytes.
/// EVEX instructions may be encoded via the VEX prefix when the AVX-512
/// instruction has a corresponding AVX/AVX2 opcode and when it does not
/// use the xmm or the mask registers or xmm/ymm registers with indexes
/// higher than 15.
/// The pass applies code reduction on the generated code for AVX-512 instrs.
//
//===----------------------------------------------------------------------===//

#include "InstPrinter/X86InstComments.h"
#include "MCTargetDesc/X86BaseInfo.h"
#include "X86.h"
#include "X86InstrInfo.h"
#include "X86Subtarget.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/MC/MCInstrDesc.h"
#include "llvm/Pass.h"
#include <cassert>
#include <cstdint>

using namespace llvm;

// Including the generated EVEX2VEX tables.
struct X86EvexToVexCompressTableEntry {
  uint16_t EvexOpcode;
  uint16_t VexOpcode;
};
#include "X86GenEVEX2VEXTables.inc"

#define EVEX2VEX_DESC "Compressing EVEX instrs to VEX encoding when possible"
#define EVEX2VEX_NAME "x86-evex-to-vex-compress"

#define DEBUG_TYPE EVEX2VEX_NAME

namespace {

class EvexToVexInstPass : public MachineFunctionPass {

  /// X86EvexToVexCompressTable - Evex to Vex encoding opcode map.
  using EvexToVexTableType = DenseMap<unsigned, uint16_t>;
  EvexToVexTableType EvexToVex128Table;
  EvexToVexTableType EvexToVex256Table;

  /// For EVEX instructions that can be encoded using VEX encoding, replace
  /// them by the VEX encoding in order to reduce size.
  bool CompressEvexToVexImpl(MachineInstr &MI) const;

  /// For initializing the hash map tables of all AVX-512 EVEX
  /// corresponding to AVX/AVX2 opcodes.
  void AddTableEntry(EvexToVexTableType &EvexToVexTable, uint16_t EvexOp,
                     uint16_t VexOp);

public:
  static char ID;

  EvexToVexInstPass() : MachineFunctionPass(ID) {
    initializeEvexToVexInstPassPass(*PassRegistry::getPassRegistry());

    // Initialize the EVEX to VEX 128 table map.
    for (X86EvexToVexCompressTableEntry Entry : X86EvexToVex128CompressTable) {
      AddTableEntry(EvexToVex128Table, Entry.EvexOpcode, Entry.VexOpcode);
    }

    // Initialize the EVEX to VEX 256 table map.
    for (X86EvexToVexCompressTableEntry Entry : X86EvexToVex256CompressTable) {
      AddTableEntry(EvexToVex256Table, Entry.EvexOpcode, Entry.VexOpcode);
    }
  }

  StringRef getPassName() const override { return EVEX2VEX_DESC; }

  /// Loop over all of the basic blocks, replacing EVEX instructions
  /// by equivalent VEX instructions when possible for reducing code size.
  bool runOnMachineFunction(MachineFunction &MF) override;

  // This pass runs after regalloc and doesn't support VReg operands.
  MachineFunctionProperties getRequiredProperties() const override {
    return MachineFunctionProperties().set(
        MachineFunctionProperties::Property::NoVRegs);
  }

private:
  /// Machine instruction info used throughout the class.
  const X86InstrInfo *TII;
};

} // end anonymous namespace

char EvexToVexInstPass::ID = 0;

bool EvexToVexInstPass::runOnMachineFunction(MachineFunction &MF) {
  TII = MF.getSubtarget<X86Subtarget>().getInstrInfo();

  const X86Subtarget &ST = MF.getSubtarget<X86Subtarget>();
  if (!ST.hasAVX512())
    return false;

  bool Changed = false;

  /// Go over all basic blocks in function and replace
  /// EVEX encoded instrs by VEX encoding when possible.
  for (MachineBasicBlock &MBB : MF) {

    // Traverse the basic block.
    for (MachineInstr &MI : MBB)
      Changed |= CompressEvexToVexImpl(MI);
  }

  return Changed;
}

void EvexToVexInstPass::AddTableEntry(EvexToVexTableType &EvexToVexTable,
                                      uint16_t EvexOp, uint16_t VexOp) {
  EvexToVexTable[EvexOp] = VexOp;
}

// For EVEX instructions that can be encoded using VEX encoding
// replace them by the VEX encoding in order to reduce size.
bool EvexToVexInstPass::CompressEvexToVexImpl(MachineInstr &MI) const {
  // VEX format.
  // # of bytes: 0,2,3  1      1      0,1   0,1,2,4  0,1
  //  [Prefixes] [VEX]  OPCODE ModR/M [SIB] [DISP]  [IMM]
  //
  // EVEX format.
  //  # of bytes: 4    1      1      1      4       / 1         1
  //  [Prefixes]  EVEX Opcode ModR/M [SIB] [Disp32] / [Disp8*N] [Immediate]

  const MCInstrDesc &Desc = MI.getDesc();

  // Check for EVEX instructions only.
  if ((Desc.TSFlags & X86II::EncodingMask) != X86II::EVEX)
    return false;

  // Check for EVEX instructions with mask or broadcast as in these cases
  // the EVEX prefix is needed in order to carry this information
  // thus preventing the transformation to VEX encoding.
  if (Desc.TSFlags & (X86II::EVEX_K | X86II::EVEX_B))
    return false;

  // Check for non EVEX_V512 instrs only.
  // EVEX_V512 instr: bit EVEX_L2 = 1; bit VEX_L = 0.
  if ((Desc.TSFlags & X86II::EVEX_L2) && !(Desc.TSFlags & X86II::VEX_L))
    return false;

  // EVEX_V128 instr: bit EVEX_L2 = 0, bit VEX_L = 0.
  bool IsEVEX_V128 =
      (!(Desc.TSFlags & X86II::EVEX_L2) && !(Desc.TSFlags & X86II::VEX_L));

  // EVEX_V256 instr: bit EVEX_L2 = 0, bit VEX_L = 1.
  bool IsEVEX_V256 =
      (!(Desc.TSFlags & X86II::EVEX_L2) && (Desc.TSFlags & X86II::VEX_L));

  unsigned NewOpc = 0;

  // Check for EVEX_V256 instructions.
  if (IsEVEX_V256) {
    // Search for opcode in the EvexToVex256 table.
    auto It = EvexToVex256Table.find(MI.getOpcode());
    if (It != EvexToVex256Table.end())
      NewOpc = It->second;
  }
  // Check for EVEX_V128 or Scalar instructions.
  else if (IsEVEX_V128) {
    // Search for opcode in the EvexToVex128 table.
    auto It = EvexToVex128Table.find(MI.getOpcode());
    if (It != EvexToVex128Table.end())
      NewOpc = It->second;
  }

  if (!NewOpc)
    return false;

  auto isHiRegIdx = [](unsigned Reg) {
    // Check for XMM register with indexes between 16 - 31.
    if (Reg >= X86::XMM16 && Reg <= X86::XMM31)
      return true;

    // Check for YMM register with indexes between 16 - 31.
    if (Reg >= X86::YMM16 && Reg <= X86::YMM31)
      return true;

    return false;
  };

  // Check that operands are not ZMM regs or
  // XMM/YMM regs with hi indexes between 16 - 31.
  for (const MachineOperand &MO : MI.explicit_operands()) {
    if (!MO.isReg())
      continue;

    unsigned Reg = MO.getReg();

    assert (!(Reg >= X86::ZMM0 && Reg <= X86::ZMM31));

    if (isHiRegIdx(Reg))
      return false;
  }

  const MCInstrDesc &MCID = TII->get(NewOpc);
  MI.setDesc(MCID);
  MI.setAsmPrinterFlag(AC_EVEX_2_VEX);
  return true;
}

INITIALIZE_PASS(EvexToVexInstPass, EVEX2VEX_NAME, EVEX2VEX_DESC, false, false)

FunctionPass *llvm::createX86EvexToVexInsts() {
  return new EvexToVexInstPass();
}
<|endoftext|>


<commit_before>/**
 * Skeleton.cpp
 * Contributors:
 *      * Arthur Sonzogni (author)
 * Licence:
 *      * Public Domain
 */

#include "Skeleton.hpp"
#include <stdexcept>
#include <iostream>

#define GLM_FORCE_RADIANS
#include <glm/gtx/matrix_operation.hpp>
#include <glm/gtc/matrix_transform.hpp>

#define DEGTORAD 0.01745329251f

Skeleton::Skeleton(const std::string& filename)
{
    std::ifstream stream;
    stream.open(filename);

    if (not stream.is_open())
        throw std::invalid_argument(std::string("Can't open the file ") + filename);

    std::string line;
    std::stringstream sstream;
    while(std::getline(stream,line))
    {
        sstream << line << " ";
    }

    readHierarchy(sstream);
    readMotion(sstream);

    stream.close();
}

void Skeleton::readHierarchy(std::stringstream& stream)
{
    std::string hierarchy,root, name;
    stream >> hierarchy >> root >> name;

    bool valid = true;
    valid &= ( hierarchy == "HIERARCHY" );
    valid &= ( root == "ROOT" );
    valid &= bool(stream);

    if (not valid)
        throw std::runtime_error("Invalid BVH file");
    else
    {
        this->name = name;
        readSkeleton(stream);
    }
}
void Skeleton::readMotion(std::stringstream& stream)
{
    // this function assign frame and frameTime
    // it read also data with the function addFrameData
    // TODO
    static bool isDisplayed = false;
    if (not isDisplayed)
    {
        isDisplayed = true;
        std::cerr << std::endl << "Please implement the line " << __LINE__ << " file : " << __FILE__ << std::endl << std::endl;
    }
}

void SkeletonPart::readSkeleton(std::stringstream& stream)
{
    // This function reads the BVH file between two curly braces
    std::string line;
    std::string word;
    while(stream >> word)
    {
        // TODO
        static bool isDisplayed = false;
        if (not isDisplayed)
        {
            isDisplayed = true;
            std::cerr << std::endl << "Please implement the line " << __LINE__ << " file : " << __FILE__ << std::endl << std::endl;
        }

        if (word == "}")
        {
            return;
        }

    }
    throw std::runtime_error("Invalid BVH file");
}

void SkeletonPart::addChannel(const std::string& name)
{
         if ( name == "Xposition") { motionData.push_back(MotionData()); motionData.back().channel = TX; }
    else if ( name == "Yposition") { motionData.push_back(MotionData()); motionData.back().channel = TY; }
    else if ( name == "Zposition") { motionData.push_back(MotionData()); motionData.back().channel = TZ; }
    else if ( name == "Xrotation") { motionData.push_back(MotionData()); motionData.back().channel = RX; }
    else if ( name == "Yrotation") { motionData.push_back(MotionData()); motionData.back().channel = RY; }
    else if ( name == "Zrotation") { motionData.push_back(MotionData()); motionData.back().channel = RZ; }
    else throw std::invalid_argument("Invalid BVH file, cannot add the channel " + name);
}

void SkeletonPart::addFrameData(std::stringstream& data)
{
    // this function read data for every channel and addFrameData for every children
    static bool isDisplayed = false;
    if (not isDisplayed)
    {
        isDisplayed = true;
        std::cerr << std::endl << "Please implement the line " << __LINE__ << " file : " << __FILE__ << std::endl << std::endl;
    }
}

SkeletonPart::~SkeletonPart()
{
    for(auto child = children.begin(); child != children.end(); ++child)
    {
        delete *child;
    }
}

glm::mat4 SkeletonPart::applyTransformation(int frame, glm::mat4 transformation)
{
    // compute the new transformation
    glm::mat4 xRot(1.f),yRot(1.f),zRot(1.f);
    glm::vec3 tOffset(0.f);
    for(auto channel = motionData.begin(); channel != motionData.end(); ++channel)
    {
       //if (frame < channel -> data.size())
       switch(channel -> channel)
       {
           case TX : tOffset += channel -> data[frame] * glm::vec3(1.f,0.f,0.f); break;
           case TY : tOffset += channel -> data[frame] * glm::vec3(0.f,1.f,0.f); break;
           case TZ : tOffset += channel -> data[frame] * glm::vec3(0.f,0.f,1.f); break;
           case RX : xRot = glm::rotate(xRot, DEGTORAD * channel -> data[frame] , glm::vec3(1.f,0.f,0.f)); break;
           case RY : yRot = glm::rotate(yRot, DEGTORAD * channel -> data[frame] , glm::vec3(0.f,1.f,0.f)); break;
           case RZ : zRot = glm::rotate(zRot, DEGTORAD * channel -> data[frame] , glm::vec3(0.f,0.f,1.f)); break;
       }
    }

    transformation = transformation * glm::translate(glm::mat4(1.f),offset + tOffset);
    transformation = transformation * zRot * xRot * yRot;
    return transformation;
}

glm::mat4 SkeletonPart::applyRestTransformation(glm::mat4 transformation)
{
    return transformation * glm::translate(glm::mat4(1.f),offset);
}

void SkeletonPart::getWireframe(int frame, std::vector<glm::vec3>& output, glm::mat4 transformation, const glm::vec3& reference)
{
    transformation = applyTransformation(frame, transformation);
    glm::vec3 myPosition = glm::vec3( transformation * glm::vec4(0.f,0.f,0.f,1.f) );

    // add a line
    output.push_back(reference);
    output.push_back(myPosition);

    // add line on every children
    for(auto child = children.begin(); child != children.end(); ++child)
        (**child).getWireframe(frame,output,transformation,myPosition);
}

void Skeleton::getWireframe(int frame, std::vector<glm::vec3>& output)
{
    SkeletonPart::getWireframe(frame, output, glm::mat4(1.f), glm::vec3(0.f));
}

void SkeletonPart::getTransformation(int frame, std::vector<glm::mat4>& output, glm::mat4 transformation, glm::mat4 rest)
{
    transformation = applyTransformation(frame,transformation);
    rest = applyRestTransformation(rest);

    // TODO
    static bool isDisplayed = false;
    if (not isDisplayed)
    {
        isDisplayed = true;
        std::cerr << std::endl << "Please implement the line " << __LINE__ << " file : " << __FILE__ << std::endl << std::endl;
    }

    for(auto child = children.begin(); child != children.end(); ++child)
        (**child).getTransformation(frame,output,transformation,rest);
}

void Skeleton::getTransformation(int frame, std::vector<glm::mat4>& output)
{
    SkeletonPart::getTransformation(frame,output,glm::mat4(1.f),glm::mat4(1.0));
}

void SkeletonPart::getWeight(PointWeight& output, const glm::vec3& p, int& i, glm::mat4 transformation)
{
    // TODO
    static bool isDisplayed = false;
    if (not isDisplayed)
    {
        isDisplayed = true;
        std::cerr << std::endl << "Please implement the line " << __LINE__ << " file : " << __FILE__ << std::endl << std::endl;
    }
    float weight = 1.0;

    // TODO end
    output.insert(weight,i);

    ++i;
    for(auto child = children.begin(); child != children.end(); ++child)
        (**child).getWeight(output,p,i,transformation);
}

void Skeleton::getWeight(PointWeight& output, const glm::vec3& p)
{
    int i = 0;
    glm::mat4 transformation = applyRestTransformation(glm::mat4(1.f));

    for(auto child = children.begin(); child != children.end(); ++child)
        (**child).getWeight(output,p,i,transformation);
}

int Skeleton::getFrameMirror(float time)
{
    int frameMiroir = time / frameTime;
    frameMiroir = frameMiroir % ( 2 * frame );
    if (frameMiroir >= frame )
        frameMiroir = 2 * frame - frameMiroir - 1;
    return frameMiroir;
}

<commit_msg>correct transformation order<commit_after>/**
 * Skeleton.cpp
 * Contributors:
 *      * Arthur Sonzogni (author)
 * Licence:
 *      * Public Domain
 */

#include "Skeleton.hpp"
#include <stdexcept>
#include <iostream>

#define GLM_FORCE_RADIANS
#include <glm/gtx/matrix_operation.hpp>
#include <glm/gtc/matrix_transform.hpp>

#define DEGTORAD 0.01745329251f

Skeleton::Skeleton(const std::string& filename)
{
    std::ifstream stream;
    stream.open(filename);

    if (not stream.is_open())
        throw std::invalid_argument(std::string("Can't open the file ") + filename);

    std::string line;
    std::stringstream sstream;
    while(std::getline(stream,line))
    {
        sstream << line << " ";
    }

    readHierarchy(sstream);
    readMotion(sstream);

    stream.close();
}

void Skeleton::readHierarchy(std::stringstream& stream)
{
    std::string hierarchy,root, name;
    stream >> hierarchy >> root >> name;

    bool valid = true;
    valid &= ( hierarchy == "HIERARCHY" );
    valid &= ( root == "ROOT" );
    valid &= bool(stream);

    if (not valid)
        throw std::runtime_error("Invalid BVH file");
    else
    {
        this->name = name;
        readSkeleton(stream);
    }
}
void Skeleton::readMotion(std::stringstream& stream)
{
    // this function assign frame and frameTime
    // it read also data with the function addFrameData
    // TODO
    static bool isDisplayed = false;
    if (not isDisplayed)
    {
        isDisplayed = true;
        std::cerr << std::endl << "Please implement the line " << __LINE__ << " file : " << __FILE__ << std::endl << std::endl;
    }
}

void SkeletonPart::readSkeleton(std::stringstream& stream)
{
    // This function reads the BVH file between two curly braces
    std::string line;
    std::string word;
    while(stream >> word)
    {
        // TODO
        static bool isDisplayed = false;
        if (not isDisplayed)
        {
            isDisplayed = true;
            std::cerr << std::endl << "Please implement the line " << __LINE__ << " file : " << __FILE__ << std::endl << std::endl;
        }

        if (word == "}")
        {
            return;
        }

    }
    throw std::runtime_error("Invalid BVH file");
}

void SkeletonPart::addChannel(const std::string& name)
{
         if ( name == "Xposition") { motionData.push_back(MotionData()); motionData.back().channel = TX; }
    else if ( name == "Yposition") { motionData.push_back(MotionData()); motionData.back().channel = TY; }
    else if ( name == "Zposition") { motionData.push_back(MotionData()); motionData.back().channel = TZ; }
    else if ( name == "Xrotation") { motionData.push_back(MotionData()); motionData.back().channel = RX; }
    else if ( name == "Yrotation") { motionData.push_back(MotionData()); motionData.back().channel = RY; }
    else if ( name == "Zrotation") { motionData.push_back(MotionData()); motionData.back().channel = RZ; }
    else throw std::invalid_argument("Invalid BVH file, cannot add the channel " + name);
}

void SkeletonPart::addFrameData(std::stringstream& data)
{
    // this function read data for every channel and addFrameData for every children
    static bool isDisplayed = false;
    if (not isDisplayed)
    {
        isDisplayed = true;
        std::cerr << std::endl << "Please implement the line " << __LINE__ << " file : " << __FILE__ << std::endl << std::endl;
    }
}

SkeletonPart::~SkeletonPart()
{
    for(auto child = children.begin(); child != children.end(); ++child)
    {
        delete *child;
    }
}

glm::mat4 SkeletonPart::applyTransformation(int frame, glm::mat4 transformation)
{
    // compute the new transformation
    glm::mat4 xRot(1.f),yRot(1.f),zRot(1.f);
    glm::vec3 tOffset(0.f);
    for(auto channel = motionData.begin(); channel != motionData.end(); ++channel)
    {
       //if (frame < channel -> data.size())
       switch(channel -> channel)
       {
           case TX : tOffset += channel -> data[frame] * glm::vec3(1.f,0.f,0.f); break;
           case TY : tOffset += channel -> data[frame] * glm::vec3(0.f,1.f,0.f); break;
           case TZ : tOffset += channel -> data[frame] * glm::vec3(0.f,0.f,1.f); break;
           case RX : xRot = glm::rotate(xRot, DEGTORAD * channel -> data[frame] , glm::vec3(1.f,0.f,0.f)); break;
           case RY : yRot = glm::rotate(yRot, DEGTORAD * channel -> data[frame] , glm::vec3(0.f,1.f,0.f)); break;
           case RZ : zRot = glm::rotate(zRot, DEGTORAD * channel -> data[frame] , glm::vec3(0.f,0.f,1.f)); break;
       }
    }

    transformation = transformation * glm::translate(glm::mat4(1.f),offset + tOffset);
    transformation = transformation * xRot * yRot * zRot;
    return transformation;
}

glm::mat4 SkeletonPart::applyRestTransformation(glm::mat4 transformation)
{
    return transformation * glm::translate(glm::mat4(1.f),offset);
}

void SkeletonPart::getWireframe(int frame, std::vector<glm::vec3>& output, glm::mat4 transformation, const glm::vec3& reference)
{
    transformation = applyTransformation(frame, transformation);
    glm::vec3 myPosition = glm::vec3( transformation * glm::vec4(0.f,0.f,0.f,1.f) );

    // add a line
    output.push_back(reference);
    output.push_back(myPosition);

    // add line on every children
    for(auto child = children.begin(); child != children.end(); ++child)
        (**child).getWireframe(frame,output,transformation,myPosition);
}

void Skeleton::getWireframe(int frame, std::vector<glm::vec3>& output)
{
    SkeletonPart::getWireframe(frame, output, glm::mat4(1.f), glm::vec3(0.f));
}

void SkeletonPart::getTransformation(int frame, std::vector<glm::mat4>& output, glm::mat4 transformation, glm::mat4 rest)
{
    transformation = applyTransformation(frame,transformation);
    rest = applyRestTransformation(rest);

    // TODO
    static bool isDisplayed = false;
    if (not isDisplayed)
    {
        isDisplayed = true;
        std::cerr << std::endl << "Please implement the line " << __LINE__ << " file : " << __FILE__ << std::endl << std::endl;
    }

    for(auto child = children.begin(); child != children.end(); ++child)
        (**child).getTransformation(frame,output,transformation,rest);
}

void Skeleton::getTransformation(int frame, std::vector<glm::mat4>& output)
{
    SkeletonPart::getTransformation(frame,output,glm::mat4(1.f),glm::mat4(1.0));
}

void SkeletonPart::getWeight(PointWeight& output, const glm::vec3& p, int& i, glm::mat4 transformation)
{
    // TODO
    static bool isDisplayed = false;
    if (not isDisplayed)
    {
        isDisplayed = true;
        std::cerr << std::endl << "Please implement the line " << __LINE__ << " file : " << __FILE__ << std::endl << std::endl;
    }
    float weight = 1.0;

    // TODO end
    output.insert(weight,i);

    ++i;
    for(auto child = children.begin(); child != children.end(); ++child)
        (**child).getWeight(output,p,i,transformation);
}

void Skeleton::getWeight(PointWeight& output, const glm::vec3& p)
{
    int i = 0;
    glm::mat4 transformation = applyRestTransformation(glm::mat4(1.f));

    for(auto child = children.begin(); child != children.end(); ++child)
        (**child).getWeight(output,p,i,transformation);
}

int Skeleton::getFrameMirror(float time)
{
    int frameMiroir = time / frameTime;
    frameMiroir = frameMiroir % ( 2 * frame );
    if (frameMiroir >= frame )
        frameMiroir = 2 * frame - frameMiroir - 1;
    return frameMiroir;
}

<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// @brief line editor using readline
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014-2015 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Jan Steemann
/// @author Copyright 2014-2015, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "ReadlineShell.h"

#include "Basics/tri-strings.h"
#include "Utilities/Completer.h"
#include "Utilities/LineEditor.h"

#include <readline/readline.h>
#include <readline/history.h>
#include <v8.h>

using namespace std;
using namespace triagens;
using namespace arangodb;

// -----------------------------------------------------------------------------
// --SECTION--                                                 private functions
// -----------------------------------------------------------------------------

namespace {
  Completer* COMPLETER;
}

static char WordBreakCharacters[] = {
  ' ', '\t', '\n', '"', '\\', '\'', '`', '@',
  '<', '>', '=', ';', '|', '&', '{', '}', '(', ')',
  '\0'
};

static char* CompletionGenerator (char const* text, int state) {
  static size_t currentIndex;
  static vector<string> result;

  // compute the possible completion
  if (state == 0) {
    result = COMPLETER->alternatives(text);
    LineEditor::sortAlternatives(result);
  }

  if (currentIndex < result.size()) {
    return TRI_SystemDuplicateString(result[currentIndex++].c_str());
  }

  currentIndex = 0;
  result.clear();
  return nullptr;
}

static char** AttemptedCompletion (char const* text, int start, int end) {
  char** result = rl_completion_matches(text, CompletionGenerator);
  rl_attempted_completion_over = true;

  if (result != nullptr && result[0] != nullptr && result[1] == nullptr) {
    size_t n = strlen(result[0]);

    if (result[0][n - 1] == ')') {
      result[0][n - 1] = '\0';
    }
  }

#if RL_READLINE_VERSION >= 0x0500
  // issue #289
  rl_completion_suppress_append = 1;
#endif

  return result;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief callback function that readline calls periodically while waiting
/// for input and being idle
////////////////////////////////////////////////////////////////////////////////

static int ReadlineIdle () {
  auto instance = ReadlineShell::instance();

  if (instance != nullptr && instance->getLoopState() == 2) {
    rl_done = 1;
  }

  return 0;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief callback function that readline calls when the input is completed
////////////////////////////////////////////////////////////////////////////////

static void ReadlineInputCompleted (char* value) {
  // if we don't clear the prompt here, readline will display it instantly
  // the user pressed the return key. this is not desired because when we
  // wait for input afterwards, readline will display the prompt again
  rl_set_prompt("");

  auto instance = ReadlineShell::instance();

  if (instance != nullptr) {
    if (instance->getLoopState() == 2) {

      // CTRL-C received
      rl_done = 1;

      // replace current input with nothing
      rl_replace_line("", 0);

      instance->setLastInput("");
    }
    else if (value == nullptr) {
      rl_done = 1;
      rl_replace_line("", 0);
      instance->setLoopState(3);
      instance->setLastInput("");
    }
    else {
      instance->setLoopState(1);
      instance->setLastInput(value == 0 ? "" : value);
    }
  }

  if (value != nullptr) {
    // avoid memleak
    TRI_SystemFree(value);
  }
}

// -----------------------------------------------------------------------------
// --SECTION--                                               class ReadlineShell
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// --SECTION--                                                 private variables
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief (sole) instance of a ReadlineShell
////////////////////////////////////////////////////////////////////////////////

std::atomic<ReadlineShell*> ReadlineShell::_instance(nullptr);

// -----------------------------------------------------------------------------
// --SECTION--                                      constructors and destructors
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief constructs a new editor
////////////////////////////////////////////////////////////////////////////////

ReadlineShell::ReadlineShell (std::string const& history, Completer* completer)
  : ShellImplementation(history, completer),
    _loopState(0),
    _lastInput(),
    _lastInputWasEmpty(false) {

  COMPLETER = completer;

  rl_initialize();

  rl_attempted_completion_function = AttemptedCompletion;
  rl_completer_word_break_characters = WordBreakCharacters;

  // register ourselves
  TRI_ASSERT(_instance == nullptr);
  _instance = this;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief destructor
////////////////////////////////////////////////////////////////////////////////

ReadlineShell::~ReadlineShell () {
  // unregister ourselves
  _instance = nullptr;
}

// -----------------------------------------------------------------------------
// --SECTION--                                       ShellImplementation methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief handle a signal
////////////////////////////////////////////////////////////////////////////////

void ReadlineShell::signal () {
  // set the global state, so the readline input loop can react on it
  setLoopState(2);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief line editor open
////////////////////////////////////////////////////////////////////////////////

bool ReadlineShell::open (bool autoComplete) {
  if (autoComplete) {

    // issue #289: do not append a space after completion
    rl_completion_append_character = '\0';

    // works only in Readline 4.2+
#if RL_READLINE_VERSION >= 0x0500
    // enable this to turn on the visual bell - evil!
    // rl_variable_bind("prefer-visible-bell", "1");

    // use this for single-line editing as in mongodb shell
    // rl_variable_bind("horizontal-scroll-mode", "1");

    // show matching parentheses
    rl_set_paren_blink_timeout(1 * 1000 * 1000);
    rl_variable_bind("blink-matching-paren", "1");

    // show selection list when completion is ambiguous. not setting this
    // variable will turn the selection list off at least on Ubuntu
    rl_variable_bind("show-all-if-ambiguous", "1");

    // use readline's built-in page-wise completer
    rl_variable_bind("page-completions", "1");
#endif

    rl_bind_key('\t', rl_complete);
  }

  using_history();
  //stifle_history(MAX_HISTORY_ENTRIES);
  stifle_history(1000);

  _state = STATE_OPENED;
  return read_history(historyPath().c_str()) == 0;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief line editor shutdown
////////////////////////////////////////////////////////////////////////////////

bool ReadlineShell::close () {
  if (_state != STATE_OPENED) {
    // avoid duplicate saving of history
    return true;
  }

  _state = STATE_CLOSED;

  bool res = writeHistory();

  clear_history();

  HIST_ENTRY** hist = history_list();

  if (hist != nullptr) {
    TRI_SystemFree(hist);
  }

  return res;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief get the history file path
////////////////////////////////////////////////////////////////////////////////

string ReadlineShell::historyPath () {
  string path;

  if (getenv("HOME")) {
    path.append(getenv("HOME"));
    path += '/';
  }

  path.append(_historyFilename);

  return path;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief add to history
////////////////////////////////////////////////////////////////////////////////

void ReadlineShell::addHistory (const string& str) {
  if (str.empty()) {
    return;
  }

  history_set_pos(history_length - 1);

  if (current_history()) {
    do {
      if (strcmp(current_history()->line, str.c_str()) == 0) {
        HIST_ENTRY* e = remove_history(where_history());

        if (e != nullptr) {
          free_history_entry(e);
        }

        break;
      }
    }
    while (previous_history());
  }

  add_history(str.c_str());
}

////////////////////////////////////////////////////////////////////////////////
/// @brief save history
////////////////////////////////////////////////////////////////////////////////

bool ReadlineShell::writeHistory () {
  return (write_history(historyPath().c_str()) == 0);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief read a line from the input
////////////////////////////////////////////////////////////////////////////////

string ReadlineShell::getLine (const string& prompt, bool& eof) {
  setLoopState(0);

  rl_event_hook = ReadlineIdle;
  rl_callback_handler_install(prompt.c_str(), ReadlineInputCompleted);

  int state;

  eof = false;

  do {
    rl_callback_read_char();
    state = getLoopState();
  }
  while (state == 0);

  rl_callback_handler_remove();

  if (state == 2) {
    setLastInput("");

    if (_lastInputWasEmpty) {
      eof = true;
    }
    else {
      _lastInputWasEmpty = true;
    }
  }
  else if (state == 3) {
    setLastInput("");
    eof = true;
    _lastInputWasEmpty = false;
  }
  else {
    _lastInputWasEmpty = false;
  }

  return _lastInput;
}

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------
<commit_msg>less pause for matching parens (helps when copy & pasting code into the shell)<commit_after>////////////////////////////////////////////////////////////////////////////////
/// @brief line editor using readline
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014-2015 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Jan Steemann
/// @author Copyright 2014-2015, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "ReadlineShell.h"

#include "Basics/tri-strings.h"
#include "Utilities/Completer.h"
#include "Utilities/LineEditor.h"

#include <readline/readline.h>
#include <readline/history.h>
#include <v8.h>

using namespace std;
using namespace triagens;
using namespace arangodb;

// -----------------------------------------------------------------------------
// --SECTION--                                                 private functions
// -----------------------------------------------------------------------------

namespace {
  Completer* COMPLETER;
}

static char WordBreakCharacters[] = {
  ' ', '\t', '\n', '"', '\\', '\'', '`', '@',
  '<', '>', '=', ';', '|', '&', '{', '}', '(', ')',
  '\0'
};

static char* CompletionGenerator (char const* text, int state) {
  static size_t currentIndex;
  static vector<string> result;

  // compute the possible completion
  if (state == 0) {
    result = COMPLETER->alternatives(text);
    LineEditor::sortAlternatives(result);
  }

  if (currentIndex < result.size()) {
    return TRI_SystemDuplicateString(result[currentIndex++].c_str());
  }

  currentIndex = 0;
  result.clear();
  return nullptr;
}

static char** AttemptedCompletion (char const* text, int start, int end) {
  char** result = rl_completion_matches(text, CompletionGenerator);
  rl_attempted_completion_over = true;

  if (result != nullptr && result[0] != nullptr && result[1] == nullptr) {
    size_t n = strlen(result[0]);

    if (result[0][n - 1] == ')') {
      result[0][n - 1] = '\0';
    }
  }

#if RL_READLINE_VERSION >= 0x0500
  // issue #289
  rl_completion_suppress_append = 1;
#endif

  return result;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief callback function that readline calls periodically while waiting
/// for input and being idle
////////////////////////////////////////////////////////////////////////////////

static int ReadlineIdle () {
  auto instance = ReadlineShell::instance();

  if (instance != nullptr && instance->getLoopState() == 2) {
    rl_done = 1;
  }

  return 0;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief callback function that readline calls when the input is completed
////////////////////////////////////////////////////////////////////////////////

static void ReadlineInputCompleted (char* value) {
  // if we don't clear the prompt here, readline will display it instantly
  // the user pressed the return key. this is not desired because when we
  // wait for input afterwards, readline will display the prompt again
  rl_set_prompt("");

  auto instance = ReadlineShell::instance();

  if (instance != nullptr) {
    if (instance->getLoopState() == 2) {

      // CTRL-C received
      rl_done = 1;

      // replace current input with nothing
      rl_replace_line("", 0);

      instance->setLastInput("");
    }
    else if (value == nullptr) {
      rl_done = 1;
      rl_replace_line("", 0);
      instance->setLoopState(3);
      instance->setLastInput("");
    }
    else {
      instance->setLoopState(1);
      instance->setLastInput(value == 0 ? "" : value);
    }
  }

  if (value != nullptr) {
    // avoid memleak
    TRI_SystemFree(value);
  }
}

// -----------------------------------------------------------------------------
// --SECTION--                                               class ReadlineShell
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// --SECTION--                                                 private variables
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief (sole) instance of a ReadlineShell
////////////////////////////////////////////////////////////////////////////////

std::atomic<ReadlineShell*> ReadlineShell::_instance(nullptr);

// -----------------------------------------------------------------------------
// --SECTION--                                      constructors and destructors
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief constructs a new editor
////////////////////////////////////////////////////////////////////////////////

ReadlineShell::ReadlineShell (std::string const& history, Completer* completer)
  : ShellImplementation(history, completer),
    _loopState(0),
    _lastInput(),
    _lastInputWasEmpty(false) {

  COMPLETER = completer;

  rl_initialize();

  rl_attempted_completion_function = AttemptedCompletion;
  rl_completer_word_break_characters = WordBreakCharacters;

  // register ourselves
  TRI_ASSERT(_instance == nullptr);
  _instance = this;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief destructor
////////////////////////////////////////////////////////////////////////////////

ReadlineShell::~ReadlineShell () {
  // unregister ourselves
  _instance = nullptr;
}

// -----------------------------------------------------------------------------
// --SECTION--                                       ShellImplementation methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief handle a signal
////////////////////////////////////////////////////////////////////////////////

void ReadlineShell::signal () {
  // set the global state, so the readline input loop can react on it
  setLoopState(2);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief line editor open
////////////////////////////////////////////////////////////////////////////////

bool ReadlineShell::open (bool autoComplete) {
  if (autoComplete) {

    // issue #289: do not append a space after completion
    rl_completion_append_character = '\0';

    // works only in Readline 4.2+
#if RL_READLINE_VERSION >= 0x0500
    // enable this to turn on the visual bell - evil!
    // rl_variable_bind("prefer-visible-bell", "1");

    // use this for single-line editing as in mongodb shell
    // rl_variable_bind("horizontal-scroll-mode", "1");

    // show matching parentheses
    rl_set_paren_blink_timeout(300 * 1000);
    rl_variable_bind("blink-matching-paren", "1");

    // show selection list when completion is ambiguous. not setting this
    // variable will turn the selection list off at least on Ubuntu
    rl_variable_bind("show-all-if-ambiguous", "1");

    // use readline's built-in page-wise completer
    rl_variable_bind("page-completions", "1");
#endif

    rl_bind_key('\t', rl_complete);
  }

  using_history();
  //stifle_history(MAX_HISTORY_ENTRIES);
  stifle_history(1000);

  _state = STATE_OPENED;
  return read_history(historyPath().c_str()) == 0;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief line editor shutdown
////////////////////////////////////////////////////////////////////////////////

bool ReadlineShell::close () {
  if (_state != STATE_OPENED) {
    // avoid duplicate saving of history
    return true;
  }

  _state = STATE_CLOSED;

  bool res = writeHistory();

  clear_history();

  HIST_ENTRY** hist = history_list();

  if (hist != nullptr) {
    TRI_SystemFree(hist);
  }

  return res;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief get the history file path
////////////////////////////////////////////////////////////////////////////////

string ReadlineShell::historyPath () {
  string path;

  if (getenv("HOME")) {
    path.append(getenv("HOME"));
    path += '/';
  }

  path.append(_historyFilename);

  return path;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief add to history
////////////////////////////////////////////////////////////////////////////////

void ReadlineShell::addHistory (const string& str) {
  if (str.empty()) {
    return;
  }

  history_set_pos(history_length - 1);

  if (current_history()) {
    do {
      if (strcmp(current_history()->line, str.c_str()) == 0) {
        HIST_ENTRY* e = remove_history(where_history());

        if (e != nullptr) {
          free_history_entry(e);
        }

        break;
      }
    }
    while (previous_history());
  }

  add_history(str.c_str());
}

////////////////////////////////////////////////////////////////////////////////
/// @brief save history
////////////////////////////////////////////////////////////////////////////////

bool ReadlineShell::writeHistory () {
  return (write_history(historyPath().c_str()) == 0);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief read a line from the input
////////////////////////////////////////////////////////////////////////////////

string ReadlineShell::getLine (const string& prompt, bool& eof) {
  setLoopState(0);

  rl_event_hook = ReadlineIdle;
  rl_callback_handler_install(prompt.c_str(), ReadlineInputCompleted);

  int state;

  eof = false;

  do {
    rl_callback_read_char();
    state = getLoopState();
  }
  while (state == 0);

  rl_callback_handler_remove();

  if (state == 2) {
    setLastInput("");

    if (_lastInputWasEmpty) {
      eof = true;
    }
    else {
      _lastInputWasEmpty = true;
    }
  }
  else if (state == 3) {
    setLastInput("");
    eof = true;
    _lastInputWasEmpty = false;
  }
  else {
    _lastInputWasEmpty = false;
  }

  return _lastInput;
}

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------
<|endoftext|>


<commit_before>/*
  Copyright (c) <2013-2014>, <BenHJ>
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.
  3. Neither the name of the copyright holder nor the names of its contributors
  may be used to endorse or promote products derived from this software without
  specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

// an implementation of XTEA

#include "teasafe/detail/DetailTeaSafe.hpp"

#include "cipher/sha2.hpp"
#include "cipher/XTEAByteTransformer.hpp"

#include <boost/progress.hpp>

#include <vector>

namespace teasafe { namespace cipher
{

    namespace detail
    {
        // the xtea encipher algorithm as found on wikipedia. Use this to encrypt
        // a sequence of numbers. The original plain-text is then xor-ed with this
        // sequence
        void encipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4])
        {
            unsigned int i;
            uint32_t v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9;
            for (i=0; i < num_rounds; i++) {
                v0 += ((v1 << 4 ^ v1 >> 5) + v1) ^(sum + key[sum & 3]);
                sum += delta;
                v1 += ((v0 << 4 ^ v0 >> 5) + v0) ^(sum + key[(sum>>11) & 3]);
            }
            v[0]=v0; v[1]=v1;
        }

        // helper code found here:
        // http://codereview.stackexchange.com/questions/2050/codereview-tiny-encryption-algorithm-for-arbitrary-sized-data
        void convertBytesAndEncipher(unsigned int num_rounds, unsigned char * buffer, uint32_t const key[4])
        {
            uint32_t datablock[2];

            datablock[0] = (buffer[0] << 24) | (buffer[1] << 16)  | (buffer[2] << 8) | (buffer[3]);
            datablock[1] = (buffer[4] << 24) | (buffer[5] << 16)  | (buffer[6] << 8) | (buffer[7]);

            encipher(num_rounds, datablock, key);

            buffer[0] = static_cast<unsigned char>((datablock[0] >> 24) & 0xFF);
            buffer[1] = static_cast<unsigned char>((datablock[0] >> 16) & 0xFF);
            buffer[2] = static_cast<unsigned char>((datablock[0] >> 8) & 0xFF);
            buffer[3] = static_cast<unsigned char>((datablock[0]) & 0xFF);
            buffer[4] = static_cast<unsigned char>((datablock[1] >> 24) & 0xFF);
            buffer[5] = static_cast<unsigned char>((datablock[1] >> 16) & 0xFF);
            buffer[6] = static_cast<unsigned char>((datablock[1] >> 8) & 0xFF);
            buffer[7] = static_cast<unsigned char>((datablock[1]) & 0xFF);
        }
    }

    // prob a bad idea all these static vars; still for the sake of optimizing.. :-)
    static bool g_init = false;

    // used for holding the hash-generated key
    static uint32_t g_key[4];

    // used to optimize crypto process. This will store
    // the first 256MB of cipher stream
    static std::vector<char> g_bigCipherBuffer;

    // the size of the cipher buffer (prefer a #define rather than a const
    // for minimal memory footprint and minimal time required to instantiate).
#define CIPHER_BUFFER_SIZE 270000000

    XTEAByteTransformer::XTEAByteTransformer(std::string const &password,
                                             uint64_t const iv,
                                             unsigned int const rounds)
        : IByteTransformer()
        , m_iv(iv)
        , m_rounds(rounds) // note, the suggested xtea rounds is 64 in the literature
    {
        // is this key-gen secure? probably not...use at own risk
        // initialize the key by taking a hash of the password and then creating
        // a uint32_t array out of it
        if (!g_init) {
            unsigned char temp[32];
            ::sha256((unsigned char*)password.c_str(), password.size(), temp);
            int c = 0;
            for (int i = 0; i < 16; i += 4) {
                unsigned char buf[4];
                buf[0] = temp[i];
                buf[1] = temp[i + 1];
                buf[2] = temp[i + 2];
                buf[3] = temp[i + 3];
                g_key[c] = (buf[0] << 24) | (buf[1] << 16)  | (buf[2] << 8) | (buf[3]);
                ++c;
            }
            buildBigCipherBuffer();
            g_init = true;
        }

    }

    XTEAByteTransformer::~XTEAByteTransformer()
    {
    }

    void
    XTEAByteTransformer::buildBigCipherBuffer()
    {
        std::cout<<"Building big xtea cipher stream buffer. Please wait..."<<std::endl;
        std::vector<char> in;
        in.resize(CIPHER_BUFFER_SIZE);
        g_bigCipherBuffer.resize(CIPHER_BUFFER_SIZE);
        uint64_t div = CIPHER_BUFFER_SIZE / 100000;
        boost::progress_display pd(div);
        for(uint64_t i = 0;i<div;++i) {
            doTransform((&in.front()) + (i * 100000), (&g_bigCipherBuffer.front()) + (i*100000), 0, 100000);
            ++pd;
        }
        std::cout<<"\nBuilt big xtea cipher stream buffer.\n"<<std::endl;
    }

    void
    XTEAByteTransformer::doTransform(char *in, char *out, std::ios_base::streamoff startPosition, long length) const
    {
        // big cipher buffer has been initialized
        if (g_init) {
            // prefer to use cipher buffer
            if ((startPosition + length) < CIPHER_BUFFER_SIZE) {
                for (long j = 0; j < length; ++j) {
                    out[j] = in[j] ^ g_bigCipherBuffer[j + startPosition];
                }
                return;
            }
        }

        // how many blocks required? defaults to 1, if length greater
        // than 8 bytes then more blocks are needed
        long blocksRequired = 0;

        std::ios_base::streamoff const startPositionOffset = startPosition % 8;

        // the counter used to determine where we start in the cipher stream
        uint64_t startRD = (startPosition - startPositionOffset);
        uint64_t ctr = (startRD / 8) + m_iv;

        // encipher the initial 64 bit counter.
        UIntVector buf;
        buf.resize(8);
        cypherBytes(ctr, buf);

        // c is a counter used to store which byte is currently being encrypted
        long c = 0;

        // if the length is > 8, we need to encrypt in multiples of 8
        if (length > 8) {

            // compute how many blocks of size 8 bytes will be encrypted
            long remainder = length % 8;
            long roundedDown = length - remainder;
            blocksRequired += (roundedDown / 8);

            // encrypt blocksRequired times 8 byte blocks of data
            doSubTransformations(in,                         // input buffer
                                 out,                        // output buffer
                                 startPosition,              // seeked-to position
                                 startPositionOffset,        // 8-byte block offset
                                 blocksRequired,             // number of iterations
                                 c,                          // stream position
                                 ctr,                        // the CTR counter
                                 buf);                       // the cipher text buffer

            // encrypt the final block which is of length remainder bytes
            if (remainder > 0) {
                doSubTransformations(in, out, startPosition, startPositionOffset, 1, c, ctr, buf, remainder);
            }

            return;
        }

        // else the length < 8 so just encrypt length bytes
        doSubTransformations(in, out, startPosition, startPositionOffset, 1, c, ctr, buf, length);

    }

    void
    XTEAByteTransformer::doXOR(char *in,
                               char *out,
                               std::ios_base::streamoff const startPositionOffset,
                               long &c,
                               uint64_t &ctr,
                               int const bytesToEncrypt,
                               UIntVector &buf) const
    {
        // now xor plain with key stream
        int k = 0;
        for (int j = startPositionOffset; j < bytesToEncrypt + startPositionOffset; ++j) {
            if (j >= 8) {

                // iterate cipher counter and update cipher buffer
                if(j == 8) { cypherBytes(ctr, buf); }

                out[c] = in[c] ^ buf[k];
                ++k;

            } else { out[c] = in[c] ^ buf[j]; }
            ++c;
        }
    }

    void
    XTEAByteTransformer::cypherBytes(uint64_t &ctr, UIntVector &buf) const
    {
        teasafe::detail::convertUInt64ToInt8Array(ctr, &buf.front());
        detail::convertBytesAndEncipher(m_rounds, &buf.front(), g_key);
        ++ctr;
    }

    void
    XTEAByteTransformer::doSubTransformations(char *in,
                                              char *out,
                                              std::ios_base::streamoff const startPosition,
                                              std::ios_base::streamoff const startPositionOffset,
                                              long const blocksOfSize8BeingTransformed,
                                              long &c,
                                              uint64_t &ctr,
                                              UIntVector &buf,
                                              int const bytesToEncrypt) const
    {
        // transform  blocks
        for (long i = 0; i < blocksOfSize8BeingTransformed; ++i) {

            // now XOR plain with key stream.
            this->doXOR(in, out, startPositionOffset, c, ctr, bytesToEncrypt, buf);

            // cipher buffer needs updating if the start position is 0 in which
            // case it won't have been updated by the XOR loop
            if(startPositionOffset == 0) { cypherBytes(ctr, buf); }
        }
    }
}
}
<commit_msg>Updated comment regarding key-derivation<commit_after>/*
  Copyright (c) <2013-2014>, <BenHJ>
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.
  3. Neither the name of the copyright holder nor the names of its contributors
  may be used to endorse or promote products derived from this software without
  specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

// an implementation of XTEA

#include "teasafe/detail/DetailTeaSafe.hpp"

#include "cipher/sha2.hpp"
#include "cipher/XTEAByteTransformer.hpp"

#include <boost/progress.hpp>

#include <vector>

namespace teasafe { namespace cipher
{

    namespace detail
    {
        // the xtea encipher algorithm as found on wikipedia. Use this to encrypt
        // a sequence of numbers. The original plain-text is then xor-ed with this
        // sequence
        void encipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4])
        {
            unsigned int i;
            uint32_t v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9;
            for (i=0; i < num_rounds; i++) {
                v0 += ((v1 << 4 ^ v1 >> 5) + v1) ^(sum + key[sum & 3]);
                sum += delta;
                v1 += ((v0 << 4 ^ v0 >> 5) + v0) ^(sum + key[(sum>>11) & 3]);
            }
            v[0]=v0; v[1]=v1;
        }

        // helper code found here:
        // http://codereview.stackexchange.com/questions/2050/codereview-tiny-encryption-algorithm-for-arbitrary-sized-data
        void convertBytesAndEncipher(unsigned int num_rounds, unsigned char * buffer, uint32_t const key[4])
        {
            uint32_t datablock[2];

            datablock[0] = (buffer[0] << 24) | (buffer[1] << 16)  | (buffer[2] << 8) | (buffer[3]);
            datablock[1] = (buffer[4] << 24) | (buffer[5] << 16)  | (buffer[6] << 8) | (buffer[7]);

            encipher(num_rounds, datablock, key);

            buffer[0] = static_cast<unsigned char>((datablock[0] >> 24) & 0xFF);
            buffer[1] = static_cast<unsigned char>((datablock[0] >> 16) & 0xFF);
            buffer[2] = static_cast<unsigned char>((datablock[0] >> 8) & 0xFF);
            buffer[3] = static_cast<unsigned char>((datablock[0]) & 0xFF);
            buffer[4] = static_cast<unsigned char>((datablock[1] >> 24) & 0xFF);
            buffer[5] = static_cast<unsigned char>((datablock[1] >> 16) & 0xFF);
            buffer[6] = static_cast<unsigned char>((datablock[1] >> 8) & 0xFF);
            buffer[7] = static_cast<unsigned char>((datablock[1]) & 0xFF);
        }
    }

    // prob a bad idea all these static vars; still for the sake of optimizing.. :-)
    static bool g_init = false;

    // used for holding the hash-generated key
    static uint32_t g_key[4];

    // used to optimize crypto process. This will store
    // the first 256MB of cipher stream
    static std::vector<char> g_bigCipherBuffer;

    // the size of the cipher buffer (prefer a #define rather than a const
    // for minimal memory footprint and minimal time required to instantiate).
#define CIPHER_BUFFER_SIZE 270000000

    XTEAByteTransformer::XTEAByteTransformer(std::string const &password,
                                             uint64_t const iv,
                                             unsigned int const rounds)
        : IByteTransformer()
        , m_iv(iv)
        , m_rounds(rounds) // note, the suggested xtea rounds is 64 in the literature
    {
        //
        // The following key generation algorithm is very naive. It simply generates
        // a sha256 hash and uses that as the basis for the key
        // NOTE: NOT VERY SECURE given the key derivation's susceptibility to brute-force
        // attacks. A stronger algorithm like scrypt is suggested (todo).
        //
        if (!g_init) {
            unsigned char temp[32];
            ::sha256((unsigned char*)password.c_str(), password.size(), temp);
            int c = 0;
            for (int i = 0; i < 16; i += 4) {
                unsigned char buf[4];
                buf[0] = temp[i];
                buf[1] = temp[i + 1];
                buf[2] = temp[i + 2];
                buf[3] = temp[i + 3];
                g_key[c] = (buf[0] << 24) | (buf[1] << 16)  | (buf[2] << 8) | (buf[3]);
                ++c;
            }
            buildBigCipherBuffer();
            g_init = true;
        }

    }

    XTEAByteTransformer::~XTEAByteTransformer()
    {
    }

    void
    XTEAByteTransformer::buildBigCipherBuffer()
    {
        std::cout<<"Building big xtea cipher stream buffer. Please wait..."<<std::endl;
        std::vector<char> in;
        in.resize(CIPHER_BUFFER_SIZE);
        g_bigCipherBuffer.resize(CIPHER_BUFFER_SIZE);
        uint64_t div = CIPHER_BUFFER_SIZE / 100000;
        boost::progress_display pd(div);
        for(uint64_t i = 0;i<div;++i) {
            doTransform((&in.front()) + (i * 100000), (&g_bigCipherBuffer.front()) + (i*100000), 0, 100000);
            ++pd;
        }
        std::cout<<"\nBuilt big xtea cipher stream buffer.\n"<<std::endl;
    }

    void
    XTEAByteTransformer::doTransform(char *in, char *out, std::ios_base::streamoff startPosition, long length) const
    {
        // big cipher buffer has been initialized
        if (g_init) {
            // prefer to use cipher buffer
            if ((startPosition + length) < CIPHER_BUFFER_SIZE) {
                for (long j = 0; j < length; ++j) {
                    out[j] = in[j] ^ g_bigCipherBuffer[j + startPosition];
                }
                return;
            }
        }

        // how many blocks required? defaults to 1, if length greater
        // than 8 bytes then more blocks are needed
        long blocksRequired = 0;

        std::ios_base::streamoff const startPositionOffset = startPosition % 8;

        // the counter used to determine where we start in the cipher stream
        uint64_t startRD = (startPosition - startPositionOffset);
        uint64_t ctr = (startRD / 8) + m_iv;

        // encipher the initial 64 bit counter.
        UIntVector buf;
        buf.resize(8);
        cypherBytes(ctr, buf);

        // c is a counter used to store which byte is currently being encrypted
        long c = 0;

        // if the length is > 8, we need to encrypt in multiples of 8
        if (length > 8) {

            // compute how many blocks of size 8 bytes will be encrypted
            long remainder = length % 8;
            long roundedDown = length - remainder;
            blocksRequired += (roundedDown / 8);

            // encrypt blocksRequired times 8 byte blocks of data
            doSubTransformations(in,                         // input buffer
                                 out,                        // output buffer
                                 startPosition,              // seeked-to position
                                 startPositionOffset,        // 8-byte block offset
                                 blocksRequired,             // number of iterations
                                 c,                          // stream position
                                 ctr,                        // the CTR counter
                                 buf);                       // the cipher text buffer

            // encrypt the final block which is of length remainder bytes
            if (remainder > 0) {
                doSubTransformations(in, out, startPosition, startPositionOffset, 1, c, ctr, buf, remainder);
            }

            return;
        }

        // else the length < 8 so just encrypt length bytes
        doSubTransformations(in, out, startPosition, startPositionOffset, 1, c, ctr, buf, length);

    }

    void
    XTEAByteTransformer::doXOR(char *in,
                               char *out,
                               std::ios_base::streamoff const startPositionOffset,
                               long &c,
                               uint64_t &ctr,
                               int const bytesToEncrypt,
                               UIntVector &buf) const
    {
        // now xor plain with key stream
        int k = 0;
        for (int j = startPositionOffset; j < bytesToEncrypt + startPositionOffset; ++j) {
            if (j >= 8) {

                // iterate cipher counter and update cipher buffer
                if(j == 8) { cypherBytes(ctr, buf); }

                out[c] = in[c] ^ buf[k];
                ++k;

            } else { out[c] = in[c] ^ buf[j]; }
            ++c;
        }
    }

    void
    XTEAByteTransformer::cypherBytes(uint64_t &ctr, UIntVector &buf) const
    {
        teasafe::detail::convertUInt64ToInt8Array(ctr, &buf.front());
        detail::convertBytesAndEncipher(m_rounds, &buf.front(), g_key);
        ++ctr;
    }

    void
    XTEAByteTransformer::doSubTransformations(char *in,
                                              char *out,
                                              std::ios_base::streamoff const startPosition,
                                              std::ios_base::streamoff const startPositionOffset,
                                              long const blocksOfSize8BeingTransformed,
                                              long &c,
                                              uint64_t &ctr,
                                              UIntVector &buf,
                                              int const bytesToEncrypt) const
    {
        // transform  blocks
        for (long i = 0; i < blocksOfSize8BeingTransformed; ++i) {

            // now XOR plain with key stream.
            this->doXOR(in, out, startPositionOffset, c, ctr, bytesToEncrypt, buf);

            // cipher buffer needs updating if the start position is 0 in which
            // case it won't have been updated by the XOR loop
            if(startPositionOffset == 0) { cypherBytes(ctr, buf); }
        }
    }
}
}
<|endoftext|>


<commit_before>//===-- ValueSymbolTable.cpp - Implement the ValueSymbolTable class -------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and revised by Reid
// Spencer. It is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the ValueSymbolTable class for the VMCore library.
//
//===----------------------------------------------------------------------===//

#include "llvm/GlobalValue.h"
#include "llvm/Type.h"
#include "llvm/ValueSymbolTable.h"
#include "llvm/ADT/StringExtras.h"
#include <algorithm>
#include <iostream>

using namespace llvm;

#define DEBUG_SYMBOL_TABLE 0
#define DEBUG_ABSTYPE 0

// Class destructor
ValueSymbolTable::~ValueSymbolTable() {
#ifndef NDEBUG   // Only do this in -g mode...
  bool LeftoverValues = true;
  for (iterator VI = vmap.begin(), VE = vmap.end(); VI != VE; ++VI)
    if (!isa<Constant>(VI->second) ) {
      std::cerr << "Value still in symbol table! Type = '"
                << VI->second->getType()->getDescription() << "' Name = '"
                << VI->first << "'\n";
      LeftoverValues = false;
    }
  assert(LeftoverValues && "Values remain in symbol table!");
#endif
}

// getUniqueName - Given a base name, return a string that is either equal to
// it (or derived from it) that does not already occur in the symbol table for
// the specified type.
//
std::string ValueSymbolTable::getUniqueName(const std::string &BaseName) const {
  std::string TryName = BaseName;
  const_iterator End = vmap.end();

  // See if the name exists
  while (vmap.find(TryName) != End)            // Loop until we find a free
    TryName = BaseName + utostr(++LastUnique); // name in the symbol table
  return TryName;
}

// lookup a value - Returns null on failure...
//
Value *ValueSymbolTable::lookup(const std::string &Name) const {
  const_iterator VI = vmap.find(Name);
  if (VI != vmap.end())                   // We found the symbol
    return const_cast<Value*>(VI->second);
  return 0;
}

// Strip the symbol table of its names.
//
bool ValueSymbolTable::strip() {
  bool RemovedSymbol = false;
  for (iterator VI = vmap.begin(), VE = vmap.end(); VI != VE; ) {
    Value *V = VI->second;
    ++VI;
    if (!isa<GlobalValue>(V) || cast<GlobalValue>(V)->hasInternalLinkage()) {
      // Set name to "", removing from symbol table!
      V->setName("");
      RemovedSymbol = true;
    }
  }
  return RemovedSymbol;
}

// Insert a value into the symbol table with the specified name...
//
void ValueSymbolTable::insert(Value* V) {
  assert(V && "Can't insert null Value into symbol table!");
  assert(V->hasName() && "Can't insert nameless Value into symbol table");

  // Check to see if there is a naming conflict.  If so, rename this type!
  std::string UniqueName = getUniqueName(V->getName());

#if DEBUG_SYMBOL_TABLE
  dump();
  std::cerr << " Inserting value: " << UniqueName << ": " << V->dump() << "\n";
#endif

  // Insert the vmap entry
  vmap.insert(make_pair(UniqueName, V));
}

// Remove a value
bool ValueSymbolTable::erase(Value *V) {
  assert(V->hasName() && "Value doesn't have name!");
  iterator Entry = vmap.find(V->getName());
  if (Entry == vmap.end())
    return false;

#if DEBUG_SYMBOL_TABLE
  dump();
  std::cerr << " Removing Value: " << Entry->second->getName() << "\n";
#endif

  // Remove the value from the plane...
  vmap.erase(Entry);
  return true;
}

// rename - Given a value with a non-empty name, remove its existing entry
// from the symbol table and insert a new one for Name.  This is equivalent to
// doing "remove(V), V->Name = Name, insert(V)",
//
bool ValueSymbolTable::rename(Value *V, const std::string &name) {
  assert(V && "Can't rename a null Value");
  assert(V->hasName() && "Can't rename a nameless Value");
  assert(!V->getName().empty() && "Can't rename an Value with null name");
  assert(V->getName() != name && "Can't rename a Value with same name");
  assert(!name.empty() && "Can't rename a named Value with a null name");

  // Find the name
  iterator VI = vmap.find(V->getName());

  // If we didn't find it, we're done
  if (VI == vmap.end())
    return false;

  // Remove the old entry.
  vmap.erase(VI);

  // See if we can insert the new name.
  VI = vmap.lower_bound(name);

  // Is there a naming conflict?
  if (VI != vmap.end() && VI->first == name) {
    V->Name = getUniqueName( name);
    vmap.insert(make_pair(V->Name, V));
  } else {
    V->Name = name;
    vmap.insert(VI, make_pair(name, V));
  }

  return true;
}

// DumpVal - a std::for_each function for dumping a value
//
static void DumpVal(const std::pair<const std::string, Value *> &V) {
  std::cerr << "  '" << V.first << "' = ";
  V.second->dump();
  std::cerr << "\n";
}

// dump - print out the symbol table
//
void ValueSymbolTable::dump() const {
  std::cerr << "ValueSymbolTable:\n";
  for_each(vmap.begin(), vmap.end(), DumpVal);
}
<commit_msg>Simple is good.  CVS is for revision control, not file headers<commit_after>//===-- ValueSymbolTable.cpp - Implement the ValueSymbolTable class -------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group.  It is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the ValueSymbolTable class for the VMCore library.
//
//===----------------------------------------------------------------------===//

#include "llvm/GlobalValue.h"
#include "llvm/Type.h"
#include "llvm/ValueSymbolTable.h"
#include "llvm/ADT/StringExtras.h"
#include <algorithm>
#include <iostream>

using namespace llvm;

#define DEBUG_SYMBOL_TABLE 0
#define DEBUG_ABSTYPE 0

// Class destructor
ValueSymbolTable::~ValueSymbolTable() {
#ifndef NDEBUG   // Only do this in -g mode...
  bool LeftoverValues = true;
  for (iterator VI = vmap.begin(), VE = vmap.end(); VI != VE; ++VI)
    if (!isa<Constant>(VI->second) ) {
      std::cerr << "Value still in symbol table! Type = '"
                << VI->second->getType()->getDescription() << "' Name = '"
                << VI->first << "'\n";
      LeftoverValues = false;
    }
  assert(LeftoverValues && "Values remain in symbol table!");
#endif
}

// getUniqueName - Given a base name, return a string that is either equal to
// it (or derived from it) that does not already occur in the symbol table for
// the specified type.
//
std::string ValueSymbolTable::getUniqueName(const std::string &BaseName) const {
  std::string TryName = BaseName;
  const_iterator End = vmap.end();

  // See if the name exists
  while (vmap.find(TryName) != End)            // Loop until we find a free
    TryName = BaseName + utostr(++LastUnique); // name in the symbol table
  return TryName;
}

// lookup a value - Returns null on failure...
//
Value *ValueSymbolTable::lookup(const std::string &Name) const {
  const_iterator VI = vmap.find(Name);
  if (VI != vmap.end())                   // We found the symbol
    return const_cast<Value*>(VI->second);
  return 0;
}

// Strip the symbol table of its names.
//
bool ValueSymbolTable::strip() {
  bool RemovedSymbol = false;
  for (iterator VI = vmap.begin(), VE = vmap.end(); VI != VE; ) {
    Value *V = VI->second;
    ++VI;
    if (!isa<GlobalValue>(V) || cast<GlobalValue>(V)->hasInternalLinkage()) {
      // Set name to "", removing from symbol table!
      V->setName("");
      RemovedSymbol = true;
    }
  }
  return RemovedSymbol;
}

// Insert a value into the symbol table with the specified name...
//
void ValueSymbolTable::insert(Value* V) {
  assert(V && "Can't insert null Value into symbol table!");
  assert(V->hasName() && "Can't insert nameless Value into symbol table");

  // Check to see if there is a naming conflict.  If so, rename this type!
  std::string UniqueName = getUniqueName(V->getName());

#if DEBUG_SYMBOL_TABLE
  dump();
  std::cerr << " Inserting value: " << UniqueName << ": " << V->dump() << "\n";
#endif

  // Insert the vmap entry
  vmap.insert(make_pair(UniqueName, V));
}

// Remove a value
bool ValueSymbolTable::erase(Value *V) {
  assert(V->hasName() && "Value doesn't have name!");
  iterator Entry = vmap.find(V->getName());
  if (Entry == vmap.end())
    return false;

#if DEBUG_SYMBOL_TABLE
  dump();
  std::cerr << " Removing Value: " << Entry->second->getName() << "\n";
#endif

  // Remove the value from the plane...
  vmap.erase(Entry);
  return true;
}

// rename - Given a value with a non-empty name, remove its existing entry
// from the symbol table and insert a new one for Name.  This is equivalent to
// doing "remove(V), V->Name = Name, insert(V)",
//
bool ValueSymbolTable::rename(Value *V, const std::string &name) {
  assert(V && "Can't rename a null Value");
  assert(V->hasName() && "Can't rename a nameless Value");
  assert(!V->getName().empty() && "Can't rename an Value with null name");
  assert(V->getName() != name && "Can't rename a Value with same name");
  assert(!name.empty() && "Can't rename a named Value with a null name");

  // Find the name
  iterator VI = vmap.find(V->getName());

  // If we didn't find it, we're done
  if (VI == vmap.end())
    return false;

  // Remove the old entry.
  vmap.erase(VI);

  // See if we can insert the new name.
  VI = vmap.lower_bound(name);

  // Is there a naming conflict?
  if (VI != vmap.end() && VI->first == name) {
    V->Name = getUniqueName( name);
    vmap.insert(make_pair(V->Name, V));
  } else {
    V->Name = name;
    vmap.insert(VI, make_pair(name, V));
  }

  return true;
}

// DumpVal - a std::for_each function for dumping a value
//
static void DumpVal(const std::pair<const std::string, Value *> &V) {
  std::cerr << "  '" << V.first << "' = ";
  V.second->dump();
  std::cerr << "\n";
}

// dump - print out the symbol table
//
void ValueSymbolTable::dump() const {
  std::cerr << "ValueSymbolTable:\n";
  for_each(vmap.begin(), vmap.end(), DumpVal);
}
<|endoftext|>


<commit_before>/**
 * @file lsh_test.cpp
 *
 * Unit tests for the 'LSHSearch' class.
 */
#include <mlpack/core.hpp>
#include <mlpack/core/metrics/lmetric.hpp>
#include <boost/test/unit_test.hpp>
#include "old_boost_test_definitions.hpp"

#include <mlpack/methods/lsh/lsh_search.hpp>
#include <mlpack/methods/neighbor_search/neighbor_search.hpp>

using namespace std;
using namespace mlpack;
using namespace mlpack::neighbor;

BOOST_AUTO_TEST_SUITE(LSHTest);

BOOST_AUTO_TEST_CASE(LSHSearchTest)
{
  //kNN and LSH parameters
  const int k = 4;
  const int numProj = 10;
  const double hashWidth = 0;
  const int secondHashSize = 99901;
  const int bucketSize = 500;

  //read iris training and testing data as reference and query
  string iris_train="iris_train.csv";
  string iris_test="iris_test.csv";
  arma::mat rdata;
  arma::mat qdata;
  data::Load(iris_train, rdata, true);
  data::Load(iris_test, qdata, true);
  const int n_queries = qdata.n_cols;

  //Run classic knn on reference data
  AllkNN knn(rdata);
  arma::Mat<size_t> groundTruth;
  arma::mat groundDistances;
  knn.Search(qdata, k, groundTruth, groundDistances);

  //Test: Run LSH with varying number of tables, keeping all other parameters
  //constant. Compute the recall, i.e. the number of reported neighbors that
  //are real neighbors of the query.
  //LSH's property is that (with high probability), increasing the number of
  //tables will increase recall.

  //Run LSH with varying number of tables and compute recall
  const int L[] = {1, 4, 16, 32, 64, 128}; //number of tables
  const int Lsize = 6;
  int recall_L[Lsize] = {0}; //recall of each LSH run

  for (int l=0; l < Lsize; ++l){
      //run LSH with only numTables varying (other values default)
      LSHSearch<> lsh_test(rdata, numProj, L[l],
              hashWidth, secondHashSize, bucketSize);
      arma::Mat<size_t> LSHneighbors;
      arma::mat LSHdistances;
      lsh_test.Search(qdata, k, LSHneighbors, LSHdistances);

      //compute recall for each query
      for (int q=0; q < n_queries; ++q){
          for (int neigh = 0; neigh < k; ++neigh){
              if (LSHneighbors(neigh, q) == groundTruth(neigh, q))
                  recall_L[l]++;
          }
      }

      if (l > 0)
          BOOST_CHECK(recall_L[l] >= recall_L[l-1]);
  }

}

BOOST_AUTO_TEST_CASE(LSHTrainTest)
{
  // This is a not very good test that simply checks that the re-trained LSH
  // model operates on the correct dimensionality and returns the correct number
  // of results.
  arma::mat referenceData = arma::randu<arma::mat>(3, 100);
  arma::mat newReferenceData = arma::randu<arma::mat>(10, 400);
  arma::mat queryData = arma::randu<arma::mat>(10, 200);

  LSHSearch<> lsh(referenceData, 3, 2, 2.0, 11, 3);

  lsh.Train(newReferenceData, 4, 3, 3.0, 12, 4);

  arma::Mat<size_t> neighbors;
  arma::mat distances;

  lsh.Search(queryData, 3, neighbors, distances);

  BOOST_REQUIRE_EQUAL(neighbors.n_cols, 200);
  BOOST_REQUIRE_EQUAL(neighbors.n_rows, 3);
  BOOST_REQUIRE_EQUAL(distances.n_cols, 200);
  BOOST_REQUIRE_EQUAL(distances.n_rows, 3);
}

BOOST_AUTO_TEST_CASE(EmptyConstructorTest)
{
  // If we create an empty LSH model and then call Search(), it should throw an
  // exception.
  LSHSearch<> lsh;

  arma::mat dataset = arma::randu<arma::mat>(5, 50);
  arma::mat distances;
  arma::Mat<size_t> neighbors;
  BOOST_REQUIRE_THROW(lsh.Search(dataset, 2, neighbors, distances),
      std::invalid_argument);

  // Now, train.
  lsh.Train(dataset, 4, 3, 3.0, 12, 4);

  lsh.Search(dataset, 3, neighbors, distances);

  BOOST_REQUIRE_EQUAL(neighbors.n_cols, 50);
  BOOST_REQUIRE_EQUAL(neighbors.n_rows, 3);
  BOOST_REQUIRE_EQUAL(distances.n_cols, 50);
  BOOST_REQUIRE_EQUAL(distances.n_rows, 3);
}

BOOST_AUTO_TEST_SUITE_END();
<commit_msg>Adds two tests for LSHSearch<commit_after>/**
 * @file lsh_test.cpp
 *
 * Unit tests for the 'LSHSearch' class.
 */
#include <mlpack/core.hpp>
#include <mlpack/core/metrics/lmetric.hpp>
#include <boost/test/unit_test.hpp>
#include "old_boost_test_definitions.hpp"

#include <mlpack/methods/lsh/lsh_search.hpp>
#include <mlpack/methods/neighbor_search/neighbor_search.hpp>

using namespace std;
using namespace mlpack;
using namespace mlpack::neighbor;

double compute_recall(arma::Mat<size_t> LSHneighbors, arma::Mat<size_t> groundTruth){
  const int n_queries = LSHneighbors.n_cols;
  const int n_neigh = LSHneighbors.n_rows;

  int recall = 0;
  for (int q = 0; q < n_queries; ++q){
      for (int n = 0; n < n_neigh; ++n){
        recall+=(LSHneighbors(n,q)==groundTruth(n,q));
      }
  }
  return static_cast<double>(recall)/
      (static_cast<double>(n_queries*n_neigh));
}

BOOST_AUTO_TEST_SUITE(LSHTest);

BOOST_AUTO_TEST_CASE(LSHSearchTest)
{

  math::RandomSeed(time(0));
  //kNN and LSH parameters
  const int k = 4;
  //const int numTables = 30;
  const int numProj = 10;
  const double hashWidth = 0;
  const int secondHashSize = 99901;
  const int bucketSize = 500;

  //test parameters
  const double epsilon = 0.1;

  //read iris training and testing data as reference and query
  const string iris_train="iris_train.csv";
  const string iris_test="iris_test.csv";
  arma::mat rdata;
  arma::mat qdata;
  data::Load(iris_train, rdata, true);
  data::Load(iris_test, qdata, true);

  //Test: Run LSH with varying number of tables, keeping all other parameters
  //constant. Compute the recall, i.e. the number of reported neighbors that
  //are real neighbors of the query.
  //LSH's property is that (with high probability), increasing the number of
  //tables will increase recall. Epsilon ensures that if noise lightly affects
  //the projections, the test will not fail.

  //Run classic knn on reference data
  AllkNN knn(rdata);
  arma::Mat<size_t> groundTruth;
  arma::mat groundDistances;
  knn.Search(qdata, k, groundTruth, groundDistances);

  //Run LSH for different number of tables
  const int L[] = {1, 8, 16, 32, 64, 128}; //number of tables
  const int Lsize = 6;
  double recall_L[Lsize] = {0.0}; //recall of each LSH run

  for (int l=0; l < Lsize; ++l){
      //run LSH with only numTables varying (other values default)
      LSHSearch<> lsh_test(rdata, numProj, L[l],
              hashWidth, secondHashSize, bucketSize);
      arma::Mat<size_t> LSHneighbors;
      arma::mat LSHdistances;
      lsh_test.Search(qdata, k, LSHneighbors, LSHdistances);

      //compute recall for each query
      recall_L[l] = compute_recall(LSHneighbors, groundTruth);

      if (l > 0){
          BOOST_CHECK(recall_L[l] >= recall_L[l-1]-epsilon);
      }
  }

  //Test: Run a very expensive LSH search, with a large number of hash tables
  //and a large hash width. This run should return an acceptable recall. We set
  //the bar very low (recall >= 50%) to make sure that a test fail means bad
  //implementation.

  const int H = 10000; //first-level hash width
  const int K = 128; //projections per table
  const int T = 128; //number of tables
  const double recall_thresh_t2 = 0.5;

  LSHSearch<> lsh_test(rdata, K, T, H, secondHashSize, bucketSize);
  arma::Mat<size_t> LSHneighbors;
  arma::mat LSHdistances;
  lsh_test.Search(qdata, k, LSHneighbors, LSHdistances);

  const double recall_t2 = compute_recall(LSHneighbors, groundTruth);

  BOOST_CHECK(recall_t2 >= recall_thresh_t2);

}

BOOST_AUTO_TEST_CASE(LSHTrainTest)
{
  // This is a not very good test that simply checks that the re-trained LSH
  // model operates on the correct dimensionality and returns the correct number
  // of results.
  arma::mat referenceData = arma::randu<arma::mat>(3, 100);
  arma::mat newReferenceData = arma::randu<arma::mat>(10, 400);
  arma::mat queryData = arma::randu<arma::mat>(10, 200);

  LSHSearch<> lsh(referenceData, 3, 2, 2.0, 11, 3);

  lsh.Train(newReferenceData, 4, 3, 3.0, 12, 4);

  arma::Mat<size_t> neighbors;
  arma::mat distances;

  lsh.Search(queryData, 3, neighbors, distances);

  BOOST_REQUIRE_EQUAL(neighbors.n_cols, 200);
  BOOST_REQUIRE_EQUAL(neighbors.n_rows, 3);
  BOOST_REQUIRE_EQUAL(distances.n_cols, 200);
  BOOST_REQUIRE_EQUAL(distances.n_rows, 3);
}

BOOST_AUTO_TEST_CASE(EmptyConstructorTest)
{
  // If we create an empty LSH model and then call Search(), it should throw an
  // exception.
  LSHSearch<> lsh;

  arma::mat dataset = arma::randu<arma::mat>(5, 50);
  arma::mat distances;
  arma::Mat<size_t> neighbors;
  BOOST_REQUIRE_THROW(lsh.Search(dataset, 2, neighbors, distances),
      std::invalid_argument);

  // Now, train.
  lsh.Train(dataset, 4, 3, 3.0, 12, 4);

  lsh.Search(dataset, 3, neighbors, distances);

  BOOST_REQUIRE_EQUAL(neighbors.n_cols, 50);
  BOOST_REQUIRE_EQUAL(neighbors.n_rows, 3);
  BOOST_REQUIRE_EQUAL(distances.n_cols, 50);
  BOOST_REQUIRE_EQUAL(distances.n_rows, 3);
}

BOOST_AUTO_TEST_SUITE_END();
<|endoftext|>


<commit_before>/*
 * mode_plasma.cpp
 *
 * Copyright (C) 2014 William Markezana <william.markezana@me.com>
 *
 */

#include "mode_plasma.h"

/*
 * public library interface
 *
 */
extern "C" mode_interface* create_mode(size_t pWidth, size_t pHeight, bool pAudioAvailable)
{
  return new mode_plasma(pWidth, pHeight, "Plasma", pAudioAvailable);
}

extern "C" void destroy_mode(mode_interface* object)
{
  delete object;
}

/*
 * constructor
 *
 */
mode_plasma::mode_plasma(size_t pWidth, size_t pHeight, string pName, bool pAudioAvailable)
		: mode_interface(pWidth, pHeight, pName, pAudioAvailable)
{
	mGridLayer = mBitmap->add_layer();

	mHueMatrix.resize(mWidth);
	for (auto &column : mHueMatrix)
	{
		column.resize(mHeight);
		for (auto &item : column)
			item = rand() % 720;
	}

	// Grid overlay
	setup_grid_layer_with_alpha(60);

	// Settings
	if (mAudioAvailable)
		mSettings.add("Sound Reactive", "Audio", "1", 0.0, 1.0, ihmCheckbox);
	mSettings.set_ini_path(mIniFilePath);
}

/*
 * destructor
 *
 */
mode_plasma::~mode_plasma()
{

}

/*
 * private functions
 *
 */
void mode_plasma::setup_grid_layer_with_alpha(uint8_t alpha)
{
	rgb_color girdColor = ColorBlack;
	girdColor.A = alpha;

	for (size_t y = 0; y < mHeight; y++)
	{
		for (size_t x = 0; x < mWidth; x++)
		{
			mGridLayer->set_pixel(x, y, ((x % 2) == (y % 2)) ? girdColor : ColorClear);
		}
	}
}

/*
 * public functions
 *
 */
void mode_plasma::paint()
{
#define COEF_FILTER			(4)

	int left, right, above, below;
	hsv_color hsvColor;
	int currentHue;
	float averageHue;
	uint16_t uint16AverageHue;
	bool soundReactive = mSettings["Sound Reactive"]->get_value<bool>();

	for (size_t j = 0; j < mHeight; j++)
	{
		for (size_t i = 0; i < mWidth; i++)
		{
			left = i - 1;
			right = i + 1;
			above = j - 1;
			below = j + 1;

			if (left < 0)
				left = mWidth - 1;
			if (left > (int) mWidth - 1)
				left = 0;
			if (right < 0)
				right = mWidth - 1;
			if (right > (int) mWidth - 1)
				right = 0;
			if (above < 0)
				above = mHeight - 1;
			if (above > (int) mHeight - 1)
				above = 0;
			if (below < 0)
				below = mHeight - 1;
			if (below > (int) mHeight - 1)
				below = 0;

			hsvColor = mBitmap->get_hsv_pixel(i, j);
			hsvColor.A = 255;

			currentHue = mHueMatrix[i][j];

			averageHue = ((float) (mHueMatrix[left][j]) + (float) (mHueMatrix[right][j]) + (float) (mHueMatrix[i][above])
					+ (float) (mHueMatrix[i][below])) / 4.0f;

			if (averageHue != currentHue)
			{
				uint16AverageHue = (uint16_t) ceil((currentHue * (COEF_FILTER - 1) + averageHue + 6) / COEF_FILTER);
				mHueMatrix[i][j] = uint16AverageHue;
			}

			if (!soundReactive)
			{
				if (rand() % 100000 > 99945)
				{
					mHueMatrix[i][j] = 0;
					mHueMatrix[right][j] = 0;
					mHueMatrix[i][below] = 0;
				}
			}

			hsvColor.H = (mHueMatrix[i][j] % 720) / 2;
			hsvColor.S = 255;
			hsvColor.V = 255;

			mBitmap->set_hsv_pixel(i, j, hsvColor);
		}
	}
}

void mode_plasma::beat_detected()
{
	for (size_t i = 0; i < (size_t) (rand() % 4); i++)
	{
		mHueMatrix[rand() % mWidth][rand() % mHeight] = 0;
	}
}
<commit_msg>[mode_plasma] added setting to disable or enable grid overlay<commit_after>/*
 * mode_plasma.cpp
 *
 * Copyright (C) 2014 William Markezana <william.markezana@me.com>
 *
 */

#include "mode_plasma.h"

/*
 * public library interface
 *
 */
extern "C" mode_interface* create_mode(size_t pWidth, size_t pHeight, bool pAudioAvailable)
{
  return new mode_plasma(pWidth, pHeight, "Plasma", pAudioAvailable);
}

extern "C" void destroy_mode(mode_interface* object)
{
  delete object;
}

/*
 * constructor
 *
 */
mode_plasma::mode_plasma(size_t pWidth, size_t pHeight, string pName, bool pAudioAvailable)
		: mode_interface(pWidth, pHeight, pName, pAudioAvailable)
{
	mGridLayer = mBitmap->add_layer();

	mHueMatrix.resize(mWidth);
	for (auto &column : mHueMatrix)
	{
		column.resize(mHeight);
		for (auto &item : column)
			item = rand() % 720;
	}

	// Settings
	if (mAudioAvailable)
		mSettings.add("Sound Reactive", "Audio", "1", 0.0, 1.0, ihmCheckbox);
	mSettings.add("Grid", "Overlay", "1", 0.0, 1.0, ihmCheckbox);
	mSettings.set_ini_path(mIniFilePath);
}

/*
 * destructor
 *
 */
mode_plasma::~mode_plasma()
{

}

/*
 * private functions
 *
 */
void mode_plasma::setup_grid_layer_with_alpha(uint8_t alpha)
{
	rgb_color girdColor = ColorBlack;
	girdColor.A = alpha;

	for (size_t y = 0; y < mHeight; y++)
	{
		for (size_t x = 0; x < mWidth; x++)
		{
			mGridLayer->set_pixel(x, y, ((x % 2) == (y % 2)) ? girdColor : ColorClear);
		}
	}
}

/*
 * public functions
 *
 */
void mode_plasma::paint()
{
#define COEF_FILTER			(4)

	int left, right, above, below;
	hsv_color hsvColor;
	int currentHue;
	float averageHue;
	uint16_t uint16AverageHue;
	bool soundReactive = mSettings["Sound Reactive"]->get_value<bool>();
	bool showGridOverlay = mSettings["Grid"]->get_value<bool>();

	// Grid overlay
	setup_grid_layer_with_alpha(showGridOverlay ? 120 : 0);

	for (size_t j = 0; j < mHeight; j++)
	{
		for (size_t i = 0; i < mWidth; i++)
		{
			left = i - 1;
			right = i + 1;
			above = j - 1;
			below = j + 1;

			if (left < 0)
				left = mWidth - 1;
			if (left > (int) mWidth - 1)
				left = 0;
			if (right < 0)
				right = mWidth - 1;
			if (right > (int) mWidth - 1)
				right = 0;
			if (above < 0)
				above = mHeight - 1;
			if (above > (int) mHeight - 1)
				above = 0;
			if (below < 0)
				below = mHeight - 1;
			if (below > (int) mHeight - 1)
				below = 0;

			hsvColor = mBitmap->get_hsv_pixel(i, j);
			hsvColor.A = 255;

			currentHue = mHueMatrix[i][j];

			averageHue = ((float) (mHueMatrix[left][j]) + (float) (mHueMatrix[right][j]) + (float) (mHueMatrix[i][above])
					+ (float) (mHueMatrix[i][below])) / 4.0f;

			if (averageHue != currentHue)
			{
				uint16AverageHue = (uint16_t) ceil((currentHue * (COEF_FILTER - 1) + averageHue + 6) / COEF_FILTER);
				mHueMatrix[i][j] = uint16AverageHue;
			}

			if (!soundReactive)
			{
				if (rand() % 100000 > 99945)
				{
					mHueMatrix[i][j] = 0;
					mHueMatrix[right][j] = 0;
					mHueMatrix[i][below] = 0;
				}
			}

			hsvColor.H = (mHueMatrix[i][j] % 720) / 2;
			hsvColor.S = 255;
			hsvColor.V = 255;

			mBitmap->set_hsv_pixel(i, j, hsvColor);
		}
	}
}

void mode_plasma::beat_detected()
{
	for (size_t i = 0; i < (size_t) (rand() % 4); i++)
	{
		mHueMatrix[rand() % mWidth][rand() % mHeight] = 0;
	}
}
<|endoftext|>