<commit_before>//===- LocalStackSlotAllocation.cpp - Pre-allocate locals to stack slots --===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass assigns local frame indices to stack slots relative to one another
// and allocates additional base registers to access them when the target
// estimates the are likely to be out of range of stack pointer and frame
// pointer relative addressing.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "localstackalloc"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Instructions.h"
#include "llvm/Intrinsics.h"
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetFrameInfo.h"

using namespace llvm;

STATISTIC(NumAllocations, "Number of frame indices allocated into local block");
STATISTIC(NumBaseRegisters, "Number of virtual frame base registers allocated");
STATISTIC(NumReplacements, "Number of frame indices references replaced");

namespace {
  class LocalStackSlotPass: public MachineFunctionPass {
    SmallVector<int64_t,16> LocalOffsets;

    void AdjustStackOffset(MachineFrameInfo *MFI, int FrameIdx, int64_t &Offset,
                           unsigned &MaxAlign);
    void calculateFrameObjectOffsets(MachineFunction &Fn);
    bool insertFrameReferenceRegisters(MachineFunction &Fn);
  public:
    static char ID; // Pass identification, replacement for typeid
    explicit LocalStackSlotPass() : MachineFunctionPass(ID) { }
    bool runOnMachineFunction(MachineFunction &MF);

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.setPreservesCFG();
      MachineFunctionPass::getAnalysisUsage(AU);
    }
    const char *getPassName() const {
      return "Local Stack Slot Allocation";
    }

  private:
  };
} // end anonymous namespace

char LocalStackSlotPass::ID = 0;

FunctionPass *llvm::createLocalStackSlotAllocationPass() {
  return new LocalStackSlotPass();
}

bool LocalStackSlotPass::runOnMachineFunction(MachineFunction &MF) {
  MachineFrameInfo *MFI = MF.getFrameInfo();
  unsigned LocalObjectCount = MFI->getObjectIndexEnd();

  // Early exit if there are no locals to consider
  if (!LocalObjectCount)
    return true;

  // Make sure we have enough space to store the local offsets.
  LocalOffsets.resize(MFI->getObjectIndexEnd());

  // Lay out the local blob.
  calculateFrameObjectOffsets(MF);

  // Insert virtual base registers to resolve frame index references.
  bool UsedBaseRegs = insertFrameReferenceRegisters(MF);

  // Tell MFI whether any base registers were allocated. PEI will only
  // want to use the local block allocations from this pass if there were any.
  // Otherwise, PEI can do a bit better job of getting the alignment right
  // without a hole at the start since it knows the alignment of the stack
  // at the start of local allocation, and this pass doesn't.
  MFI->setUseLocalStackAllocationBlock(UsedBaseRegs);

  return true;
}

/// AdjustStackOffset - Helper function used to adjust the stack frame offset.
void LocalStackSlotPass::AdjustStackOffset(MachineFrameInfo *MFI,
                                           int FrameIdx, int64_t &Offset,
                                           unsigned &MaxAlign) {
  unsigned Align = MFI->getObjectAlignment(FrameIdx);

  // If the alignment of this object is greater than that of the stack, then
  // increase the stack alignment to match.
  MaxAlign = std::max(MaxAlign, Align);

  // Adjust to alignment boundary.
  Offset = (Offset + Align - 1) / Align * Align;

  DEBUG(dbgs() << "Allocate FI(" << FrameIdx << ") to local offset "
        << Offset << "\n");
  // Keep the offset available for base register allocation
  LocalOffsets[FrameIdx] = Offset;
  // And tell MFI about it for PEI to use later
  MFI->mapLocalFrameObject(FrameIdx, Offset);
  Offset += MFI->getObjectSize(FrameIdx);

  ++NumAllocations;
}

/// calculateFrameObjectOffsets - Calculate actual frame offsets for all of the
/// abstract stack objects.
///
void LocalStackSlotPass::calculateFrameObjectOffsets(MachineFunction &Fn) {
  // Loop over all of the stack objects, assigning sequential addresses...
  MachineFrameInfo *MFI = Fn.getFrameInfo();
  int64_t Offset = 0;
  unsigned MaxAlign = 0;

  // Make sure that the stack protector comes before the local variables on the
  // stack.
  SmallSet<int, 16> LargeStackObjs;
  if (MFI->getStackProtectorIndex() >= 0) {
    AdjustStackOffset(MFI, MFI->getStackProtectorIndex(), Offset, MaxAlign);

    // Assign large stack objects first.
    for (unsigned i = 0, e = MFI->getObjectIndexEnd(); i != e; ++i) {
      if (MFI->isDeadObjectIndex(i))
        continue;
      if (MFI->getStackProtectorIndex() == (int)i)
        continue;
      if (!MFI->MayNeedStackProtector(i))
        continue;

      AdjustStackOffset(MFI, i, Offset, MaxAlign);
      LargeStackObjs.insert(i);
    }
  }

  // Then assign frame offsets to stack objects that are not used to spill
  // callee saved registers.
  for (unsigned i = 0, e = MFI->getObjectIndexEnd(); i != e; ++i) {
    if (MFI->isDeadObjectIndex(i))
      continue;
    if (MFI->getStackProtectorIndex() == (int)i)
      continue;
    if (LargeStackObjs.count(i))
      continue;

    AdjustStackOffset(MFI, i, Offset, MaxAlign);
  }

  // Remember how big this blob of stack space is
  MFI->setLocalFrameSize(Offset);
  MFI->setLocalFrameMaxAlign(MaxAlign);
}

static inline bool
lookupCandidateBaseReg(const SmallVector<std::pair<unsigned, int64_t>, 8> &Regs,
                       std::pair<unsigned, int64_t> &RegOffset,
                       int64_t LocalFrameOffset,
                       const MachineInstr *MI,
                       const TargetRegisterInfo *TRI) {
  unsigned e = Regs.size();
  for (unsigned i = 0; i < e; ++i) {
    RegOffset = Regs[i];
    // Check if the relative offset from the where the base register references
    // to the target address is in range for the instruction.
    int64_t Offset = LocalFrameOffset - RegOffset.second;
    if (TRI->isFrameOffsetLegal(MI, Offset))
      return true;
  }
  return false;
}

bool LocalStackSlotPass::insertFrameReferenceRegisters(MachineFunction &Fn) {
  // Scan the function's instructions looking for frame index references.
  // For each, ask the target if it wants a virtual base register for it
  // based on what we can tell it about where the local will end up in the
  // stack frame. If it wants one, re-use a suitable one we've previously
  // allocated, or if there isn't one that fits the bill, allocate a new one
  // and ask the target to create a defining instruction for it.
  bool UsedBaseReg = false;

  MachineFrameInfo *MFI = Fn.getFrameInfo();
  const TargetRegisterInfo *TRI = Fn.getTarget().getRegisterInfo();

  for (MachineFunction::iterator BB = Fn.begin(),
         E = Fn.end(); BB != E; ++BB) {
    // A base register definition is a register+offset pair.
    SmallVector<std::pair<unsigned, int64_t>, 8> BaseRegisters;

    for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); ++I) {
      MachineInstr *MI = I;
      // Debug value instructions can't be out of range, so they don't need
      // any updates.
      // FIXME: When we extend this stuff to handle functions with both
      // VLAs and dynamic realignment, we should update the debug values
      // to reference the new base pointer when possible.
      if (MI->isDebugValue())
        continue;

      // For now, allocate the base register(s) within the basic block
      // where they're used, and don't try to keep them around outside
      // of that. It may be beneficial to try sharing them more broadly
      // than that, but the increased register pressure makes that a
      // tricky thing to balance. Investigate if re-materializing these
      // becomes an issue.
      for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
        // Consider replacing all frame index operands that reference
        // an object allocated in the local block.
        if (MI->getOperand(i).isFI()) {
          int FrameIdx = MI->getOperand(i).getIndex();

          // Don't try this with values not in the local block.
          if (!MFI->isObjectPreAllocated(FrameIdx))
            continue;

          DEBUG(dbgs() << "Considering: " << *MI);
          if (TRI->needsFrameBaseReg(MI, i)) {
            unsigned BaseReg = 0;
            int64_t Offset = 0;

            DEBUG(dbgs() << "  Replacing FI in: " << *MI);

            // If we have a suitable base register available, use it; otherwise
            // create a new one. Note that any offset encoded in the
            // instruction itself will be taken into account by the target,
            // so we don't have to adjust for it here when reusing a base
            // register.
            std::pair<unsigned, int64_t> RegOffset;
            if (lookupCandidateBaseReg(BaseRegisters, RegOffset,
                                       LocalOffsets[FrameIdx], MI, TRI)) {
              DEBUG(dbgs() << "  Reusing base register " <<
                    RegOffset.first << "\n");
              // We found a register to reuse.
              BaseReg = RegOffset.first;
              Offset = LocalOffsets[FrameIdx] - RegOffset.second;
            } else {
              // No previously defined register was in range, so create a
              // new one.
              int64_t InstrOffset = TRI->getFrameIndexInstrOffset(MI, i);
              const TargetRegisterClass *RC = TRI->getPointerRegClass();
              BaseReg = Fn.getRegInfo().createVirtualRegister(RC);

              DEBUG(dbgs() << "  Materializing base register " << BaseReg <<
                    " at frame local offset " <<
                    LocalOffsets[FrameIdx] + InstrOffset << "\n");
              // Tell the target to insert the instruction to initialize
              // the base register.
              TRI->materializeFrameBaseRegister(I, BaseReg, FrameIdx,
                                                InstrOffset);

              // The base register already includes any offset specified
              // by the instruction, so account for that so it doesn't get
              // applied twice.
              Offset = -InstrOffset;

              BaseRegisters.push_back(
                std::pair<unsigned, int64_t>(BaseReg,
                                      LocalOffsets[FrameIdx] + InstrOffset));
              ++NumBaseRegisters;
              UsedBaseReg = true;
            }
            assert(BaseReg != 0 && "Unable to allocate virtual base register!");

            // Modify the instruction to use the new base register rather
            // than the frame index operand.
            TRI->resolveFrameIndex(I, BaseReg, Offset);
            DEBUG(dbgs() << "Resolved: " << *MI);

            ++NumReplacements;
          }

        }
      }
    }
  }
  return UsedBaseReg;
}
<commit_msg>Downwards growing stack allocation order reverses relative offsets<commit_after>//===- LocalStackSlotAllocation.cpp - Pre-allocate locals to stack slots --===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass assigns local frame indices to stack slots relative to one another
// and allocates additional base registers to access them when the target
// estimates the are likely to be out of range of stack pointer and frame
// pointer relative addressing.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "localstackalloc"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Instructions.h"
#include "llvm/Intrinsics.h"
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetFrameInfo.h"

using namespace llvm;

STATISTIC(NumAllocations, "Number of frame indices allocated into local block");
STATISTIC(NumBaseRegisters, "Number of virtual frame base registers allocated");
STATISTIC(NumReplacements, "Number of frame indices references replaced");

namespace {
  class LocalStackSlotPass: public MachineFunctionPass {
    SmallVector<int64_t,16> LocalOffsets;

    void AdjustStackOffset(MachineFrameInfo *MFI, int FrameIdx, int64_t &Offset,
                           unsigned &MaxAlign);
    void calculateFrameObjectOffsets(MachineFunction &Fn);
    bool insertFrameReferenceRegisters(MachineFunction &Fn);
  public:
    static char ID; // Pass identification, replacement for typeid
    explicit LocalStackSlotPass() : MachineFunctionPass(ID) { }
    bool runOnMachineFunction(MachineFunction &MF);

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.setPreservesCFG();
      MachineFunctionPass::getAnalysisUsage(AU);
    }
    const char *getPassName() const {
      return "Local Stack Slot Allocation";
    }

  private:
  };
} // end anonymous namespace

char LocalStackSlotPass::ID = 0;

FunctionPass *llvm::createLocalStackSlotAllocationPass() {
  return new LocalStackSlotPass();
}

bool LocalStackSlotPass::runOnMachineFunction(MachineFunction &MF) {
  MachineFrameInfo *MFI = MF.getFrameInfo();
  unsigned LocalObjectCount = MFI->getObjectIndexEnd();

  // Early exit if there are no locals to consider
  if (!LocalObjectCount)
    return true;

  // Make sure we have enough space to store the local offsets.
  LocalOffsets.resize(MFI->getObjectIndexEnd());

  // Lay out the local blob.
  calculateFrameObjectOffsets(MF);

  // Insert virtual base registers to resolve frame index references.
  bool UsedBaseRegs = insertFrameReferenceRegisters(MF);

  // Tell MFI whether any base registers were allocated. PEI will only
  // want to use the local block allocations from this pass if there were any.
  // Otherwise, PEI can do a bit better job of getting the alignment right
  // without a hole at the start since it knows the alignment of the stack
  // at the start of local allocation, and this pass doesn't.
  MFI->setUseLocalStackAllocationBlock(UsedBaseRegs);

  return true;
}

/// AdjustStackOffset - Helper function used to adjust the stack frame offset.
void LocalStackSlotPass::AdjustStackOffset(MachineFrameInfo *MFI,
                                           int FrameIdx, int64_t &Offset,
                                           unsigned &MaxAlign) {
  unsigned Align = MFI->getObjectAlignment(FrameIdx);

  // If the alignment of this object is greater than that of the stack, then
  // increase the stack alignment to match.
  MaxAlign = std::max(MaxAlign, Align);

  // Adjust to alignment boundary.
  Offset = (Offset + Align - 1) / Align * Align;

  DEBUG(dbgs() << "Allocate FI(" << FrameIdx << ") to local offset "
        << Offset << "\n");
  // Keep the offset available for base register allocation
  LocalOffsets[FrameIdx] = Offset;
  // And tell MFI about it for PEI to use later
  MFI->mapLocalFrameObject(FrameIdx, Offset);
  Offset += MFI->getObjectSize(FrameIdx);

  ++NumAllocations;
}

/// calculateFrameObjectOffsets - Calculate actual frame offsets for all of the
/// abstract stack objects.
///
void LocalStackSlotPass::calculateFrameObjectOffsets(MachineFunction &Fn) {
  // Loop over all of the stack objects, assigning sequential addresses...
  MachineFrameInfo *MFI = Fn.getFrameInfo();
  int64_t Offset = 0;
  unsigned MaxAlign = 0;

  // Make sure that the stack protector comes before the local variables on the
  // stack.
  SmallSet<int, 16> LargeStackObjs;
  if (MFI->getStackProtectorIndex() >= 0) {
    AdjustStackOffset(MFI, MFI->getStackProtectorIndex(), Offset, MaxAlign);

    // Assign large stack objects first.
    for (unsigned i = 0, e = MFI->getObjectIndexEnd(); i != e; ++i) {
      if (MFI->isDeadObjectIndex(i))
        continue;
      if (MFI->getStackProtectorIndex() == (int)i)
        continue;
      if (!MFI->MayNeedStackProtector(i))
        continue;

      AdjustStackOffset(MFI, i, Offset, MaxAlign);
      LargeStackObjs.insert(i);
    }
  }

  // Then assign frame offsets to stack objects that are not used to spill
  // callee saved registers.
  for (unsigned i = 0, e = MFI->getObjectIndexEnd(); i != e; ++i) {
    if (MFI->isDeadObjectIndex(i))
      continue;
    if (MFI->getStackProtectorIndex() == (int)i)
      continue;
    if (LargeStackObjs.count(i))
      continue;

    AdjustStackOffset(MFI, i, Offset, MaxAlign);
  }

  // Remember how big this blob of stack space is
  MFI->setLocalFrameSize(Offset);
  MFI->setLocalFrameMaxAlign(MaxAlign);
}

static inline bool
lookupCandidateBaseReg(const SmallVector<std::pair<unsigned, int64_t>, 8> &Regs,
                       std::pair<unsigned, int64_t> &RegOffset,
                       int64_t LocalFrameOffset,
                       bool StackGrowsDown,
                       const MachineInstr *MI,
                       const TargetRegisterInfo *TRI) {
  unsigned e = Regs.size();
  for (unsigned i = 0; i < e; ++i) {
    RegOffset = Regs[i];
    // Check if the relative offset from the where the base register references
    // to the target address is in range for the instruction.
    int64_t Offset = LocalFrameOffset - RegOffset.second;
    if (StackGrowsDown)
      Offset = -Offset;
    if (TRI->isFrameOffsetLegal(MI, Offset))
      return true;
  }
  return false;
}

bool LocalStackSlotPass::insertFrameReferenceRegisters(MachineFunction &Fn) {
  // Scan the function's instructions looking for frame index references.
  // For each, ask the target if it wants a virtual base register for it
  // based on what we can tell it about where the local will end up in the
  // stack frame. If it wants one, re-use a suitable one we've previously
  // allocated, or if there isn't one that fits the bill, allocate a new one
  // and ask the target to create a defining instruction for it.
  bool UsedBaseReg = false;

  MachineFrameInfo *MFI = Fn.getFrameInfo();
  const TargetRegisterInfo *TRI = Fn.getTarget().getRegisterInfo();
  const TargetFrameInfo &TFI = *Fn.getTarget().getFrameInfo();
  bool StackGrowsDown =
    TFI.getStackGrowthDirection() == TargetFrameInfo::StackGrowsDown;

  for (MachineFunction::iterator BB = Fn.begin(),
         E = Fn.end(); BB != E; ++BB) {
    // A base register definition is a register+offset pair.
    SmallVector<std::pair<unsigned, int64_t>, 8> BaseRegisters;

    for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); ++I) {
      MachineInstr *MI = I;
      // Debug value instructions can't be out of range, so they don't need
      // any updates.
      // FIXME: When we extend this stuff to handle functions with both
      // VLAs and dynamic realignment, we should update the debug values
      // to reference the new base pointer when possible.
      if (MI->isDebugValue())
        continue;

      // For now, allocate the base register(s) within the basic block
      // where they're used, and don't try to keep them around outside
      // of that. It may be beneficial to try sharing them more broadly
      // than that, but the increased register pressure makes that a
      // tricky thing to balance. Investigate if re-materializing these
      // becomes an issue.
      for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
        // Consider replacing all frame index operands that reference
        // an object allocated in the local block.
        if (MI->getOperand(i).isFI()) {
          int FrameIdx = MI->getOperand(i).getIndex();

          // Don't try this with values not in the local block.
          if (!MFI->isObjectPreAllocated(FrameIdx))
            continue;

          DEBUG(dbgs() << "Considering: " << *MI);
          if (TRI->needsFrameBaseReg(MI, i)) {
            unsigned BaseReg = 0;
            int64_t Offset = 0;

            DEBUG(dbgs() << "  Replacing FI in: " << *MI);

            // If we have a suitable base register available, use it; otherwise
            // create a new one. Note that any offset encoded in the
            // instruction itself will be taken into account by the target,
            // so we don't have to adjust for it here when reusing a base
            // register.
            std::pair<unsigned, int64_t> RegOffset;
            if (lookupCandidateBaseReg(BaseRegisters, RegOffset,
                                       LocalOffsets[FrameIdx],
                                       StackGrowsDown, MI, TRI)) {
              DEBUG(dbgs() << "  Reusing base register " <<
                    RegOffset.first << "\n");
              // We found a register to reuse.
              BaseReg = RegOffset.first;
              Offset = LocalOffsets[FrameIdx] - RegOffset.second;
              if (StackGrowsDown)
                Offset = -Offset;
            } else {
              // No previously defined register was in range, so create a
              // new one.
              int64_t InstrOffset = TRI->getFrameIndexInstrOffset(MI, i);
              const TargetRegisterClass *RC = TRI->getPointerRegClass();
              BaseReg = Fn.getRegInfo().createVirtualRegister(RC);

              DEBUG(dbgs() << "  Materializing base register " << BaseReg <<
                    " at frame local offset " <<
                    LocalOffsets[FrameIdx] + InstrOffset << "\n");
              // Tell the target to insert the instruction to initialize
              // the base register.
              TRI->materializeFrameBaseRegister(I, BaseReg, FrameIdx,
                                                InstrOffset);

              // The base register already includes any offset specified
              // by the instruction, so account for that so it doesn't get
              // applied twice.
              Offset = -InstrOffset;

              BaseRegisters.push_back(
                std::pair<unsigned, int64_t>(BaseReg,
                                      LocalOffsets[FrameIdx] + InstrOffset));
              ++NumBaseRegisters;
              UsedBaseReg = true;
            }
            assert(BaseReg != 0 && "Unable to allocate virtual base register!");

            // Modify the instruction to use the new base register rather
            // than the frame index operand.
            TRI->resolveFrameIndex(I, BaseReg, Offset);
            DEBUG(dbgs() << "Resolved: " << *MI);

            ++NumReplacements;
          }

        }
      }
    }
  }
  return UsedBaseReg;
}
<|endoftext|>


<commit_before>/*
    virtual_keyboard.cpp:

    Copyright (C) 2006 Steven Yi

    This file is part of Csound.

    The Csound Library is free software; you can redistribute it
    and/or modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    Csound is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with Csound; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA
*/

#include "csdl.h"
#include "csGblMtx.h"
#include "midiops.h"
#include "oload.h"
#include "winFLTK.h"
#include "FLTKKeyboardWindow.hpp"

static FLTKKeyboardWindow *createWindow() {
       return new FLTKKeyboardWindow(624, 80, "Csound Virtual Keyboard");
}

static void deleteWindow(FLTKKeyboardWindow * keyWin) {
    delete keyWin;
}

extern "C"
{

static int OpenMidiInDevice_(CSOUND *csound, void **userData, const char *dev)
{
    FLTKKeyboardWindow *keyboard = createWindow();
    *userData = (void *)keyboard;

    Fl_lock(csound);
    keyboard->show();
    //keyboard->redraw();
    Fl_wait(csound, 0.0);
    Fl_unlock(csound);

    /* report success */
    return 0;
}

static int OpenMidiOutDevice_(CSOUND *csound, void **userData, const char *dev)
{
    /* report success */
    return 0;
}

static int ReadMidiData_(CSOUND *csound, void *userData,
                         unsigned char *mbuf, int nbytes)
{

    FLTKKeyboardWindow *keyWin = (FLTKKeyboardWindow *)userData;

    if(!keyWin->visible()) {
        return 0;
    }

    Fl_lock(csound);
    keyWin->make_current();
//    if(keyboard->damage()) {
//        keyboard->redraw();
//    }
	Fl::wait(0.0);
    Fl_unlock(csound);

 	int *keyStates = keyWin->keyboard->keyStates;

    int count = 0;

    for(int i = 0; i < 88; i++) {
        if(keyStates[i] == 1) {
            //csound->Message(csound, "key down: %d\n", i);
            keyStates[i] = 0;

            *mbuf++ = (unsigned char)0x90;
            *mbuf++ = (unsigned char)i + 21;
            *mbuf++ = (unsigned char)127;

            count += 3;

        } else if (keyStates[i] == 2) {
            keyStates[i] = 0;
            //csound->Message(csound, "key up: %d\n", i);

            *mbuf++ = (unsigned char)0x90;
            *mbuf++ = (unsigned char)i + 21;
            *mbuf++ = (unsigned char)0;

            count += 3;
        }

    }

    return count;
}

static int WriteMidiData_(CSOUND *csound, void *userData,
                          const unsigned char *mbuf, int nbytes)
{
    /* return the number of bytes written */
    return 0;
}

static int CloseMidiInDevice_(CSOUND *csound, void *userData)
{

    deleteWindow((FLTKKeyboardWindow *)userData);

    return 0;
}

static int CloseMidiOutDevice_(CSOUND *csound, void *userData)
{
    return 0;
}

/* module interface functions */

PUBLIC int csoundModuleCreate(CSOUND *csound)
{
    /* nothing to do, report success */
    csound->Message(csound, "virtual_keyboard real time MIDI plugin for Csound\n");
    return 0;
}

PUBLIC int csoundModuleInit(CSOUND *csound)
{
    char    *drv;

    if (csound->QueryGlobalVariable(csound,
                                    "FLTK_Flags") == (void*) 0) {
      if (csound->CreateGlobalVariable(csound,
                                       "FLTK_Flags", sizeof(int)) != 0)
        csound->Die(csound,
                    Str("virtual_keyboard.cpp: error allocating FLTK flags"));
    }

    drv = (char*) (csound->QueryGlobalVariable(csound, "_RTMIDI"));
    if (drv == NULL)
      return 0;
    if (!(strcmp(drv, "virtual") == 0))
      return 0;
    csound->Message(csound, "rtmidi: virtual_keyboard module enabled\n");
    csound->SetExternalMidiInOpenCallback(csound, OpenMidiInDevice_);
    csound->SetExternalMidiReadCallback(csound, ReadMidiData_);
    csound->SetExternalMidiInCloseCallback(csound, CloseMidiInDevice_);
    csound->SetExternalMidiOutOpenCallback(csound, OpenMidiOutDevice_);
    csound->SetExternalMidiWriteCallback(csound, WriteMidiData_);
    csound->SetExternalMidiOutCloseCallback(csound, CloseMidiOutDevice_);

    return 0;
}

PUBLIC int csoundModuleInfo(void)
{
    /* does not depend on MYFLT type */
    return ((CS_APIVERSION << 16) + (CS_APISUBVER << 8));
}

} // END EXTERN C
<commit_msg>changed to use Fl_awake instead of keyWin->make_current(), use locking for accessing keystates; seems to have stabilized CPU usage as well as stuck notes<commit_after>/*
    virtual_keyboard.cpp:

    Copyright (C) 2006 Steven Yi

    This file is part of Csound.

    The Csound Library is free software; you can redistribute it
    and/or modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    Csound is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with Csound; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA
*/

#include "csdl.h"
#include "csGblMtx.h"
#include "midiops.h"
#include "oload.h"
#include "winFLTK.h"
#include "FLTKKeyboardWindow.hpp"

static FLTKKeyboardWindow *createWindow(CSOUND *csound) {
       return new FLTKKeyboardWindow(csound, 624, 80, "Csound Virtual Keyboard");
}

static void deleteWindow(FLTKKeyboardWindow * keyWin) {
    delete keyWin;
}

extern "C"
{

static int OpenMidiInDevice_(CSOUND *csound, void **userData, const char *dev)
{
    FLTKKeyboardWindow *keyboard = createWindow(csound);
    *userData = (void *)keyboard;

    Fl_lock(csound);
    keyboard->show();
    Fl_wait(csound, 0.0);
    Fl_unlock(csound);

    /* report success */
    return 0;
}

static int OpenMidiOutDevice_(CSOUND *csound, void **userData, const char *dev)
{
    /* report success */
    return 0;
}

static int ReadMidiData_(CSOUND *csound, void *userData,
                         unsigned char *mbuf, int nbytes)
{

    FLTKKeyboardWindow *keyWin = (FLTKKeyboardWindow *)userData;

    if(!keyWin->visible()) {
        return 0;
    }

    Fl_lock(csound);
	Fl_awake(csound);
	Fl_wait(csound, 0.0);
	Fl_unlock(csound);

	keyWin->keyboard->lock();
 	int *keyStates = keyWin->keyboard->keyStates;

    int count = 0;

    for(int i = 0; i < 88; i++) {
        if(keyStates[i] == 1) {
            //csound->Message(csound, "key down: %d\n", i);
            keyStates[i] = 0;

            *mbuf++ = (unsigned char)0x90;
            *mbuf++ = (unsigned char)i + 21;
            *mbuf++ = (unsigned char)127;

            count += 3;

        } else if (keyStates[i] == 2) {
            keyStates[i] = 0;
            //csound->Message(csound, "key up: %d\n", i);

            *mbuf++ = (unsigned char)0x90;
            *mbuf++ = (unsigned char)i + 21;
            *mbuf++ = (unsigned char)0;

            count += 3;
        }

    }
	keyWin->keyboard->unlock();

    return count;
}

static int WriteMidiData_(CSOUND *csound, void *userData,
                          const unsigned char *mbuf, int nbytes)
{
    /* return the number of bytes written */
    return 0;
}

static int CloseMidiInDevice_(CSOUND *csound, void *userData)
{

    deleteWindow((FLTKKeyboardWindow *)userData);

    return 0;
}

static int CloseMidiOutDevice_(CSOUND *csound, void *userData)
{
    return 0;
}

/* module interface functions */

PUBLIC int csoundModuleCreate(CSOUND *csound)
{
    /* nothing to do, report success */
    csound->Message(csound, "virtual_keyboard real time MIDI plugin for Csound\n");
    return 0;
}

PUBLIC int csoundModuleInit(CSOUND *csound)
{
    char    *drv;

    if (csound->QueryGlobalVariable(csound,
                                    "FLTK_Flags") == (void*) 0) {
      if (csound->CreateGlobalVariable(csound,
                                       "FLTK_Flags", sizeof(int)) != 0)
        csound->Die(csound,
                    Str("virtual_keyboard.cpp: error allocating FLTK flags"));
    }

    drv = (char*) (csound->QueryGlobalVariable(csound, "_RTMIDI"));
    if (drv == NULL)
      return 0;
    if (!(strcmp(drv, "virtual") == 0))
      return 0;
    csound->Message(csound, "rtmidi: virtual_keyboard module enabled\n");
    csound->SetExternalMidiInOpenCallback(csound, OpenMidiInDevice_);
    csound->SetExternalMidiReadCallback(csound, ReadMidiData_);
    csound->SetExternalMidiInCloseCallback(csound, CloseMidiInDevice_);
    csound->SetExternalMidiOutOpenCallback(csound, OpenMidiOutDevice_);
    csound->SetExternalMidiWriteCallback(csound, WriteMidiData_);
    csound->SetExternalMidiOutCloseCallback(csound, CloseMidiOutDevice_);

    return 0;
}

PUBLIC int csoundModuleInfo(void)
{
    /* does not depend on MYFLT type */
    return ((CS_APIVERSION << 16) + (CS_APISUBVER << 8));
}

} // END EXTERN C
<|endoftext|>


<commit_before>#include "../includes/win32_2/Controller.h"

static std::wstring convertMultiByteToWideChar(const std::string &multiByte)
{
    const int wlen = MultiByteToWideChar(CP_UTF8, 0, multiByte.data(), -1, 0, 0);

    if (wlen == 0) {
        return std::wstring();
    }

    std::wstring wideString;
    wideString.reserve(wlen);
    int failureToResolveUTF8 = MultiByteToWideChar(CP_UTF8, 0, multiByte.data(), -1, const_cast<wchar_t*>(wideString.data()), wlen);
    if (failureToResolveUTF8 == 0) {
        return std::wstring();
    }
    return wideString;
}

HANDLE Controller::openDirectory(const std::wstring &path)
{
    return CreateFileW(
            path.data(),
            FILE_LIST_DIRECTORY,
            FILE_SHARE_READ
            | FILE_SHARE_WRITE
            | FILE_SHARE_DELETE,
            NULL,
            OPEN_EXISTING,
            FILE_FLAG_BACKUP_SEMANTICS
            | FILE_FLAG_OVERLAPPED,
            NULL
        );
}

Controller::Controller(std::shared_ptr<EventQueue> queue, const std::string &path)
    : mDirectoryHandle(INVALID_HANDLE_VALUE)
{
    auto widePath = convertMultiByteToWideChar(path);
    mDirectoryHandle = openDirectory(widePath);

    if (mDirectoryHandle == INVALID_HANDLE_VALUE) {
        return;
    }

    mWatcher.reset(new Watcher(queue, mDirectoryHandle, widePath));
}

Controller::~Controller()
{
    mWatcher.reset();
    CancelIo(mDirectoryHandle);
    CloseHandle(mDirectoryHandle);
    mDirectoryHandle = INVALID_HANDLE_VALUE;
}

std::string Controller::getError()
{
    if (mDirectoryHandle == INVALID_HANDLE_VALUE) {
        return "Failed to open directory";
    }
    return mWatcher->getError();
}

bool Controller::hasErrored()
{
    return mDirectoryHandle == INVALID_HANDLE_VALUE || !mWatcher->getError().empty();
}

bool Controller::isWatching()
{
    return mWatcher->isRunning();
}
<commit_msg>quickfix for windows js tests<commit_after>#include "../includes/win32_2/Controller.h"

static std::wstring convertMultiByteToWideChar(const std::string &multiByte)
{
    const int wlen = MultiByteToWideChar(CP_UTF8, 0, multiByte.data(), -1, 0, 0);

    if (wlen == 0) {
        return std::wstring();
    }

    std::wstring wideString;
    wideString.resize(wlen-1);
    int failureToResolveUTF8 = MultiByteToWideChar(CP_UTF8, 0, multiByte.data(), -1, &(wideString[0]), wlen);
    if (failureToResolveUTF8 == 0) {
        return std::wstring();
    }
    return wideString;
}

HANDLE Controller::openDirectory(const std::wstring &path)
{
    return CreateFileW(
            path.data(),
            FILE_LIST_DIRECTORY,
            FILE_SHARE_READ
            | FILE_SHARE_WRITE
            | FILE_SHARE_DELETE,
            NULL,
            OPEN_EXISTING,
            FILE_FLAG_BACKUP_SEMANTICS
            | FILE_FLAG_OVERLAPPED,
            NULL
        );
}

Controller::Controller(std::shared_ptr<EventQueue> queue, const std::string &path)
    : mDirectoryHandle(INVALID_HANDLE_VALUE)
{
    auto widePath = convertMultiByteToWideChar(path);
    mDirectoryHandle = openDirectory(widePath);

    if (mDirectoryHandle == INVALID_HANDLE_VALUE) {
        return;
    }

    mWatcher.reset(new Watcher(queue, mDirectoryHandle, widePath));
}

Controller::~Controller()
{
    mWatcher.reset();
    CancelIo(mDirectoryHandle);
    CloseHandle(mDirectoryHandle);
    mDirectoryHandle = INVALID_HANDLE_VALUE;
}

std::string Controller::getError()
{
    if (mDirectoryHandle == INVALID_HANDLE_VALUE) {
        return "Failed to open directory";
    }
    return mWatcher->getError();
}

bool Controller::hasErrored()
{
    return mDirectoryHandle == INVALID_HANDLE_VALUE || !mWatcher->getError().empty();
}

bool Controller::isWatching()
{
    return mWatcher->isRunning();
}
<|endoftext|>


<commit_before>#include "BuiltinDetumbling.hpp"
#include <chrono>
#include "logger/logger.h"

using namespace std::chrono_literals;

namespace adcs
{
    constexpr std::chrono::milliseconds BuiltinDetumbling::GetWaitPeriod()
    {
        return chrono_extensions::period_cast<std::chrono::milliseconds>(BuiltinDetumbling::Frequency);
    }

    constexpr std::chrono::seconds BuiltinDetumbling::GetDetumblingPeriod()
    {
        return chrono_extensions::period_cast<std::chrono::seconds>(BuiltinDetumbling::Frequency) * 2;
    }

    BuiltinDetumbling::BuiltinDetumbling(devices::imtq::IImtqDriver& imtqDriver_) : imtqDriver(imtqDriver_)
    {
    }

    OSResult BuiltinDetumbling::Initialize()
    {
        return OSResult::Success;
    }

    OSResult BuiltinDetumbling::Enable()
    {
        return OSResult::Success;
    }

    OSResult BuiltinDetumbling::Disable()
    {
        return imtqDriver.CancelOperation() ? OSResult::Success : OSResult::IOError;
    }

    void BuiltinDetumbling::Process()
    {
        if (!imtqDriver.StartBDotDetumbling(GetDetumblingPeriod()))
        {
            LOG(LOG_LEVEL_ERROR, "Unable to run built-in detumbling");
            return;
        }

        System::SleepTask(2s);

        devices::imtq::DetumbleData result;
        if (!imtqDriver.GetDetumbleData(result))
        {
            LOG(LOG_LEVEL_ERROR, "Unable to acquire built-in detumble data");
        }

        devices::imtq::HouseKeepingEngineering housekeeping;
        if (!imtqDriver.GetHouseKeepingEngineering(housekeeping))
        {
            LOG(LOG_LEVEL_ERROR, "Unable to acquire imtq housekeeping");
        }
    }

    std::chrono::milliseconds BuiltinDetumbling::GetWait() const
    {
        return GetWaitPeriod();
    }
}
<commit_msg>[telemetry][imtq] Query itmq state in built-in detumbling mode.<commit_after>#include "BuiltinDetumbling.hpp"
#include <chrono>
#include "logger/logger.h"

using namespace std::chrono_literals;

namespace adcs
{
    constexpr std::chrono::milliseconds BuiltinDetumbling::GetWaitPeriod()
    {
        return chrono_extensions::period_cast<std::chrono::milliseconds>(BuiltinDetumbling::Frequency);
    }

    constexpr std::chrono::seconds BuiltinDetumbling::GetDetumblingPeriod()
    {
        return chrono_extensions::period_cast<std::chrono::seconds>(BuiltinDetumbling::Frequency) * 2;
    }

    BuiltinDetumbling::BuiltinDetumbling(devices::imtq::IImtqDriver& imtqDriver_) : imtqDriver(imtqDriver_)
    {
    }

    OSResult BuiltinDetumbling::Initialize()
    {
        return OSResult::Success;
    }

    OSResult BuiltinDetumbling::Enable()
    {
        return OSResult::Success;
    }

    OSResult BuiltinDetumbling::Disable()
    {
        return imtqDriver.CancelOperation() ? OSResult::Success : OSResult::IOError;
    }

    void BuiltinDetumbling::Process()
    {
        if (!imtqDriver.StartBDotDetumbling(GetDetumblingPeriod()))
        {
            LOG(LOG_LEVEL_ERROR, "Unable to run built-in detumbling");
            return;
        }

        System::SleepTask(2s);

        devices::imtq::DetumbleData result;
        if (!imtqDriver.GetDetumbleData(result))
        {
            LOG(LOG_LEVEL_ERROR, "Unable to acquire built-in detumble data");
        }

        devices::imtq::State state;
        if (!imtqDriver.GetSystemState(state))
        {
            LOG(LOG_LEVEL_ERROR, "Unable to acquire imtq state");
        }

        devices::imtq::HouseKeepingEngineering housekeeping;
        if (!imtqDriver.GetHouseKeepingEngineering(housekeeping))
        {
            LOG(LOG_LEVEL_ERROR, "Unable to acquire imtq housekeeping");
        }
    }

    std::chrono::milliseconds BuiltinDetumbling::GetWait() const
    {
        return GetWaitPeriod();
    }
}
<|endoftext|>


<commit_before>#include "lib/pool.hpp"
#include "lib/matrix.hpp"
#include "lib/image.hpp"

void conv(matrix &x, const matrix &k) {
  matrix y;
  y.create(x.rows + k.rows, x.cols + k.cols);

  for (unsigned row = 0; row < x.rows; row++) {
    for (unsigned col = 0; col < x.cols; col++) {
      auto yrow = row + k.rows / 2;
      auto ycol = col + k.cols / 2;
      y(yrow, ycol) = x(row, col);
    }
  }

  // Compute sum of k
  int weight = 0;
  for (unsigned row = 0; row < k.rows; row++) {
    for (unsigned col = 0; col < k.cols; col++) {
      weight += k(row, col);
    }
  }

  // Do the convolution
  for (unsigned row = 0; row < x.rows; row++) {
    for (unsigned col = 0; col < x.cols; col++) {
      int t = 0;

      auto yrow = row;
      for (int krow = k.rows - 1; krow >= 0; krow--, yrow++) {
        auto ycol = col;
        for (int kcol = k.cols - 1; kcol >= 0; kcol--, ycol++) {
          t += y(yrow, ycol) * k(krow, kcol);
        }
      }

      if (weight != 0) {
        t /= weight;
      }

      x(row, col) = t;
    }
  }
}

int binomial_coefficient(int n, int k) {
  if (n <= 1 || k == 0) {
    return 1;
  } else {
    return binomial_coefficient(n - 1, k - 1) * n / k;
  }
}

matrix binomial(int n) {
  if ((n & 1) == 0) {
    throw std::invalid_argument("n must be odd");
  }

  matrix x, y;
  x.create(1, n);
  y.create(n, 1);

  for (int i = 0; i < n / 2; i++) {
    x(0, i) = x(0, n - i - 1) = binomial_coefficient(n - 1, i);
    y(i, 0) = y(n - i - 1, 0) = binomial_coefficient(n - 1, i);
  }

  x(0, n / 2) = binomial_coefficient(n - 1, n / 2);
  y(n / 2, 0) = binomial_coefficient(n - 1, n / 2);

  return y * x;
}

int main(int argc, char **argv) {
  auto bmp = load_image("C:\\Users\\Joe\\Desktop\\test.jpg");
  auto orig = bmp;

  matrix kernel = binomial(1);

  conv(bmp, kernel);

  save_png(bmp, "C:\\Users\\Joe\\Desktop\\test.png");
  return 0;
}
<commit_msg>Complete convolution<commit_after>#include "lib/pool.hpp"
#include "lib/matrix.hpp"
#include "lib/image.hpp"

void conv(Pool &pool, matrix &x, const matrix &k) {
  matrix y;
  y.create(x.rows + k.rows, x.cols + k.cols);

  for (unsigned row = 0; row < x.rows; row++) {
    for (unsigned col = 0; col < x.cols; col++) {
      auto yrow = row + k.rows / 2;
      auto ycol = col + k.cols / 2;
      y(yrow, ycol) = x(row, col);
    }
  }

  // Compute sum of k
  int weight = 0;
  for (unsigned row = 0; row < k.rows; row++) {
    for (unsigned col = 0; col < k.cols; col++) {
      weight += k(row, col);
    }
  }

  // Do the convolution
  std::vector<std::future<void>> wv;
  for (unsigned row = 0; row < x.rows; row++) {
	  wv.push_back(pool.submit([row, &x, &y, &k, weight] {
		for (unsigned col = 0; col < x.cols; col++) {
		  int t = 0;

		  auto yrow = row;
		  for (int krow = k.rows - 1; krow >= 0; krow--, yrow++) {
			auto ycol = col;
			for (int kcol = k.cols - 1; kcol >= 0; kcol--, ycol++) {
			  t += y(yrow, ycol) * k(krow, kcol);
			}
		  }

		  if (weight != 0) {
			t /= weight;
		  }

		  x(row, col) = t;
		}
	  }));
  }
  for (auto it = wv.begin(); it != wv.end(); ++it) it->wait();
}

int binomial_coefficient(int n, int k) {
  if (n <= 1 || k == 0) {
    return 1;
  } else {
    return binomial_coefficient(n - 1, k - 1) * n / k;
  }
}

matrix binomial(int n) {
  if ((n & 1) == 0) {
    throw std::invalid_argument("n must be odd");
  }

  matrix x, y;
  x.create(1, n);
  y.create(n, 1);

  for (int i = 0; i < n / 2; i++) {
    x(0, i) = x(0, n - i - 1) = binomial_coefficient(n - 1, i);
    y(i, 0) = y(n - i - 1, 0) = binomial_coefficient(n - 1, i);
  }

  x(0, n / 2) = binomial_coefficient(n - 1, n / 2);
  y(n / 2, 0) = binomial_coefficient(n - 1, n / 2);

  return y * x;
}

int main(int argc, char **argv) {
	Pool pool;

  auto bmp = load_image("C:\\Users\\Joe\\Desktop\\test.jpg");
  auto orig = bmp;

  matrix kernel = binomial(1);

  conv(pool, bmp, kernel);

  save_png(bmp, "C:\\Users\\Joe\\Desktop\\test.png");
  return 0;
}
<|endoftext|>


<commit_before><commit_msg>Fix potential memleak in GetArgs.<commit_after><|endoftext|>


<commit_before>/* +------------------------------------------------------------------------+
   |                     Mobile Robot Programming Toolkit (MRPT)            |
   |                          https://www.mrpt.org/                         |
   |                                                                        |
   | Copyright (c) 2005-2022, Individual contributors, see AUTHORS file     |
   | See: https://www.mrpt.org/Authors - All rights reserved.               |
   | Released under BSD License. See: https://www.mrpt.org/License          |
   +------------------------------------------------------------------------+ */

#include <gtest/gtest.h>
#include <mrpt/opengl/CBox.h>
#include <mrpt/opengl/CFBORender.h>
#include <mrpt/opengl/CGridPlaneXY.h>
#include <mrpt/opengl/CMesh.h>
#include <mrpt/opengl/CMeshFast.h>
#include <mrpt/opengl/CSphere.h>
#include <mrpt/opengl/CText3D.h>
#include <mrpt/opengl/stock_objects.h>
#include <mrpt/system/filesystem.h>
//
#include <Eigen/Dense>
//
#include <mrpt/config.h>  // for MRPT_HAS_*
#include <test_mrpt_common.h>

static float imageDiff(
	const mrpt::img::CImage& im1, const mrpt::img::CImage& im2)
{
	mrpt::math::CMatrixFloat r1, g1, b1;
	im1.getAsRGBMatrices(r1, g1, b1);

	mrpt::math::CMatrixFloat r2, g2, b2;
	im2.getAsRGBMatrices(r2, g2, b2);

	return (r1 - r2).asEigen().array().abs().sum() +
		(g1 - g2).asEigen().array().abs().sum() +
		(b1 - b2).asEigen().array().abs().sum();
}

static void test_opengl_CFBORender(const bool useCameraFromIntrinsics)
{
	using namespace mrpt;  // _deg
	using namespace std::string_literals;  // s
	using namespace mrpt::opengl;

	const std::string expected_RGB_img_file = UNITTEST_BASEDIR +
		"/tests/CFBORender_expected_rgb_"s +
		(useCameraFromIntrinsics ? "camInt"s : "camFOV"s) + ".png"s;

	const std::string expected_depth_img_file = UNITTEST_BASEDIR +
		"/tests/CFBORender_expected_depth_"s +
		(useCameraFromIntrinsics ? "camInt"s : "camFOV"s) + ".png"s;

	COpenGLScene scene;

	{
		auto obj = mrpt::opengl::CGridPlaneXY::Create(-20, 20, -20, 20, 0, 5);
		obj->setColor(0.4f, 0.4f, 0.4f);
		scene.insert(obj);
	}
	{
		auto obj = mrpt::opengl::CBox::Create(
			mrpt::math::TPoint3D(0, 0, 0), mrpt::math::TPoint3D(.1, .1, .1));
		obj->setColor(1.0f, 0.f, 0.f);
		obj->setName("x");
		obj->enableShowName(true);
		obj->setLocation(1.0, 0, 0);
		scene.insert(obj);
	}
	{
		auto obj = mrpt::opengl::CTexturedPlane::Create();
		obj->setPlaneCorners(-10, 10, -10, 10);
		obj->setColor_u8(0x00, 0xff, 0xff, 0xff);
		obj->setLocation(0, 0, -14);
		scene.insert(obj);
	}
	{
		auto obj = mrpt::opengl::CSphere::Create();
		obj->setColor(0, 0, 1);
		obj->setRadius(1.0f);
		obj->setLocation(0, 1, 0);
		obj->setName("ball_1");
		scene.insert(obj);
	}

	{
		auto obj = mrpt::opengl::CText3D::Create("Hi there!");
		obj->setLocation(5.0, 3.0, 1.0);
		scene.insert(obj);
	}
	{
		auto obj = opengl::stock_objects::CornerXYZ(2.0f);
		obj->setLocation(-3, -2, 0.5);
		scene.insert(obj);
	}

	// CMeshFast, CMesh:
	{
		double off_x = -5.0, STEP_X = 1.0;
		opengl::CMeshFast::Ptr obj1 = opengl::CMeshFast::Create();
		opengl::CMeshFast::Ptr obj2 = opengl::CMeshFast::Create();
		opengl::CMesh::Ptr obj3 = opengl::CMesh::Create();
		opengl::CMesh::Ptr obj4 = opengl::CMesh::Create();

		obj1->setXBounds(-1, 1);
		obj1->setYBounds(-1, 1);

		const int W = 128, H = 128;

		mrpt::math::CMatrixDynamic<float> Z(H, W);

		for (int r = 0; r < H; r++)
			for (int c = 0; c < W; c++)
				Z(r, c) = sin(0.05 * (c + r) - 0.5) * cos(0.9 - 0.03 * r);

		const std::string texture_file = mrpt::system::getShareMRPTDir() +
			"datasets/sample-texture-terrain.jpg"s;

		mrpt::img::CImage im;

		// obj1:
		obj1->setZ(Z);
		obj1->enableColorFromZ(true);
		obj1->setPointSize(2.0);
		obj1->setLocation(off_x, 0, 0);
		scene.insert(obj1);

		// obj 2:
		if (im.loadFromFile(texture_file))
		{
			obj2->assignImageAndZ(im, Z);
			obj2->setPointSize(2.0);
			obj2->setLocation(off_x, 3, 0);
			scene.insert(obj2);
		}

		off_x += STEP_X;

		// obj 3:
		obj3->setZ(Z);
		obj3->enableColorFromZ(true, mrpt::img::cmJET);
		obj3->enableWireFrame(true);
		obj3->setLocation(off_x, 0, 0);
		obj3->cullFaces(mrpt::opengl::TCullFace::BACK);
		scene.insert(obj3);

		// obj 4:
		if (im.getWidth() > 1)
		{
			obj4->assignImageAndZ(im, Z);
			obj4->setLocation(off_x, 3, 0);
			obj4->cullFaces(mrpt::opengl::TCullFace::BACK);
			scene.insert(obj4);
		}
	}

	int width = 500, height = 400;
	const double cameraFOVdeg = 120.0;

	CFBORender renderer(width, height);
	mrpt::img::CImage frame(width, height, mrpt::img::CH_RGB);
	mrpt::math::CMatrixFloat depth;

	scene.getViewport()->setCustomBackgroundColor({0.3f, 0.3f, 0.3f, 1.0f});
	const float clipMax = 25.0f;
	scene.getViewport()->setViewportClipDistances(0.1, clipMax);

	{
		CCamera& camera = renderer.getCamera(scene);

		if (useCameraFromIntrinsics)
		{
			mrpt::img::TCamera c1;
			c1.ncols = width;
			c1.nrows = height;
			c1.fx(width * 0.5);
			c1.fy(width * 0.5);
			c1.cx(width / 2);
			c1.cy(height / 2);

			camera.setProjectiveFromPinhole(c1);
		}
		else
		{
			camera.setProjectiveFOVdeg(cameraFOVdeg);
		}

		// Defined by setPose() instead of orbit values:
		camera.set6DOFMode(true);

		// Reference camera pose:
		auto robotPose = mrpt::poses::CPose3D(
			0, 0, 10.0, 0.0_deg /*yaw*/, 90.0_deg /*pitch*/, 0.0_deg /*roll*/);

		// Convert to +Z pointing forward camera axes:
		auto camPose =
			robotPose +
			mrpt::poses::CPose3D::FromYawPitchRoll(
				90.0_deg /*yaw*/, 0.0_deg /*pitch*/, 90.0_deg /*roll*/);

		camera.setPose(camPose);
	}

	renderer.render_RGBD(scene, frame, depth);

	mrpt::img::CImage gt_frame;
	bool readOk_rgb = gt_frame.loadFromFile(expected_RGB_img_file);

	EXPECT_TRUE(readOk_rgb);
	const float rgb_diff = imageDiff(gt_frame, frame);
	std::cout << "rgb_diff=" << rgb_diff << "\n";
	EXPECT_LT(rgb_diff, 100.0f);

	{
		mrpt::img::CImage imDepth;
		depth *= (1.0f / clipMax);
		imDepth.setFromMatrix(depth, true);

		mrpt::img::CImage gt_imDepth;
		bool readOk_depth = gt_imDepth.loadFromFile(expected_depth_img_file);

		EXPECT_TRUE(readOk_depth);

		const float depth_diff = imageDiff(gt_imDepth, imDepth);
		std::cout << "depth_diff=" << depth_diff << "\n";
		EXPECT_LT(depth_diff, 100.0f);
	}
}

#if MRPT_HAS_OPENCV && MRPT_HAS_OPENGL_GLUT && MRPT_HAS_EGL
TEST(OpenGL, CFBORender_camera_intrinsics)
#else
TEST(OpenGL, DISABLED_CFBORender_camera_intrinsics)
#endif
{
	test_opengl_CFBORender(true);
}

#if MRPT_HAS_OPENCV && MRPT_HAS_OPENGL_GLUT && MRPT_HAS_EGL
TEST(OpenGL, CFBORender_camera_fov)
#else
TEST(OpenGL, DISABLED_CFBORender_camera_fov)
#endif
{
	test_opengl_CFBORender(false);
}
<commit_msg>adjust threshold<commit_after>/* +------------------------------------------------------------------------+
   |                     Mobile Robot Programming Toolkit (MRPT)            |
   |                          https://www.mrpt.org/                         |
   |                                                                        |
   | Copyright (c) 2005-2022, Individual contributors, see AUTHORS file     |
   | See: https://www.mrpt.org/Authors - All rights reserved.               |
   | Released under BSD License. See: https://www.mrpt.org/License          |
   +------------------------------------------------------------------------+ */

#include <gtest/gtest.h>
#include <mrpt/opengl/CBox.h>
#include <mrpt/opengl/CFBORender.h>
#include <mrpt/opengl/CGridPlaneXY.h>
#include <mrpt/opengl/CMesh.h>
#include <mrpt/opengl/CMeshFast.h>
#include <mrpt/opengl/CSphere.h>
#include <mrpt/opengl/CText3D.h>
#include <mrpt/opengl/stock_objects.h>
#include <mrpt/system/filesystem.h>
//
#include <Eigen/Dense>
//
#include <mrpt/config.h>  // for MRPT_HAS_*
#include <test_mrpt_common.h>

static float imageDiff(
	const mrpt::img::CImage& im1, const mrpt::img::CImage& im2)
{
	mrpt::math::CMatrixFloat r1, g1, b1;
	im1.getAsRGBMatrices(r1, g1, b1);

	mrpt::math::CMatrixFloat r2, g2, b2;
	im2.getAsRGBMatrices(r2, g2, b2);

	return (r1 - r2).asEigen().array().abs().sum() +
		(g1 - g2).asEigen().array().abs().sum() +
		(b1 - b2).asEigen().array().abs().sum();
}

static void test_opengl_CFBORender(const bool useCameraFromIntrinsics)
{
	using namespace mrpt;  // _deg
	using namespace std::string_literals;  // s
	using namespace mrpt::opengl;

	const std::string expected_RGB_img_file = UNITTEST_BASEDIR +
		"/tests/CFBORender_expected_rgb_"s +
		(useCameraFromIntrinsics ? "camInt"s : "camFOV"s) + ".png"s;

	const std::string expected_depth_img_file = UNITTEST_BASEDIR +
		"/tests/CFBORender_expected_depth_"s +
		(useCameraFromIntrinsics ? "camInt"s : "camFOV"s) + ".png"s;

	COpenGLScene scene;

	{
		auto obj = mrpt::opengl::CGridPlaneXY::Create(-20, 20, -20, 20, 0, 5);
		obj->setColor(0.4f, 0.4f, 0.4f);
		scene.insert(obj);
	}
	{
		auto obj = mrpt::opengl::CBox::Create(
			mrpt::math::TPoint3D(0, 0, 0), mrpt::math::TPoint3D(.1, .1, .1));
		obj->setColor(1.0f, 0.f, 0.f);
		obj->setName("x");
		obj->enableShowName(true);
		obj->setLocation(1.0, 0, 0);
		scene.insert(obj);
	}
	{
		auto obj = mrpt::opengl::CTexturedPlane::Create();
		obj->setPlaneCorners(-10, 10, -10, 10);
		obj->setColor_u8(0x00, 0xff, 0xff, 0xff);
		obj->setLocation(0, 0, -14);
		scene.insert(obj);
	}
	{
		auto obj = mrpt::opengl::CSphere::Create();
		obj->setColor(0, 0, 1);
		obj->setRadius(1.0f);
		obj->setLocation(0, 1, 0);
		obj->setName("ball_1");
		scene.insert(obj);
	}

	{
		auto obj = mrpt::opengl::CText3D::Create("Hi there!");
		obj->setLocation(5.0, 3.0, 1.0);
		scene.insert(obj);
	}
	{
		auto obj = opengl::stock_objects::CornerXYZ(2.0f);
		obj->setLocation(-3, -2, 0.5);
		scene.insert(obj);
	}

	// CMeshFast, CMesh:
	{
		double off_x = -5.0, STEP_X = 1.0;
		opengl::CMeshFast::Ptr obj1 = opengl::CMeshFast::Create();
		opengl::CMeshFast::Ptr obj2 = opengl::CMeshFast::Create();
		opengl::CMesh::Ptr obj3 = opengl::CMesh::Create();
		opengl::CMesh::Ptr obj4 = opengl::CMesh::Create();

		obj1->setXBounds(-1, 1);
		obj1->setYBounds(-1, 1);

		const int W = 128, H = 128;

		mrpt::math::CMatrixDynamic<float> Z(H, W);

		for (int r = 0; r < H; r++)
			for (int c = 0; c < W; c++)
				Z(r, c) = sin(0.05 * (c + r) - 0.5) * cos(0.9 - 0.03 * r);

		const std::string texture_file = mrpt::system::getShareMRPTDir() +
			"datasets/sample-texture-terrain.jpg"s;

		mrpt::img::CImage im;

		// obj1:
		obj1->setZ(Z);
		obj1->enableColorFromZ(true);
		obj1->setPointSize(2.0);
		obj1->setLocation(off_x, 0, 0);
		scene.insert(obj1);

		// obj 2:
		if (im.loadFromFile(texture_file))
		{
			obj2->assignImageAndZ(im, Z);
			obj2->setPointSize(2.0);
			obj2->setLocation(off_x, 3, 0);
			scene.insert(obj2);
		}

		off_x += STEP_X;

		// obj 3:
		obj3->setZ(Z);
		obj3->enableColorFromZ(true, mrpt::img::cmJET);
		obj3->enableWireFrame(true);
		obj3->setLocation(off_x, 0, 0);
		obj3->cullFaces(mrpt::opengl::TCullFace::BACK);
		scene.insert(obj3);

		// obj 4:
		if (im.getWidth() > 1)
		{
			obj4->assignImageAndZ(im, Z);
			obj4->setLocation(off_x, 3, 0);
			obj4->cullFaces(mrpt::opengl::TCullFace::BACK);
			scene.insert(obj4);
		}
	}

	int width = 500, height = 400;
	const double cameraFOVdeg = 120.0;

	CFBORender renderer(width, height);
	mrpt::img::CImage frame(width, height, mrpt::img::CH_RGB);
	mrpt::math::CMatrixFloat depth;

	scene.getViewport()->setCustomBackgroundColor({0.3f, 0.3f, 0.3f, 1.0f});
	const float clipMax = 25.0f;
	scene.getViewport()->setViewportClipDistances(0.1, clipMax);

	{
		CCamera& camera = renderer.getCamera(scene);

		if (useCameraFromIntrinsics)
		{
			mrpt::img::TCamera c1;
			c1.ncols = width;
			c1.nrows = height;
			c1.fx(width * 0.5);
			c1.fy(width * 0.5);
			c1.cx(width / 2);
			c1.cy(height / 2);

			camera.setProjectiveFromPinhole(c1);
		}
		else
		{
			camera.setProjectiveFOVdeg(cameraFOVdeg);
		}

		// Defined by setPose() instead of orbit values:
		camera.set6DOFMode(true);

		// Reference camera pose:
		auto robotPose = mrpt::poses::CPose3D(
			0, 0, 10.0, 0.0_deg /*yaw*/, 90.0_deg /*pitch*/, 0.0_deg /*roll*/);

		// Convert to +Z pointing forward camera axes:
		auto camPose =
			robotPose +
			mrpt::poses::CPose3D::FromYawPitchRoll(
				90.0_deg /*yaw*/, 0.0_deg /*pitch*/, 90.0_deg /*roll*/);

		camera.setPose(camPose);
	}

	renderer.render_RGBD(scene, frame, depth);

	mrpt::img::CImage gt_frame;
	bool readOk_rgb = gt_frame.loadFromFile(expected_RGB_img_file);

	EXPECT_TRUE(readOk_rgb);

	const float rgb_diff = imageDiff(gt_frame, frame);
	std::cout << "rgb_diff=" << rgb_diff << "\n";
	EXPECT_LT(rgb_diff, 5000.0f);

	{
		mrpt::img::CImage imDepth;
		depth *= (1.0f / clipMax);
		imDepth.setFromMatrix(depth, true);

		mrpt::img::CImage gt_imDepth;
		bool readOk_depth = gt_imDepth.loadFromFile(expected_depth_img_file);

		EXPECT_TRUE(readOk_depth);

		const float depth_diff = imageDiff(gt_imDepth, imDepth);
		std::cout << "depth_diff=" << depth_diff << "\n";
		EXPECT_LT(depth_diff, 3000.0f);
	}
}

#if MRPT_HAS_OPENCV && MRPT_HAS_OPENGL_GLUT && MRPT_HAS_EGL
TEST(OpenGL, CFBORender_camera_intrinsics)
#else
TEST(OpenGL, DISABLED_CFBORender_camera_intrinsics)
#endif
{
	test_opengl_CFBORender(true);
}

#if MRPT_HAS_OPENCV && MRPT_HAS_OPENGL_GLUT && MRPT_HAS_EGL
TEST(OpenGL, CFBORender_camera_fov)
#else
TEST(OpenGL, DISABLED_CFBORender_camera_fov)
#endif
{
	test_opengl_CFBORender(false);
}
<|endoftext|>


<commit_before>#include "SkinInfo.h"

#include "Logger.h"
#include "Settings.h"
#include "StringUtils.h"

SkinInfo::SkinInfo(std::wstring skinFile) :
_skinFile(skinFile) {
    CLOG(L"Loading skin XML: %s", _skinFile.c_str());

    /* Remove the '/skin.xml' portion from the file name to get the dir name. */
    std::wstring xmlName = std::wstring(SKIN_XML);
    _skinDir = _skinFile.substr(0, _skinFile.length() - (xmlName.length() + 1));

    std::string u8FileName = StringUtils::Narrow(_skinFile);
    tinyxml2::XMLError result = _xml.LoadFile(u8FileName.c_str());
    if (result != tinyxml2::XMLError::XML_SUCCESS) {
        throw std::logic_error("Failed to read XML file!");
    }

    _root = _xml.GetDocument()->FirstChildElement("skin");
    if (_root == NULL) {
        throw std::runtime_error("Could not find root XML element");
    }
}

std::wstring SkinInfo::Author() {
    tinyxml2::XMLHandle xmlHandle(_root);
    tinyxml2::XMLElement *author = xmlHandle
        .FirstChildElement("info")
        .FirstChildElement("author")
        .ToElement();

    const char *authorText;
    if (author == NULL || (authorText = author->GetText()) == NULL) {
        return L"";
    }

    return std::wstring(StringUtils::Widen(authorText));
}

std::wstring SkinInfo::URL() {
    tinyxml2::XMLHandle xmlHandle(_root);
    tinyxml2::XMLElement *site = xmlHandle
        .FirstChildElement("info")
        .FirstChildElement("website")
        .ToElement();

    const char *text;
    if (site == NULL || (text = site->GetText()) == NULL) {
        return L"";
    }
    return std::wstring(StringUtils::Widen(text));
}<commit_msg>Show message box when we can't find the skin<commit_after>#include "SkinInfo.h"

#include "Logger.h"
#include "Settings.h"
#include "StringUtils.h"

SkinInfo::SkinInfo(std::wstring skinFile) :
_skinFile(skinFile) {
    CLOG(L"Loading skin XML: %s", _skinFile.c_str());

    /* Remove the '/skin.xml' portion from the file name to get the dir name. */
    std::wstring xmlName = std::wstring(SKIN_XML);
    _skinDir = _skinFile.substr(0, _skinFile.length() - (xmlName.length() + 1));

    std::string u8FileName = StringUtils::Narrow(_skinFile);
    tinyxml2::XMLError result = _xml.LoadFile(u8FileName.c_str());
    if (result != tinyxml2::XMLError::XML_SUCCESS) {
        if (result == tinyxml2::XMLError::XML_ERROR_FILE_NOT_FOUND) {
            std::wstring info = L"Could not find skin:\n\n";
            info += skinFile;
            MessageBox(NULL, info.c_str(), L"Skin Error", MB_ICONERROR);
        }
        throw std::logic_error("Failed to read XML file!");
    }

    _root = _xml.GetDocument()->FirstChildElement("skin");
    if (_root == NULL) {
        throw std::runtime_error("Could not find root XML element");
    }
}

std::wstring SkinInfo::Author() {
    tinyxml2::XMLHandle xmlHandle(_root);
    tinyxml2::XMLElement *author = xmlHandle
        .FirstChildElement("info")
        .FirstChildElement("author")
        .ToElement();

    const char *authorText;
    if (author == NULL || (authorText = author->GetText()) == NULL) {
        return L"";
    }

    return std::wstring(StringUtils::Widen(authorText));
}

std::wstring SkinInfo::URL() {
    tinyxml2::XMLHandle xmlHandle(_root);
    tinyxml2::XMLElement *site = xmlHandle
        .FirstChildElement("info")
        .FirstChildElement("website")
        .ToElement();

    const char *text;
    if (site == NULL || (text = site->GetText()) == NULL) {
        return L"";
    }
    return std::wstring(StringUtils::Widen(text));
}<|endoftext|>


<commit_before>#include <QtCore/QJsonDocument>
#include <QtCore/QJsonArray>
#include <QtCore/QJsonObject>
#include <QtCore/QFile>

#include "trikKitInterpreterCommon/trikQtsInterpreter.h"

#include "qrgui/plugins/toolPluginInterface/usedInterfaces/errorReporterInterface.h"

#include <twoDModel/engine/model/timeline.h>

#include <QDebug>

const QString overrides = "script.random = brick.random;script.wait = brick.wait;script.time = brick.time;\n"
		"script.readAll = brick.readAll;\n"
		"print = function() {var res = '';\n"
		"for(var i = 0; i < arguments.length; i++) {res += arguments[i].toString();}\n"
		"brick.log(res);return res;};\n"
		"script.system = function() {print('system is disabled in the interpreter');};";

trik::TrikQtsInterpreter::TrikQtsInterpreter(
        const QSharedPointer<trik::robotModel::twoD::TrikTwoDRobotModel> &model
		) : mRunning(false), mBrick(model), mScriptRunner(mBrick, nullptr), mErrorReporter(nullptr)
{
	connect(&mBrick, &TrikBrick::error, this, &TrikQtsInterpreter::reportError);
//	mScriptRunner.registerUserFunction("print", printRedirect);
//	connect(&mBrick, &TrikBrick::log, [this](const QString &msg){
//		QMetaObject::invokeMethod(this, "reportLog", Q_ARG(const QString &, msg));
//	});
//	auto redirectPrint = [](QScriptContext * ctx, QScriptEngine * eng) -> QScriptValue {
//		const auto txt = ctx->argument(0).toString();
//		eng->globalObject().property("brick").
//		return QScriptValue();
//	};
	//auto &t = dynamic_cast<twoDModel::model::Timeline &>(model->timeline());
	//t.setImmediateMode(true);
	connect(&mScriptRunner, SIGNAL(completed(QString,int)), this, SLOT(scriptFinished(QString,int)));
}

trik::TrikQtsInterpreter::~TrikQtsInterpreter()
{
	abort();
}

void trik::TrikQtsInterpreter::interpretCommand(const QString &script)
{
	mScriptRunner.runDirectCommand(script);
}

void trik::TrikQtsInterpreter::interpretScript(const QString &script)
{
	mRunning = true;
	mScriptRunner.run(overrides + script);
}

void trik::TrikQtsInterpreter::interpretScriptExercise(const QString &script, const QString &inputs)
{
	mRunning = true;
	mBrick.setCurrentInputs(inputs);
	QString newScript = overrides + "script.writeToFile = null;\n" + script;
	//qDebug() << newScript;
	mScriptRunner.run(newScript);
}

void trik::TrikQtsInterpreter::abort()
{
	//mScriptRunner.abort();
	mBrick.stopWaiting();
	QMetaObject::invokeMethod(&mScriptRunner, "abort"); // just a wild test
	mRunning = false; // reset brick?
}

void trik::TrikQtsInterpreter::init()
{
	mBrick.init(); // very crucial. Maybe move into interpret methods?
}

void trik::TrikQtsInterpreter::setErrorReporter(qReal::ErrorReporterInterface &errorReporter)
{
	mErrorReporter = &errorReporter;
}

bool trik::TrikQtsInterpreter::isRunning() const
{
	return mRunning;
}

void trik::TrikQtsInterpreter::reportError(const QString &msg)
{
	mErrorReporter->addError(msg);
//	mBrick.abort(); what if there are more errors?
}

void trik::TrikQtsInterpreter::reportLog(const QString &msg)
{
	mErrorReporter->addInformation("log: " + msg);
}

QString trik::TrikQtsInterpreter::initInputs(const QString &inputs) const
{
	auto jsValToStr = [this](const QJsonValue &val) -> QString {
		switch (val.type()) {
		case QJsonValue::Bool:
			return val.toBool() ? "true" : "false";
		case QJsonValue::Double:
			return QString::number(val.Double);//maybe increase precision
		case QJsonValue::String:
			return QString("\"%1\"").arg(val.toString());
		case QJsonValue::Array:
			return QString(QJsonDocument(val.toArray()).toJson(QJsonDocument::Compact));
		case QJsonValue::Object:
			return QString(QJsonDocument(val.toObject()).toJson(QJsonDocument::Compact));
		default:
			mErrorReporter->addError(QObject::tr("Bogus input values"));
			return "";
		}
	};

	QString result;
	if (!inputs.isEmpty()) {
		QString val;
		QFile file;
		file.setFileName(inputs);
		if (file.open(QIODevice::ReadOnly)) {
			val = file.readAll();
			file.close();
			QJsonDocument document = QJsonDocument::fromJson(val.toUtf8());
			QJsonObject object = document.object();
			for (const QString &name : object.keys()) {
				QJsonValue value = object[name];
				QString valueStr = jsValToStr(value);
				QString line("var " + name + " = " + valueStr + ";\n");
				result.append(line);
			}
		} else {
			mErrorReporter->addError(QObject::tr("Error: File %1 couldn't be opened!").arg(inputs));
		}
	}
	return result;
}

void trik::TrikQtsInterpreter::setRunning(bool running)
{
	mRunning = running;
}

void trik::TrikQtsInterpreter::setCurrentDir(const QString &dir)
{
	mBrick.setCurrentDir(dir);
}

QStringList trik::TrikQtsInterpreter::supportedRobotModelNames() const
{
	return {"TwoDRobotModelForTrikV62RealRobotModel", "TwoDRobotModelForTrikV6RealRobotModel"};
}

void trik::TrikQtsInterpreter::scriptFinished(const QString &error, int scriptId)
{
	Q_UNUSED(scriptId);
	if (!error.isEmpty()) {
		reportError(error);
	}
	if (mRunning) { /// @todo: figure out better place for this check - it should avoid double aborts
		mRunning = false;
		emit completed();
	}
}
<commit_msg>Fixed reporting incorrect JS error position<commit_after>#include <QtCore/QJsonDocument>
#include <QtCore/QJsonArray>
#include <QtCore/QJsonObject>
#include <QtCore/QFile>

#include "trikKitInterpreterCommon/trikQtsInterpreter.h"

#include "qrgui/plugins/toolPluginInterface/usedInterfaces/errorReporterInterface.h"

#include <twoDModel/engine/model/timeline.h>

#include <QDebug>

const QString overrides = "script.random = brick.random;script.wait = brick.wait;script.time = brick.time;"
		"script.readAll = brick.readAll;"
		"print = function() {var res = '';"
		"for(var i = 0; i < arguments.length; i++) {res += arguments[i].toString();}"
		"brick.log(res);return res;};"
		"script.system = function() {print('system is disabled in the interpreter');};";

trik::TrikQtsInterpreter::TrikQtsInterpreter(
        const QSharedPointer<trik::robotModel::twoD::TrikTwoDRobotModel> &model
		) : mRunning(false), mBrick(model), mScriptRunner(mBrick, nullptr), mErrorReporter(nullptr)
{
	connect(&mBrick, &TrikBrick::error, this, &TrikQtsInterpreter::reportError);
//	mScriptRunner.registerUserFunction("print", printRedirect);
//	connect(&mBrick, &TrikBrick::log, [this](const QString &msg){
//		QMetaObject::invokeMethod(this, "reportLog", Q_ARG(const QString &, msg));
//	});
//	auto redirectPrint = [](QScriptContext * ctx, QScriptEngine * eng) -> QScriptValue {
//		const auto txt = ctx->argument(0).toString();
//		eng->globalObject().property("brick").
//		return QScriptValue();
//	};
	//auto &t = dynamic_cast<twoDModel::model::Timeline &>(model->timeline());
	//t.setImmediateMode(true);
	connect(&mScriptRunner, SIGNAL(completed(QString,int)), this, SLOT(scriptFinished(QString,int)));
}

trik::TrikQtsInterpreter::~TrikQtsInterpreter()
{
	abort();
}

void trik::TrikQtsInterpreter::interpretCommand(const QString &script)
{
	mScriptRunner.runDirectCommand(script);
}

void trik::TrikQtsInterpreter::interpretScript(const QString &script)
{
	mRunning = true;
	mScriptRunner.run(overrides + script);
}

void trik::TrikQtsInterpreter::interpretScriptExercise(const QString &script, const QString &inputs)
{
	mRunning = true;
	mBrick.setCurrentInputs(inputs);
	QString newScript = overrides + "script.writeToFile = null;\n" + script;
	//qDebug() << newScript;
	mScriptRunner.run(newScript);
}

void trik::TrikQtsInterpreter::abort()
{
	//mScriptRunner.abort();
	mBrick.stopWaiting();
	QMetaObject::invokeMethod(&mScriptRunner, "abort"); // just a wild test
	mRunning = false; // reset brick?
}

void trik::TrikQtsInterpreter::init()
{
	mBrick.init(); // very crucial. Maybe move into interpret methods?
}

void trik::TrikQtsInterpreter::setErrorReporter(qReal::ErrorReporterInterface &errorReporter)
{
	mErrorReporter = &errorReporter;
}

bool trik::TrikQtsInterpreter::isRunning() const
{
	return mRunning;
}

void trik::TrikQtsInterpreter::reportError(const QString &msg)
{
	mErrorReporter->addError(msg);
//	mBrick.abort(); what if there are more errors?
}

void trik::TrikQtsInterpreter::reportLog(const QString &msg)
{
	mErrorReporter->addInformation("log: " + msg);
}

QString trik::TrikQtsInterpreter::initInputs(const QString &inputs) const
{
	auto jsValToStr = [this](const QJsonValue &val) -> QString {
		switch (val.type()) {
		case QJsonValue::Bool:
			return val.toBool() ? "true" : "false";
		case QJsonValue::Double:
			return QString::number(val.Double);//maybe increase precision
		case QJsonValue::String:
			return QString("\"%1\"").arg(val.toString());
		case QJsonValue::Array:
			return QString(QJsonDocument(val.toArray()).toJson(QJsonDocument::Compact));
		case QJsonValue::Object:
			return QString(QJsonDocument(val.toObject()).toJson(QJsonDocument::Compact));
		default:
			mErrorReporter->addError(QObject::tr("Bogus input values"));
			return "";
		}
	};

	QString result;
	if (!inputs.isEmpty()) {
		QString val;
		QFile file;
		file.setFileName(inputs);
		if (file.open(QIODevice::ReadOnly)) {
			val = file.readAll();
			file.close();
			QJsonDocument document = QJsonDocument::fromJson(val.toUtf8());
			QJsonObject object = document.object();
			for (const QString &name : object.keys()) {
				QJsonValue value = object[name];
				QString valueStr = jsValToStr(value);
				QString line("var " + name + " = " + valueStr + ";\n");
				result.append(line);
			}
		} else {
			mErrorReporter->addError(QObject::tr("Error: File %1 couldn't be opened!").arg(inputs));
		}
	}
	return result;
}

void trik::TrikQtsInterpreter::setRunning(bool running)
{
	mRunning = running;
}

void trik::TrikQtsInterpreter::setCurrentDir(const QString &dir)
{
	mBrick.setCurrentDir(dir);
}

QStringList trik::TrikQtsInterpreter::supportedRobotModelNames() const
{
	return {"TwoDRobotModelForTrikV62RealRobotModel", "TwoDRobotModelForTrikV6RealRobotModel"};
}

void trik::TrikQtsInterpreter::scriptFinished(const QString &error, int scriptId)
{
	Q_UNUSED(scriptId);
	if (!error.isEmpty()) {
		reportError(error);
	}
	if (mRunning) { /// @todo: figure out better place for this check - it should avoid double aborts
		mRunning = false;
		emit completed();
	}
}
<|endoftext|>


<commit_before>/*
 * Jamoma RampUnit: scheduler
 * Ramping function using the Max scheduler
 *
 * By Tim Place, Copyright � 2006, 2007
 *
 * License: This code is licensed under the terms of the GNU LGPL
 * http://www.gnu.org/licenses/lgpl.html
 */

#include "Jamoma.h"
#include "scheduler.h"

static t_symbol *ps_granularity;
static t_symbol *ps_clock;

t_scheduler*	create(rampunit_method_callback_type in_callback, void *in_baton)
{
	t_atom	*argv;

	t_scheduler *rampunit = (t_scheduler *)malloc(sizeof(t_scheduler));
	if(rampunit){
		ps_granularity = gensym("granularity");							// cache attr names for speed
		ps_clock = gensym("clock");

		rampunit->callback = in_callback;
		rampunit->baton = in_baton;
		rampunit->max_clock = clock_new(rampunit, (method)&tick);		// install the max timer
		rampunit->numvalues = 0;
		rampunit->value_current = NULL;
		rampunit->value_target = NULL;
		rampunit->stepsize = NULL;
		rampunit->function = NULL;
		rampunit->functionName = NULL;
		setnumvalues(rampunit, 1);
		rampunit->value_current[0] = 0;

		atom_setfloat(argv,20.0);
		attrset(rampunit, ps_granularity, 1, argv);
		setFunction(rampunit, gensym("linear"));
	}
	return rampunit;
}

void destroy(t_scheduler *rampunit)
{
	clock_unset(rampunit->max_clock);
	freeobject((t_object *)rampunit->max_clock);
	free(rampunit->value_current);
	free(rampunit->value_target);
	free(rampunit->value_start);
	if(rampunit->function)
		delete rampunit->function;
	free(rampunit);
}

JamomaError setFunction(t_scheduler *rampunit, t_symbol *functionName)
{
	JamomaError	err = JAMOMA_ERR_NONE;
	if(functionName != rampunit->functionName){
		err = jamoma_getFunction(functionName, &rampunit->function);
		if(!err){
			rampunit->functionName = functionName;
		}
	}
	return err;
}

JamomaError getFunction(t_scheduler *rampunit, t_symbol **functionName)
{
	*functionName = rampunit->functionName;
	return JAMOMA_ERR_NONE;
}

JamomaError setFunctionParameter(t_scheduler *rampunit, t_symbol *parameterName, long argc, t_atom *argv)
{
	return rampunit->function->setParameter(parameterName, argc, argv);
}

JamomaError getFunctionParameter(t_scheduler *rampunit, t_symbol *parameterName, long *argc, t_atom **argv)
{
	return rampunit->function->getParameter(parameterName, argc, argv);
}

ramp_err attrset(t_scheduler *rampunit, t_symbol *attrname, long argc, t_atom *argv)
{
	if(attrname == ps_granularity)
		{
			if (argc)
				rampunit->granularity = atom_getfloat(argv);
			// Should there be a minimum threshold for granularity?
		}
	else if (attrname == ps_clock) {
		// The below copied from the SDK

		/*
		void *old = x->m_setclock->s_thing;
		void *c = 0;
		*/

		/* the line below can be restated as:
		if s is the empty symbol
		or s->s_thing is zero
		or s->s_thing is non-zero and a setclock object
		*/
		/*
		if ((s == gensym("")) || ((c = s->s_thing) && zgetfn(c,&s_unset)))
		{
			if (old)
				setclock_unset(old,x->m_clock);
			x->m_setclock = s; 						// s is a t_symbol *
			if (x->m_running)
				setclock_delay(c,x->m_clock,0L);
		}
		*/
		post("Tutten betutten");
	}

	else
		return RAMP_ERR_ATTR_INVALID;

	return RAMP_ERR_NONE;
}

ramp_err attrget(t_scheduler *rampunit, t_symbol *attrname, long *argc, t_atom **argv)
{
	if(attrname == ps_granularity) {
		*argv = (t_atom*)sysmem_newptr(sizeof(t_atom));
		*argc = 1;
		atom_setfloat(*argv,rampunit->granularity);
	}
	else if (attrname == ps_clock) {
		// something
	}
	else {
		*argc = 0;
		return RAMP_ERR_ATTR_INVALID;
	}

	return RAMP_ERR_NONE;
}

//void go(t_scheduler *rampunit, float value, double time)
void go(t_scheduler *rampunit, short numvalues, double *values, double time)
{
	short	i;

	rampunit->ramptime = time;
	rampunit->numgrains = rampunit->ramptime / rampunit->granularity;
	rampunit->stepsize = 1.0 / rampunit->numgrains;

	setnumvalues(rampunit, numvalues);
	for(i=0; i<numvalues; i++){
		rampunit->value_target[i] = values[i];
		rampunit->value_start[i] = rampunit->value_current[i];
	}
	rampunit->value = 0.0;							// set the ramp to the beginning
	setclock_fdelay(NULL, rampunit->max_clock, 0);	// start now
}

//void set(t_scheduler *rampunit, double value)
void set(t_scheduler *rampunit, short numvalues, double *values)
{
	short i;

	clock_unset(rampunit->max_clock);
	setnumvalues(rampunit, numvalues);
	for(i=0; i<numvalues; i++)
		rampunit->value_current[i] = values[i];
}

void stop(t_scheduler *rampunit)
{
	clock_unset(rampunit->max_clock);
}

void tick(t_scheduler *rampunit)
{
	short	i;
	double	mapped;
	double	*current = rampunit->value_current;
	double	*target = rampunit->value_target;
	double	*start = rampunit->value_start;

	// 1. go to the the next step in our ramp
	rampunit->numgrains--;
	if(rampunit->numgrains == 0){
		for(i=0; i < rampunit->numvalues; i++)
			rampunit->value_current[i] = rampunit->value_target[i];
	}
	else{
		rampunit->value += rampunit->stepsize;
		mapped = rampunit->function->mapValue(rampunit->value);
		for(i=0; i < rampunit->numvalues; i++)
			current[i] = start[i] + ((target[i] - start[i]) * mapped);
	}

	// 2. send the value to the host
	(rampunit->callback)(rampunit->baton, rampunit->numvalues, rampunit->value_current);

	// 3. set the clock to fire again
	if(rampunit->numgrains)
		setclock_fdelay(NULL, rampunit->max_clock, rampunit->granularity);
}

// PRIVATE METHOD: memory allocation
void setnumvalues(t_scheduler *rampunit, short numvalues)
{
	if(numvalues != rampunit->numvalues){
		if(rampunit->numvalues == 0){
			rampunit->value_start = (double *)malloc(numvalues * sizeof(double));
			rampunit->value_current = (double *)malloc(numvalues * sizeof(double));
			rampunit->value_target = (double *)malloc(numvalues * sizeof(double));
		}
		else{
			rampunit->value_start = (double *)realloc(rampunit->value_start, numvalues * sizeof(double));
			rampunit->value_current = (double *)realloc(rampunit->value_current, numvalues * sizeof(double));
			rampunit->value_target = (double *)realloc(rampunit->value_target, numvalues * sizeof(double));
		}
		rampunit->numvalues = numvalues;
	}
}

<commit_msg>make argv a local variable instead of a pointer, prevents us from writing to some arbitrary memory address, fixes crashes reported by Tim<commit_after>/*
 * Jamoma RampUnit: scheduler
 * Ramping function using the Max scheduler
 *
 * By Tim Place, Copyright � 2006, 2007
 *
 * License: This code is licensed under the terms of the GNU LGPL
 * http://www.gnu.org/licenses/lgpl.html
 */

#include "Jamoma.h"
#include "scheduler.h"

static t_symbol *ps_granularity;
static t_symbol *ps_clock;

t_scheduler*	create(rampunit_method_callback_type in_callback, void *in_baton)
{
	t_atom argv;

	t_scheduler *rampunit = (t_scheduler *)malloc(sizeof(t_scheduler));
	if(rampunit){
		ps_granularity = gensym("granularity");							// cache attr names for speed
		ps_clock = gensym("clock");

		rampunit->callback = in_callback;
		rampunit->baton = in_baton;
		rampunit->max_clock = clock_new(rampunit, (method)&tick);		// install the max timer
		rampunit->numvalues = 0;
		rampunit->value_current = NULL;
		rampunit->value_target = NULL;
		rampunit->stepsize = NULL;
		rampunit->function = NULL;
		rampunit->functionName = NULL;
		setnumvalues(rampunit, 1);
		rampunit->value_current[0] = 0;

		atom_setfloat(&argv,20.0);
		attrset(rampunit, ps_granularity, 1, &argv);
		setFunction(rampunit, gensym("linear"));
	}
	return rampunit;
}

void destroy(t_scheduler *rampunit)
{
	clock_unset(rampunit->max_clock);
	freeobject((t_object *)rampunit->max_clock);
	free(rampunit->value_current);
	free(rampunit->value_target);
	free(rampunit->value_start);
	if(rampunit->function)
		delete rampunit->function;
	free(rampunit);
}

JamomaError setFunction(t_scheduler *rampunit, t_symbol *functionName)
{
	JamomaError	err = JAMOMA_ERR_NONE;
	if(functionName != rampunit->functionName){
		err = jamoma_getFunction(functionName, &rampunit->function);
		if(!err){
			rampunit->functionName = functionName;
		}
	}
	return err;
}

JamomaError getFunction(t_scheduler *rampunit, t_symbol **functionName)
{
	*functionName = rampunit->functionName;
	return JAMOMA_ERR_NONE;
}

JamomaError setFunctionParameter(t_scheduler *rampunit, t_symbol *parameterName, long argc, t_atom *argv)
{
	return rampunit->function->setParameter(parameterName, argc, argv);
}

JamomaError getFunctionParameter(t_scheduler *rampunit, t_symbol *parameterName, long *argc, t_atom **argv)
{
	return rampunit->function->getParameter(parameterName, argc, argv);
}

ramp_err attrset(t_scheduler *rampunit, t_symbol *attrname, long argc, t_atom *argv)
{
	if(attrname == ps_granularity)
		{
			if (argc)
				rampunit->granularity = atom_getfloat(argv);
			// Should there be a minimum threshold for granularity?
		}
	else if (attrname == ps_clock) {
		// The below copied from the SDK

		/*
		void *old = x->m_setclock->s_thing;
		void *c = 0;
		*/

		/* the line below can be restated as:
		if s is the empty symbol
		or s->s_thing is zero
		or s->s_thing is non-zero and a setclock object
		*/
		/*
		if ((s == gensym("")) || ((c = s->s_thing) && zgetfn(c,&s_unset)))
		{
			if (old)
				setclock_unset(old,x->m_clock);
			x->m_setclock = s; 						// s is a t_symbol *
			if (x->m_running)
				setclock_delay(c,x->m_clock,0L);
		}
		*/
		post("Tutten betutten");
	}

	else
		return RAMP_ERR_ATTR_INVALID;

	return RAMP_ERR_NONE;
}

ramp_err attrget(t_scheduler *rampunit, t_symbol *attrname, long *argc, t_atom **argv)
{
	if(attrname == ps_granularity) {
		*argv = (t_atom*)sysmem_newptr(sizeof(t_atom));
		*argc = 1;
		atom_setfloat(*argv,rampunit->granularity);
	}
	else if (attrname == ps_clock) {
		// something
	}
	else {
		*argc = 0;
		return RAMP_ERR_ATTR_INVALID;
	}

	return RAMP_ERR_NONE;
}

//void go(t_scheduler *rampunit, float value, double time)
void go(t_scheduler *rampunit, short numvalues, double *values, double time)
{
	short	i;

	rampunit->ramptime = time;
	rampunit->numgrains = rampunit->ramptime / rampunit->granularity;
	rampunit->stepsize = 1.0 / rampunit->numgrains;

	setnumvalues(rampunit, numvalues);
	for(i=0; i<numvalues; i++){
		rampunit->value_target[i] = values[i];
		rampunit->value_start[i] = rampunit->value_current[i];
	}
	rampunit->value = 0.0;							// set the ramp to the beginning
	setclock_fdelay(NULL, rampunit->max_clock, 0);	// start now
}

//void set(t_scheduler *rampunit, double value)
void set(t_scheduler *rampunit, short numvalues, double *values)
{
	short i;

	clock_unset(rampunit->max_clock);
	setnumvalues(rampunit, numvalues);
	for(i=0; i<numvalues; i++)
		rampunit->value_current[i] = values[i];
}

void stop(t_scheduler *rampunit)
{
	clock_unset(rampunit->max_clock);
}

void tick(t_scheduler *rampunit)
{
	short	i;
	double	mapped;
	double	*current = rampunit->value_current;
	double	*target = rampunit->value_target;
	double	*start = rampunit->value_start;

	// 1. go to the the next step in our ramp
	rampunit->numgrains--;
	if(rampunit->numgrains == 0){
		for(i=0; i < rampunit->numvalues; i++)
			rampunit->value_current[i] = rampunit->value_target[i];
	}
	else{
		rampunit->value += rampunit->stepsize;
		mapped = rampunit->function->mapValue(rampunit->value);
		for(i=0; i < rampunit->numvalues; i++)
			current[i] = start[i] + ((target[i] - start[i]) * mapped);
	}

	// 2. send the value to the host
	(rampunit->callback)(rampunit->baton, rampunit->numvalues, rampunit->value_current);

	// 3. set the clock to fire again
	if(rampunit->numgrains)
		setclock_fdelay(NULL, rampunit->max_clock, rampunit->granularity);
}

// PRIVATE METHOD: memory allocation
void setnumvalues(t_scheduler *rampunit, short numvalues)
{
	if(numvalues != rampunit->numvalues){
		if(rampunit->numvalues == 0){
			rampunit->value_start = (double *)malloc(numvalues * sizeof(double));
			rampunit->value_current = (double *)malloc(numvalues * sizeof(double));
			rampunit->value_target = (double *)malloc(numvalues * sizeof(double));
		}
		else{
			rampunit->value_start = (double *)realloc(rampunit->value_start, numvalues * sizeof(double));
			rampunit->value_current = (double *)realloc(rampunit->value_current, numvalues * sizeof(double));
			rampunit->value_target = (double *)realloc(rampunit->value_target, numvalues * sizeof(double));
		}
		rampunit->numvalues = numvalues;
	}
}

<|endoftext|>


<commit_before>#include "photoeffects.hpp"
#include <opencv2/core/internal.hpp>
using namespace cv;

class FadeColorInvoker
{
public:
    FadeColorInvoker(const Mat& src, Mat& dst, int A,int B,int C,int mD)
        : src_(src),
          dst_(dst),
          A_(A),B_(B),C_(C),maxDistance(mD),
          cols_(src.cols) {}

    void operator()(const BlockedRange& rowsRange) const
    {
        Mat srcStripe = src_.rowRange(rowsRange.begin(), rowsRange.end());
        Mat dstStripe = dst_.rowRange(rowsRange.begin(), rowsRange.end());
        int rows = srcStripe.rows;
        int rown=rowsRange.begin();
        for (int i = 0; i < rows; i++)
        {
            uchar* row = (uchar*)srcStripe.row(i).data;
            uchar* dstRow = (uchar*)dstStripe.row(i).data;
            for (int j = 0; j < cols_; j ++)
            {
                int distance=A_*(rown+i)+B_*j+C_;
                //change pixels only in the direction of the perpendicular
                if(distance>0)
                {
                    for(int n=0;n<src_.channels();n++)
                    {
                        int channelValue=row[src_.channels()*j+n];
                        channelValue*=(maxDistance-distance);
                        channelValue+=255*distance;
                        channelValue/=maxDistance;
                        dstRow[src_.channels()*j+n]=channelValue;
                    }
                }
            }
        }
    }

private:
    const Mat& src_;
    Mat& dst_;
    int cols_;
    //line
    int A_,B_,C_;
    int maxDistance;
    FadeColorInvoker& operator=(const FadeColorInvoker&);
};
Point findFarthestPoint(Point vector, Mat& image)
{
    int a,b;
    if(vector.x<=0)
    {
        a=0;
    }
    else
    {
        a=1;
    }

    if(vector.y<=0)
    {
        b=0;
    }
    else
    {
        b=1;
    }

    return Point(a*image.cols, b*image.rows);
}

int fadeColor(InputArray src, OutputArray dst,
              Point startPoint, Point endPoint)
{

    CV_Assert(!src.empty());
    Mat image=src.getMat();
    CV_Assert(image.type() == CV_8UC1 || image.type() == CV_8UC3);
    CV_Assert(startPoint.x>=0 && startPoint.x<image.cols);
    CV_Assert(endPoint.x>=0 && endPoint.x<image.cols);
    CV_Assert(startPoint.y>=0 && startPoint.y<image.rows);
    CV_Assert(endPoint.y>=0 && endPoint.y<image.rows);
    CV_Assert(startPoint!=endPoint);
    // perpendicular to the line
    Point perpendicular;
    perpendicular.x=endPoint.x-startPoint.x;
    perpendicular.y=endPoint.y-startPoint.y;
    //line equation: A*x+By+C=0

    int A=perpendicular.y;
    int B=perpendicular.x;
    int C=-startPoint.y*A-B*startPoint.x;
    //find the most distant point from the line
    Point farthestPoint=findFarthestPoint(perpendicular, image);

    int maxDistance=abs(A*farthestPoint.y+B*farthestPoint.x+C);
    Mat dstMat=dst.getMat();
    dstMat.create(image.size(),image.type());
    parallel_for(BlockedRange(0, image.rows), FadeColorInvoker(image, dstMat, A,B,C,maxDistance));
    dstMat.copyTo(dst);
    return 0;
}
<commit_msg>Some modifications.<commit_after>#include "photoeffects.hpp"
#include <opencv2/core/internal.hpp>
using namespace cv;

class FadeColorInvoker
{
public:
    FadeColorInvoker(Mat& dst, int A,int B,int C,int mD)
        : dst_(dst),
          A_(A),B_(B),C_(C),maxDistance(mD),
          cols_(dst.cols) {}

    void operator()(const BlockedRange& rowsRange) const
    {
        Mat dstStripe = dst_.rowRange(rowsRange.begin(), rowsRange.end());
        int rows = dstStripe.rows;
        int rowNum=rowsRange.begin();
        for (int i = 0; i < rows; i++)
        {
            uchar* dstRow = (uchar*)dstStripe.row(i).data;
            for (int j = 0; j < cols_; j ++)
            {
                int distance=A_*(rowNum+i)+B_*j+C_;
                //change pixels only in the direction of the perpendicular
                if(distance>0)
                {
                    for(int n=0;n<dst_.channels();n++)
                    {
                        int channelValue=dstRow[dst_.channels()*j+n];
                        channelValue*=(maxDistance-distance);
                        channelValue+=255*distance;
                        channelValue/=maxDistance;
                        dstRow[dst_.channels()*j+n]=channelValue;
                    }
                }
            }
        }
    }

private:
    Mat& dst_;
    int cols_;
    //line
    int A_,B_,C_;
    int maxDistance;
    FadeColorInvoker& operator=(const FadeColorInvoker&);
};
Point findFarthestPoint(Point vector, Mat& image)
{
    int a,b;
    if(vector.x<=0)
    {
        a=0;
    }
    else
    {
        a=1;
    }

    if(vector.y<=0)
    {
        b=0;
    }
    else
    {
        b=1;
    }

    return Point(a*image.cols, b*image.rows);
}

int fadeColor(InputArray src, OutputArray dst,
              Point startPoint, Point endPoint)
{

    CV_Assert(!src.empty());
    Mat image=src.getMat();
    CV_Assert(image.type() == CV_8UC1 || image.type() == CV_8UC3);
    CV_Assert(startPoint.x>=0 && startPoint.x<image.cols);
    CV_Assert(endPoint.x>=0 && endPoint.x<image.cols);
    CV_Assert(startPoint.y>=0 && startPoint.y<image.rows);
    CV_Assert(endPoint.y>=0 && endPoint.y<image.rows);
    CV_Assert(startPoint!=endPoint);
    // perpendicular to the line
    Point perpendicular;
    perpendicular.x=endPoint.x-startPoint.x;
    perpendicular.y=endPoint.y-startPoint.y;
    //line equation: A*x+By+C=0

    int A=perpendicular.y;
    int B=perpendicular.x;
    int C=-startPoint.y*A-B*startPoint.x;
    //find the most distant point from the line
    Point farthestPoint=findFarthestPoint(perpendicular, image);

    int maxDistance=abs(A*farthestPoint.y+B*farthestPoint.x+C);
    Mat dstMat;
    image.copyTo(dstMat);
    parallel_for(BlockedRange(0, image.rows), FadeColorInvoker(dstMat, A,B,C,maxDistance));
    dstMat.copyTo(dst);
    return 0;
}
<|endoftext|>


<commit_before>NAN_METHOD(GitRevwalk::FastWalk)
{
  if (info.Length() == 0 || !info[0]->IsNumber()) {
    return Nan::ThrowError("Max count is required and must be a number.");
  }

  if (info.Length() == 1 || !info[1]->IsFunction()) {
    return Nan::ThrowError("Callback is required and must be a Function.");
  }

  FastWalkBaton* baton = new FastWalkBaton;

  baton->error_code = GIT_OK;
  baton->error = NULL;
  baton->max_count = (unsigned int)info[0]->ToNumber()->Value();
  baton->out = new std::vector<git_oid*>;
  baton->out->reserve(baton->max_count);
  baton->walk = Nan::ObjectWrap::Unwrap<GitRevwalk>(info.This())->GetValue();

  Nan::Callback *callback = new Nan::Callback(Local<Function>::Cast(info[1]));
  FastWalkWorker *worker = new FastWalkWorker(baton, callback);
  worker->SaveToPersistent("fastWalk", info.This());

  Nan::AsyncQueueWorker(worker);
  return;
}

void GitRevwalk::FastWalkWorker::Execute()
{
  for (int i = 0; i < baton->max_count; i++)
  {
    git_oid *nextCommit = (git_oid *)malloc(sizeof(git_oid));
    giterr_clear();
    baton->error_code = git_revwalk_next(nextCommit, baton->walk);

    if (baton->error_code != GIT_OK)
    {
      // We couldn't get a commit out of the revwalk. It's either in
      // an error state or there aren't anymore commits in the revwalk.
      free(nextCommit);

      if (baton->error_code != GIT_ITEROVER) {
        baton->error = git_error_dup(giterr_last());

        while(!baton->out->empty())
        {
          // part of me wants to #define shoot free so we can take the
          // baton out back and shoot the oids
          git_oid *oidToFree = baton->out->back();
          free(oidToFree);
          baton->out->pop_back();
        }

        delete baton->out;

        baton->out = NULL;
      }
      else {
        baton->error_code == GIT_OK;
      }

      break;
    }

    baton->out->push_back(nextCommit);
  }
}

void GitRevwalk::FastWalkWorker::HandleOKCallback()
{
  if (baton->out != NULL)
  {
    unsigned int size = baton->out->size();
    Local<Array> result = Nan::New<Array>(size);
    for (unsigned int i = 0; i < size; i++) {
      Nan::Set(result, Nan::New<Number>(i), GitOid::New(baton->out->at(i), false));
    }

    Local<v8::Value> argv[2] = {
      Nan::Null(),
      result
    };
    callback->Call(2, argv);
  }
  else
  {
    if (baton->error)
    {
      Local<v8::Value> argv[1] = {
        Nan::Error(baton->error->message)
      };
      callback->Call(1, argv);
      if (baton->error->message)
      {
        free((void *)baton->error->message);
      }

      free((void *)baton->error);
    }
    else if (baton->error_code < 0)
    {
      std::queue< Local<v8::Value> > workerArguments;
      bool callbackFired = false;

      while(!workerArguments.empty())
      {
        Local<v8::Value> node = workerArguments.front();
        workerArguments.pop();

        if (
          !node->IsObject()
          || node->IsArray()
          || node->IsBooleanObject()
          || node->IsDate()
          || node->IsFunction()
          || node->IsNumberObject()
          || node->IsRegExp()
          || node->IsStringObject()
        )
        {
          continue;
        }

        Local<v8::Object> nodeObj = node->ToObject();
        Local<v8::Value> checkValue = nodeObj->GetHiddenValue(Nan::New("NodeGitPromiseError").ToLocalChecked());

        if (!checkValue.IsEmpty() && !checkValue->IsNull() && !checkValue->IsUndefined())
        {
          Local<v8::Value> argv[1] = {
            checkValue->ToObject()
          };
          callback->Call(1, argv);
          callbackFired = true;
          break;
        }

        Local<v8::Array> properties = nodeObj->GetPropertyNames();
        for (unsigned int propIndex = 0; propIndex < properties->Length(); ++propIndex)
        {
          Local<v8::String> propName = properties->Get(propIndex)->ToString();
          Local<v8::Value> nodeToQueue = nodeObj->Get(propName);
          if (!nodeToQueue->IsUndefined())
          {
            workerArguments.push(nodeToQueue);
          }
        }
      }

      if (!callbackFired)
      {
        Local<v8::Object> err = Nan::Error("Method next has thrown an error.")->ToObject();
        err->Set(Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code));
        Local<v8::Value> argv[1] = {
          err
        };
        callback->Call(1, argv);
      }
    }
    else
    {
      callback->Call(0, NULL);
    }
  }
}
<commit_msg>Fix `fast_walk.cc` when there was an error<commit_after>NAN_METHOD(GitRevwalk::FastWalk)
{
  if (info.Length() == 0 || !info[0]->IsNumber()) {
    return Nan::ThrowError("Max count is required and must be a number.");
  }

  if (info.Length() == 1 || !info[1]->IsFunction()) {
    return Nan::ThrowError("Callback is required and must be a Function.");
  }

  FastWalkBaton* baton = new FastWalkBaton;

  baton->error_code = GIT_OK;
  baton->error = NULL;
  baton->max_count = (unsigned int)info[0]->ToNumber()->Value();
  baton->out = new std::vector<git_oid*>;
  baton->out->reserve(baton->max_count);
  baton->walk = Nan::ObjectWrap::Unwrap<GitRevwalk>(info.This())->GetValue();

  Nan::Callback *callback = new Nan::Callback(Local<Function>::Cast(info[1]));
  FastWalkWorker *worker = new FastWalkWorker(baton, callback);
  worker->SaveToPersistent("fastWalk", info.This());

  Nan::AsyncQueueWorker(worker);
  return;
}

void GitRevwalk::FastWalkWorker::Execute()
{
  for (int i = 0; i < baton->max_count; i++)
  {
    git_oid *nextCommit = (git_oid *)malloc(sizeof(git_oid));
    giterr_clear();
    baton->error_code = git_revwalk_next(nextCommit, baton->walk);

    if (baton->error_code != GIT_OK)
    {
      // We couldn't get a commit out of the revwalk. It's either in
      // an error state or there aren't anymore commits in the revwalk.
      free(nextCommit);

      if (baton->error_code != GIT_ITEROVER) {
        baton->error = git_error_dup(giterr_last());

        while(!baton->out->empty())
        {
          // part of me wants to #define shoot free so we can take the
          // baton out back and shoot the oids
          git_oid *oidToFree = baton->out->back();
          free(oidToFree);
          baton->out->pop_back();
        }

        delete baton->out;

        baton->out = NULL;
      }
      else {
        baton->error_code = GIT_OK;
      }

      break;
    }

    baton->out->push_back(nextCommit);
  }
}

void GitRevwalk::FastWalkWorker::HandleOKCallback()
{
  if (baton->out != NULL)
  {
    unsigned int size = baton->out->size();
    Local<Array> result = Nan::New<Array>(size);
    for (unsigned int i = 0; i < size; i++) {
      Nan::Set(result, Nan::New<Number>(i), GitOid::New(baton->out->at(i), false));
    }

    Local<v8::Value> argv[2] = {
      Nan::Null(),
      result
    };
    callback->Call(2, argv);
  }
  else
  {
    if (baton->error)
    {
      Local<v8::Value> argv[1] = {
        Nan::Error(baton->error->message)
      };
      callback->Call(1, argv);
      if (baton->error->message)
      {
        free((void *)baton->error->message);
      }

      free((void *)baton->error);
    }
    else if (baton->error_code < 0)
    {
      std::queue< Local<v8::Value> > workerArguments;
      bool callbackFired = false;

      while(!workerArguments.empty())
      {
        Local<v8::Value> node = workerArguments.front();
        workerArguments.pop();

        if (
          !node->IsObject()
          || node->IsArray()
          || node->IsBooleanObject()
          || node->IsDate()
          || node->IsFunction()
          || node->IsNumberObject()
          || node->IsRegExp()
          || node->IsStringObject()
        )
        {
          continue;
        }

        Local<v8::Object> nodeObj = node->ToObject();
        Local<v8::Value> checkValue = nodeObj->GetHiddenValue(Nan::New("NodeGitPromiseError").ToLocalChecked());

        if (!checkValue.IsEmpty() && !checkValue->IsNull() && !checkValue->IsUndefined())
        {
          Local<v8::Value> argv[1] = {
            checkValue->ToObject()
          };
          callback->Call(1, argv);
          callbackFired = true;
          break;
        }

        Local<v8::Array> properties = nodeObj->GetPropertyNames();
        for (unsigned int propIndex = 0; propIndex < properties->Length(); ++propIndex)
        {
          Local<v8::String> propName = properties->Get(propIndex)->ToString();
          Local<v8::Value> nodeToQueue = nodeObj->Get(propName);
          if (!nodeToQueue->IsUndefined())
          {
            workerArguments.push(nodeToQueue);
          }
        }
      }

      if (!callbackFired)
      {
        Local<v8::Object> err = Nan::Error("Method next has thrown an error.")->ToObject();
        err->Set(Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code));
        Local<v8::Value> argv[1] = {
          err
        };
        callback->Call(1, argv);
      }
    }
    else
    {
      callback->Call(0, NULL);
    }
  }
}
<|endoftext|>