<commit_before>//===- DCE.cpp - Code to perform dead code elimination --------------------===//
//
// This file implements dead code elimination and basic block merging.
//
// Specifically, this:
//   * removes definitions with no uses (including unused constants)
//   * removes basic blocks with no predecessors
//   * merges a basic block into its predecessor if there is only one and the
//     predecessor only has one successor.
//   * Eliminates PHI nodes for basic blocks with a single predecessor
//   * Eliminates a basic block that only contains an unconditional branch
//
// TODO: This should REALLY be worklist driven instead of iterative.  Right now,
// we scan linearly through values, removing unused ones as we go.  The problem
// is that this may cause other earlier values to become unused.  To make sure
// that we get them all, we iterate until things stop changing.  Instead, when
// removing a value, recheck all of its operands to see if they are now unused.
// Piece of cake, and more efficient as well.
//
// Note, this is not trivial, because we have to worry about invalidating
// iterators.  :(
//
//===----------------------------------------------------------------------===//

#include "llvm/Optimizations/DCE.h"
#include "llvm/Tools/STLExtras.h"
#include "llvm/Module.h"
#include "llvm/Method.h"
#include "llvm/BasicBlock.h"
#include "llvm/iTerminators.h"
#include "llvm/iOther.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/CFG.h"
#include <algorithm>

using namespace cfg;

struct ConstPoolDCE {
  enum { EndOffs = 0 };
  static bool isDCEable(const Value *) { return true; }
};

struct BasicBlockDCE {
  enum { EndOffs = 1 };
  static bool isDCEable(const Instruction *I) {
    return !I->hasSideEffects();
  }
};

template<class ValueSubclass, class ItemParentType, class DCEController>
static bool RemoveUnusedDefs(ValueHolder<ValueSubclass, ItemParentType> &Vals,
			     DCEController DCEControl) {
  bool Changed = false;
  typedef ValueHolder<ValueSubclass, ItemParentType> Container;

  int Offset = DCEController::EndOffs;
  for (Container::iterator DI = Vals.begin(); DI != Vals.end()-Offset; ) {
    // Look for un"used" definitions...
    if ((*DI)->use_empty() && DCEController::isDCEable(*DI)) {
      // Bye bye
      //cerr << "Removing: " << *DI;
      delete Vals.remove(DI);
      Changed = true;
    } else {
      ++DI;
    }
  }
  return Changed;
}

// RemoveSingularPHIs - This removes PHI nodes from basic blocks that have only
// a single predecessor.  This means that the PHI node must only have a single
// RHS value and can be eliminated.
//
// This routine is very simple because we know that PHI nodes must be the first
// things in a basic block, if they are present.
//
static bool RemoveSingularPHIs(BasicBlock *BB) {
  pred_iterator PI(pred_begin(BB));
  if (PI == pred_end(BB) || ++PI != pred_end(BB))
    return false;   // More than one predecessor...

  Instruction *I = BB->front();
  if (!I->isPHINode()) return false;  // No PHI nodes

  //cerr << "Killing PHIs from " << BB;
  //cerr << "Pred #0 = " << *pred_begin(BB);

  //cerr << "Method == " << BB->getParent();

  do {
    PHINode *PN = (PHINode*)I;
    assert(PN->getNumOperands() == 2 && "PHI node should only have one value!");
    Value *V = PN->getOperand(0);

    PN->replaceAllUsesWith(V);      // Replace PHI node with its single value.
    delete BB->getInstList().remove(BB->begin());

    I = BB->front();
  } while (I->isPHINode());

  return true;  // Yes, we nuked at least one phi node
}

bool opt::DoRemoveUnusedConstants(SymTabValue *S) {
  bool Changed = false;
  ConstantPool &CP = S->getConstantPool();
  for (ConstantPool::plane_iterator PI = CP.begin(); PI != CP.end(); ++PI)
    Changed |= RemoveUnusedDefs(**PI, ConstPoolDCE());
  return Changed;
}

static void ReplaceUsesWithConstant(Instruction *I) {
  // Get the method level constant pool
  ConstantPool &CP = I->getParent()->getParent()->getConstantPool();

  ConstPoolVal *CPV = 0;
  ConstantPool::PlaneType *P;
  if (!CP.getPlane(I->getType(), P)) {  // Does plane exist?
    // Yes, is it empty?
    if (!P->empty()) CPV = P->front();
  }

  if (CPV == 0) { // We don't have an existing constant to reuse.  Just add one.
    CPV = ConstPoolVal::getNullConstant(I->getType());  // Create a new constant

    // Add the new value to the constant pool...
    CP.insert(CPV);
  }

  // Make all users of this instruction reference the constant instead
  I->replaceAllUsesWith(CPV);
}

// PropogatePredecessors - This gets "Succ" ready to have the predecessors from
// "BB".  This is a little tricky because "Succ" has PHI nodes, which need to
// have extra slots added to them to hold the merge edges from BB's
// predecessors.
//
// Assumption: BB is the single predecessor of Succ.
//
static void PropogatePredecessorsForPHIs(BasicBlock *BB, BasicBlock *Succ) {
  assert(Succ->front()->isPHINode() && "Only works on PHId BBs!");

  // If there is more than one predecessor, and there are PHI nodes in
  // the successor, then we need to add incoming edges for the PHI nodes
  //
  const vector<BasicBlock*> BBPreds(pred_begin(BB), pred_end(BB));

  BasicBlock::iterator I = Succ->begin();
  do {                     // Loop over all of the PHI nodes in the successor BB
    PHINode *PN = (PHINode*)*I;
    Value *OldVal = PN->removeIncomingValue(BB);
    assert(OldVal && "No entry in PHI for Pred BB!");

    for (vector<BasicBlock*>::const_iterator PredI = BBPreds.begin(),
	   End = BBPreds.end(); PredI != End; ++PredI) {
      // Add an incoming value for each of the new incoming values...
      PN->addIncoming(OldVal, *PredI);
    }

    ++I;
  } while ((*I)->isPHINode());
}

// SimplifyCFG - This function is used to do simplification of a CFG.  For
// example, it adjusts branches to branches to eliminate the extra hop, it
// eliminates unreachable basic blocks, and does other "peephole" optimization
// of the CFG.  It returns true if a modification was made, and returns an
// iterator that designates the first element remaining after the block that
// was deleted.
//
// WARNING:  The entry node of a method may not be simplified.
//
bool opt::SimplifyCFG(Method::iterator &BBIt) {
  assert(*BBIt && (*BBIt)->getParent() && "Block not embedded in method!");
  BasicBlock *BB = *BBIt;
  Method *M = BB->getParent();
  assert(BB->getTerminator() && "Degenerate basic block encountered!");
  assert(BB->getParent()->front() != BB && "Can't Simplify entry block!");

  // Remove basic blocks that have no predecessors... which are unreachable.
  if (pred_begin(BB) == pred_end(BB) &&
      !BB->hasConstantPoolReferences()) {
    //cerr << "Removing BB: \n" << BB;

    // Loop through all of our successors and make sure they know that one
    // of their predecessors is going away.
    for_each(succ_begin(BB), succ_end(BB),
	     std::bind2nd(std::mem_fun(&BasicBlock::removePredecessor), BB));

    while (!BB->empty()) {
      Instruction *I = BB->back();
      // If this instruction is used, replace uses with an arbitrary
      // constant value.  Because control flow can't get here, we don't care
      // what we replace the value with.  Note that since this block is
      // unreachable, and all values contained within it must dominate their
      // uses, that all uses will eventually be removed.
      if (!I->use_empty()) ReplaceUsesWithConstant(I);

      // Remove the instruction from the basic block
      delete BB->getInstList().pop_back();
    }
    delete M->getBasicBlocks().remove(BBIt);
    return true;
  }

  // Check to see if this block has no instructions and only a single
  // successor.  If so, replace block references with successor.
  succ_iterator SI(succ_begin(BB));
  if (SI != succ_end(BB) && ++SI == succ_end(BB)) {  // One succ?
    Instruction *I = BB->front();
    if (I->isTerminator()) {   // Terminator is the only instruction!
      BasicBlock *Succ = *succ_begin(BB); // There is exactly one successor
      //cerr << "Killing Trivial BB: \n" << BB;

      if (Succ != BB) {   // Arg, don't hurt infinite loops!
	if (Succ->front()->isPHINode()) {
	  // If our successor has PHI nodes, then we need to update them to
	  // include entries for BB's predecessors, not for BB itself.
	  //
	  PropogatePredecessorsForPHIs(BB, Succ);
	}

	BB->replaceAllUsesWith(Succ);
	BB = M->getBasicBlocks().remove(BBIt);

	if (BB->hasName() && !Succ->hasName())  // Transfer name if we can
	  Succ->setName(BB->getName());
	delete BB;                              // Delete basic block

	//cerr << "Method after removal: \n" << M;
	return true;
      }
    }
  }

  // Merge basic blocks into their predecessor if there is only one pred,
  // and if there is only one successor of the predecessor.
  pred_iterator PI(pred_begin(BB));
  if (PI != pred_end(BB) && *PI != BB &&    // Not empty?  Not same BB?
      ++PI == pred_end(BB) && !BB->hasConstantPoolReferences()) {
    BasicBlock *Pred = *pred_begin(BB);
    TerminatorInst *Term = Pred->getTerminator();
    assert(Term != 0 && "malformed basic block without terminator!");

    // Does the predecessor block only have a single successor?
    succ_iterator SI(succ_begin(Pred));
    if (++SI == succ_end(Pred)) {
      //cerr << "Merging: " << BB << "into: " << Pred;

      // Delete the unconditianal branch from the predecessor...
      BasicBlock::iterator DI = Pred->end();
      assert(Pred->getTerminator() &&
	     "Degenerate basic block encountered!");  // Empty bb???
      delete Pred->getInstList().remove(--DI);        // Destroy uncond branch

      // Move all definitions in the succecessor to the predecessor...
      while (!BB->empty()) {
	DI = BB->begin();
	Instruction *Def = BB->getInstList().remove(DI); // Remove from front
	Pred->getInstList().push_back(Def);              // Add to end...
      }

      // Remove basic block from the method... and advance iterator to the
      // next valid block...
      BB = M->getBasicBlocks().remove(BBIt);

      // Make all PHI nodes that refered to BB now refer to Pred as their
      // source...
      BB->replaceAllUsesWith(Pred);

      // Inherit predecessors name if it exists...
      if (BB->hasName() && !Pred->hasName()) Pred->setName(BB->getName());

      delete BB; // You ARE the weakest link... goodbye
      return true;
    }
  }

  return false;
}

static bool DoDCEPass(Method *M) {
  Method::iterator BBIt, BBEnd = M->end();
  if (M->begin() == BBEnd) return false;  // Nothing to do
  bool Changed = false;

  // Loop through now and remove instructions that have no uses...
  for (BBIt = M->begin(); BBIt != BBEnd; ++BBIt) {
    Changed |= RemoveUnusedDefs((*BBIt)->getInstList(), BasicBlockDCE());
    Changed |= RemoveSingularPHIs(*BBIt);
  }

  // Loop over all of the basic blocks (except the first one) and remove them
  // if they are unneeded...
  //
  for (BBIt = M->begin(), ++BBIt; BBIt != M->end(); ) {
    if (opt::SimplifyCFG(BBIt)) {
      Changed = true;
    } else {
      ++BBIt;
    }
  }

  // Remove unused constants
  return Changed | opt::DoRemoveUnusedConstants(M);
}

// It is possible that we may require multiple passes over the code to fully
// eliminate dead code.  Iterate until we are done.
//
bool opt::DoDeadCodeElimination(Method *M) {
  bool Changed = false;
  while (DoDCEPass(M)) Changed = true;
  return Changed;
}

bool opt::DoDeadCodeElimination(Module *C) {
  bool Val = C->reduceApply(DoDeadCodeElimination);

  while (DoRemoveUnusedConstants(C)) Val = true;
  return Val;
}
<commit_msg>Don't clean out the type plane of the constant pool... this is a hack.  FIXME<commit_after>//===- DCE.cpp - Code to perform dead code elimination --------------------===//
//
// This file implements dead code elimination and basic block merging.
//
// Specifically, this:
//   * removes definitions with no uses (including unused constants)
//   * removes basic blocks with no predecessors
//   * merges a basic block into its predecessor if there is only one and the
//     predecessor only has one successor.
//   * Eliminates PHI nodes for basic blocks with a single predecessor
//   * Eliminates a basic block that only contains an unconditional branch
//
// TODO: This should REALLY be worklist driven instead of iterative.  Right now,
// we scan linearly through values, removing unused ones as we go.  The problem
// is that this may cause other earlier values to become unused.  To make sure
// that we get them all, we iterate until things stop changing.  Instead, when
// removing a value, recheck all of its operands to see if they are now unused.
// Piece of cake, and more efficient as well.
//
// Note, this is not trivial, because we have to worry about invalidating
// iterators.  :(
//
//===----------------------------------------------------------------------===//

#include "llvm/Optimizations/DCE.h"
#include "llvm/Tools/STLExtras.h"
#include "llvm/Module.h"
#include "llvm/Method.h"
#include "llvm/BasicBlock.h"
#include "llvm/iTerminators.h"
#include "llvm/iOther.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/CFG.h"
#include <algorithm>

using namespace cfg;

struct ConstPoolDCE {
  enum { EndOffs = 0 };
  static bool isDCEable(const ConstPoolVal *CPV) {
    // TODO: The bytecode writer requires that all used types are in the
    // constant pool for the current method.  This is messy and is really
    // irritating. FIXME
    return CPV->getType() != Type::TypeTy;  // Don't DCE Type plane constants!
  }
};

struct BasicBlockDCE {
  enum { EndOffs = 1 };
  static bool isDCEable(const Instruction *I) {
    return !I->hasSideEffects();
  }
};

template<class ValueSubclass, class ItemParentType, class DCEController>
static bool RemoveUnusedDefs(ValueHolder<ValueSubclass, ItemParentType> &Vals,
			     DCEController DCEControl) {
  bool Changed = false;
  typedef ValueHolder<ValueSubclass, ItemParentType> Container;

  int Offset = DCEController::EndOffs;
  for (Container::iterator DI = Vals.begin(); DI != Vals.end()-Offset; ) {
    // Look for un"used" definitions...
    if ((*DI)->use_empty() && DCEController::isDCEable(*DI)) {
      // Bye bye
      //cerr << "Removing: " << *DI;
      delete Vals.remove(DI);
      Changed = true;
    } else {
      ++DI;
    }
  }
  return Changed;
}

// RemoveSingularPHIs - This removes PHI nodes from basic blocks that have only
// a single predecessor.  This means that the PHI node must only have a single
// RHS value and can be eliminated.
//
// This routine is very simple because we know that PHI nodes must be the first
// things in a basic block, if they are present.
//
static bool RemoveSingularPHIs(BasicBlock *BB) {
  pred_iterator PI(pred_begin(BB));
  if (PI == pred_end(BB) || ++PI != pred_end(BB))
    return false;   // More than one predecessor...

  Instruction *I = BB->front();
  if (!I->isPHINode()) return false;  // No PHI nodes

  //cerr << "Killing PHIs from " << BB;
  //cerr << "Pred #0 = " << *pred_begin(BB);

  //cerr << "Method == " << BB->getParent();

  do {
    PHINode *PN = (PHINode*)I;
    assert(PN->getNumOperands() == 2 && "PHI node should only have one value!");
    Value *V = PN->getOperand(0);

    PN->replaceAllUsesWith(V);      // Replace PHI node with its single value.
    delete BB->getInstList().remove(BB->begin());

    I = BB->front();
  } while (I->isPHINode());

  return true;  // Yes, we nuked at least one phi node
}

bool opt::DoRemoveUnusedConstants(SymTabValue *S) {
  bool Changed = false;
  ConstantPool &CP = S->getConstantPool();
  for (ConstantPool::plane_iterator PI = CP.begin(); PI != CP.end(); ++PI)
    Changed |= RemoveUnusedDefs(**PI, ConstPoolDCE());
  return Changed;
}

static void ReplaceUsesWithConstant(Instruction *I) {
  // Get the method level constant pool
  ConstantPool &CP = I->getParent()->getParent()->getConstantPool();

  ConstPoolVal *CPV = 0;
  ConstantPool::PlaneType *P;
  if (!CP.getPlane(I->getType(), P)) {  // Does plane exist?
    // Yes, is it empty?
    if (!P->empty()) CPV = P->front();
  }

  if (CPV == 0) { // We don't have an existing constant to reuse.  Just add one.
    CPV = ConstPoolVal::getNullConstant(I->getType());  // Create a new constant

    // Add the new value to the constant pool...
    CP.insert(CPV);
  }

  // Make all users of this instruction reference the constant instead
  I->replaceAllUsesWith(CPV);
}

// PropogatePredecessors - This gets "Succ" ready to have the predecessors from
// "BB".  This is a little tricky because "Succ" has PHI nodes, which need to
// have extra slots added to them to hold the merge edges from BB's
// predecessors.
//
// Assumption: BB is the single predecessor of Succ.
//
static void PropogatePredecessorsForPHIs(BasicBlock *BB, BasicBlock *Succ) {
  assert(Succ->front()->isPHINode() && "Only works on PHId BBs!");

  // If there is more than one predecessor, and there are PHI nodes in
  // the successor, then we need to add incoming edges for the PHI nodes
  //
  const vector<BasicBlock*> BBPreds(pred_begin(BB), pred_end(BB));

  BasicBlock::iterator I = Succ->begin();
  do {                     // Loop over all of the PHI nodes in the successor BB
    PHINode *PN = (PHINode*)*I;
    Value *OldVal = PN->removeIncomingValue(BB);
    assert(OldVal && "No entry in PHI for Pred BB!");

    for (vector<BasicBlock*>::const_iterator PredI = BBPreds.begin(),
	   End = BBPreds.end(); PredI != End; ++PredI) {
      // Add an incoming value for each of the new incoming values...
      PN->addIncoming(OldVal, *PredI);
    }

    ++I;
  } while ((*I)->isPHINode());
}

// SimplifyCFG - This function is used to do simplification of a CFG.  For
// example, it adjusts branches to branches to eliminate the extra hop, it
// eliminates unreachable basic blocks, and does other "peephole" optimization
// of the CFG.  It returns true if a modification was made, and returns an
// iterator that designates the first element remaining after the block that
// was deleted.
//
// WARNING:  The entry node of a method may not be simplified.
//
bool opt::SimplifyCFG(Method::iterator &BBIt) {
  assert(*BBIt && (*BBIt)->getParent() && "Block not embedded in method!");
  BasicBlock *BB = *BBIt;
  Method *M = BB->getParent();
  assert(BB->getTerminator() && "Degenerate basic block encountered!");
  assert(BB->getParent()->front() != BB && "Can't Simplify entry block!");

  // Remove basic blocks that have no predecessors... which are unreachable.
  if (pred_begin(BB) == pred_end(BB) &&
      !BB->hasConstantPoolReferences()) {
    //cerr << "Removing BB: \n" << BB;

    // Loop through all of our successors and make sure they know that one
    // of their predecessors is going away.
    for_each(succ_begin(BB), succ_end(BB),
	     std::bind2nd(std::mem_fun(&BasicBlock::removePredecessor), BB));

    while (!BB->empty()) {
      Instruction *I = BB->back();
      // If this instruction is used, replace uses with an arbitrary
      // constant value.  Because control flow can't get here, we don't care
      // what we replace the value with.  Note that since this block is
      // unreachable, and all values contained within it must dominate their
      // uses, that all uses will eventually be removed.
      if (!I->use_empty()) ReplaceUsesWithConstant(I);

      // Remove the instruction from the basic block
      delete BB->getInstList().pop_back();
    }
    delete M->getBasicBlocks().remove(BBIt);
    return true;
  }

  // Check to see if this block has no instructions and only a single
  // successor.  If so, replace block references with successor.
  succ_iterator SI(succ_begin(BB));
  if (SI != succ_end(BB) && ++SI == succ_end(BB)) {  // One succ?
    Instruction *I = BB->front();
    if (I->isTerminator()) {   // Terminator is the only instruction!
      BasicBlock *Succ = *succ_begin(BB); // There is exactly one successor
      //cerr << "Killing Trivial BB: \n" << BB;

      if (Succ != BB) {   // Arg, don't hurt infinite loops!
	if (Succ->front()->isPHINode()) {
	  // If our successor has PHI nodes, then we need to update them to
	  // include entries for BB's predecessors, not for BB itself.
	  //
	  PropogatePredecessorsForPHIs(BB, Succ);
	}

	BB->replaceAllUsesWith(Succ);
	BB = M->getBasicBlocks().remove(BBIt);

	if (BB->hasName() && !Succ->hasName())  // Transfer name if we can
	  Succ->setName(BB->getName());
	delete BB;                              // Delete basic block

	//cerr << "Method after removal: \n" << M;
	return true;
      }
    }
  }

  // Merge basic blocks into their predecessor if there is only one pred,
  // and if there is only one successor of the predecessor.
  pred_iterator PI(pred_begin(BB));
  if (PI != pred_end(BB) && *PI != BB &&    // Not empty?  Not same BB?
      ++PI == pred_end(BB) && !BB->hasConstantPoolReferences()) {
    BasicBlock *Pred = *pred_begin(BB);
    TerminatorInst *Term = Pred->getTerminator();
    assert(Term != 0 && "malformed basic block without terminator!");

    // Does the predecessor block only have a single successor?
    succ_iterator SI(succ_begin(Pred));
    if (++SI == succ_end(Pred)) {
      //cerr << "Merging: " << BB << "into: " << Pred;

      // Delete the unconditianal branch from the predecessor...
      BasicBlock::iterator DI = Pred->end();
      assert(Pred->getTerminator() &&
	     "Degenerate basic block encountered!");  // Empty bb???
      delete Pred->getInstList().remove(--DI);        // Destroy uncond branch

      // Move all definitions in the succecessor to the predecessor...
      while (!BB->empty()) {
	DI = BB->begin();
	Instruction *Def = BB->getInstList().remove(DI); // Remove from front
	Pred->getInstList().push_back(Def);              // Add to end...
      }

      // Remove basic block from the method... and advance iterator to the
      // next valid block...
      BB = M->getBasicBlocks().remove(BBIt);

      // Make all PHI nodes that refered to BB now refer to Pred as their
      // source...
      BB->replaceAllUsesWith(Pred);

      // Inherit predecessors name if it exists...
      if (BB->hasName() && !Pred->hasName()) Pred->setName(BB->getName());

      delete BB; // You ARE the weakest link... goodbye
      return true;
    }
  }

  return false;
}

static bool DoDCEPass(Method *M) {
  Method::iterator BBIt, BBEnd = M->end();
  if (M->begin() == BBEnd) return false;  // Nothing to do
  bool Changed = false;

  // Loop through now and remove instructions that have no uses...
  for (BBIt = M->begin(); BBIt != BBEnd; ++BBIt) {
    Changed |= RemoveUnusedDefs((*BBIt)->getInstList(), BasicBlockDCE());
    Changed |= RemoveSingularPHIs(*BBIt);
  }

  // Loop over all of the basic blocks (except the first one) and remove them
  // if they are unneeded...
  //
  for (BBIt = M->begin(), ++BBIt; BBIt != M->end(); ) {
    if (opt::SimplifyCFG(BBIt)) {
      Changed = true;
    } else {
      ++BBIt;
    }
  }

  // Remove unused constants
  return Changed | opt::DoRemoveUnusedConstants(M);
}

// It is possible that we may require multiple passes over the code to fully
// eliminate dead code.  Iterate until we are done.
//
bool opt::DoDeadCodeElimination(Method *M) {
  bool Changed = false;
  while (DoDCEPass(M)) Changed = true;
  return Changed;
}

bool opt::DoDeadCodeElimination(Module *C) {
  bool Val = C->reduceApply(DoDeadCodeElimination);

  while (DoRemoveUnusedConstants(C)) Val = true;
  return Val;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Luke San Antonio
 * All rights reserved.
 */
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <vector>
#include <thread>

#include "common/log.h"

#include "gfx/gl/driver.h"
#include "gfx/camera.h"
#include "gfx/object.h"
#include "gfx/scene_node.h"
#include "gfx/texture.h"
#include "gfx/mesh.h"

#include "glad/glad.h"
#include "glfw3.h"

#define GLM_FORCE_RADIANS
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"

#include "uv.h"

#define CATCH_CONFIG_RUNNER
#include "catch/catch.hpp"

struct Command_Options
{
};

Command_Options parse_command_line(int argc, char**)
{
  Command_Options opt;
  for(int i = 0; i < argc; ++i)
  {
    //auto option = argv[i];
  }
  return opt;
}

int main(int argc, char** argv)
{
  using namespace game;

  set_log_level(Log_Severity::Debug);

  uv_chdir("assets/");

  // Initialize logger.
  Scoped_Log_Init log_init_raii_lock{};

  // Parse command line arguments.
  auto options = parse_command_line(argc - 1, argv+1);

  // Init glfw.
  if(!glfwInit())
    return EXIT_FAILURE;

  auto window = glfwCreateWindow(1000, 1000, "Hello World", NULL, NULL);
  if(!window)
  {
    glfwTerminate();
    return EXIT_FAILURE;
  }

  // Init context + load gl functions.
  glfwMakeContextCurrent(window);
  gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);

  // Log glfw version.
  log_i("Initialized GLFW %", glfwGetVersionString());

  int maj = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR);
  int min = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR);
  int rev = glfwGetWindowAttrib(window, GLFW_CONTEXT_REVISION);

  // Log GL profile.
  log_i("OpenGL core profile %.%.%", maj, min, rev);

  // Hide the mouse and capture it
  glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);

  {
    // Make an OpenGL driver.
    gfx::gl::Driver driver{};

    // Make an fps camera.
    auto cam = gfx::make_fps_camera();
    cam.fp.pos = glm::vec3(0.0f, 0.0f, 25.0f);

    auto house = gfx::load_object("obj/house.obj", "mat/house.json");
    prepare_object(driver, house);

    auto house_aabb = generate_aabb(*house.mesh);

    auto plane = gfx::load_object("obj/plane.obj", "mat/plane.json");
    prepare_object(driver, plane);
    plane.model_matrix = glm::translate(plane.model_matrix,
                                        glm::vec3(0.0f,house_aabb.min.y,0.0f));
    plane.model_matrix = glm::scale(plane.model_matrix,
                                    glm::vec3(5.0f, 1.0f, 7.0f));
    plane.model_matrix = glm::translate(plane.model_matrix,
                                        glm::vec3(-0.5f, 0.0f, -0.5f));

    int fps = 0;
    int time = glfwGetTime();

    // Set up some pre-rendering state.
    driver.clear_color_value(Color{0x55, 0x66, 0x77});
    driver.clear_depth_value(1.0);

    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);

    while(!glfwWindowShouldClose(window))
    {
      ++fps;
      glfwPollEvents();

      if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
      {
        glfwSetWindowShouldClose(window, true);
      }

      double x, y;
      glfwGetCursorPos(window, &x, &y);

      cam.fp.pitch = y / 250.0;
      cam.fp.yaw = x / 250.0;

      driver.use_camera(cam);

      // Clear the screen
      driver.clear();

      render_object(driver, house);
      render_object(driver, plane);

      glfwSwapBuffers(window);

      if(int(glfwGetTime()) != time)
      {
        time = glfwGetTime();
        log_d("fps: %", fps);
        fps = 0;
      }
    }
  }
  glfwTerminate();
  return 0;
}
<commit_msg>We're now using our nifty fps camera controller in the main(_fps.cpp) file.<commit_after>/*
 * Copyright (C) 2015 Luke San Antonio
 * All rights reserved.
 */
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <vector>
#include <thread>

#include "common/log.h"

#include "gfx/gl/driver.h"
#include "gfx/camera.h"
#include "gfx/object.h"
#include "gfx/scene_node.h"
#include "gfx/texture.h"
#include "gfx/mesh.h"

#include "fps/camera_controller.h"

#include "glad/glad.h"
#include "glfw3.h"

#define GLM_FORCE_RADIANS
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"

#include "uv.h"

#define CATCH_CONFIG_RUNNER
#include "catch/catch.hpp"

#define PI 3.141592653589793238463

struct Command_Options
{
};

Command_Options parse_command_line(int argc, char**)
{
  Command_Options opt;
  for(int i = 0; i < argc; ++i)
  {
    //auto option = argv[i];
  }
  return opt;
}

int main(int argc, char** argv)
{
  using namespace game;

  set_log_level(Log_Severity::Debug);

  uv_chdir("assets/");

  // Initialize logger.
  Scoped_Log_Init log_init_raii_lock{};

  // Parse command line arguments.
  auto options = parse_command_line(argc - 1, argv+1);

  // Init glfw.
  if(!glfwInit())
    return EXIT_FAILURE;

  auto window = glfwCreateWindow(1000, 1000, "Hello World", NULL, NULL);
  if(!window)
  {
    glfwTerminate();
    return EXIT_FAILURE;
  }

  // Init context + load gl functions.
  glfwMakeContextCurrent(window);
  gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);

  // Log glfw version.
  log_i("Initialized GLFW %", glfwGetVersionString());

  int maj = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR);
  int min = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR);
  int rev = glfwGetWindowAttrib(window, GLFW_CONTEXT_REVISION);

  // Log GL profile.
  log_i("OpenGL core profile %.%.%", maj, min, rev);

  // Hide the mouse and capture it
  glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);

  {
    // Make an OpenGL driver.
    gfx::gl::Driver driver{};

    // Make an fps camera.
    auto cam = gfx::make_fps_camera();
    cam.fp.pos = glm::vec3(0.0f, 0.0f, 15.0f);

    auto cam_controller = fps::Camera_Controller{};
    cam_controller.camera(cam);

    cam_controller.set_yaw_limit(PI / 2);
    cam_controller.set_pitch_limit(PI / 2);

    auto house = gfx::load_object("obj/house.obj", "mat/house.json");
    prepare_object(driver, house);

    auto house_aabb = generate_aabb(*house.mesh);

    auto plane = gfx::load_object("obj/plane.obj", "mat/plane.json");
    prepare_object(driver, plane);
    plane.model_matrix = glm::translate(plane.model_matrix,
                                        glm::vec3(0.0f,house_aabb.min.y,0.0f));
    plane.model_matrix = glm::scale(plane.model_matrix,
                                    glm::vec3(5.0f, 1.0f, 7.0f));
    plane.model_matrix = glm::translate(plane.model_matrix,
                                        glm::vec3(-0.5f, 0.0f, -0.5f));

    int fps = 0;
    int time = glfwGetTime();

    // Set up some pre-rendering state.
    driver.clear_color_value(Color{0x55, 0x66, 0x77});
    driver.clear_depth_value(1.0);

    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);

    double prev_x, prev_y;
    glfwPollEvents();
    glfwGetCursorPos(window, &prev_x, &prev_y);

    while(!glfwWindowShouldClose(window))
    {
      ++fps;
      glfwPollEvents();

      if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
      {
        glfwSetWindowShouldClose(window, true);
      }

      double x, y;
      glfwGetCursorPos(window, &x, &y);
      cam_controller.apply_delta_pitch(y / 250.0 - prev_y / 250.0);
      cam_controller.apply_delta_yaw(x / 250.0 - prev_x / 250.0);
      prev_x = x, prev_y = y;

      driver.use_camera(cam);

      // Clear the screen
      driver.clear();

      render_object(driver, house);
      render_object(driver, plane);

      glfwSwapBuffers(window);

      if(int(glfwGetTime()) != time)
      {
        time = glfwGetTime();
        log_d("fps: %", fps);
        fps = 0;
      }
    }
  }
  glfwTerminate();
  return 0;
}
<|endoftext|>


<commit_before><commit_msg>this counter is not needed in sw/.. view.cxx, thanks cppcheck<commit_after><|endoftext|>


<commit_before>
#include "../common.h"
#include "gamefw.h"

#include <glm/gtc/matrix_projection.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/euler_angles.hpp>

using namespace gamefw;

Renderer::Renderer(const GLuint display_width, const GLuint display_height) :
    m_display_width((float) display_width),
    m_display_height((float) display_height),
    m_aspect_ratio((float) display_width / (float) display_height),
    m_camera(new Entity())
{
    initBuffers(display_width, display_height);
    m_camera->setName("Camera");
}

Renderer::~Renderer()
{
    glDeleteRenderbuffers(1, &m_depth_stencil_buffers.gbuffer);
    glDeleteRenderbuffers(1, &m_depth_stencil_buffers.pbuffer);
    glDeleteFramebuffers(1, &m_fbo.gbuffer);
    glDeleteFramebuffers(1, &m_fbo.pbuffer);
    glDeleteFramebuffers(1, &m_fbo.ppbuffer);

    // Delete manually allocated textures.
    shared_ptr<RenderJob> gbuffer_renderjob = m_gbuffer.getRenderJob();
    glDeleteTextures(gbuffer_renderjob->m_num_textures,
                     gbuffer_renderjob->m_textures);
    delete [] gbuffer_renderjob->m_textures;
    gbuffer_renderjob->m_num_textures = 0;

    shared_ptr<RenderJob> pbuffer_renderjob = m_pbuffer.getRenderJob();
    glDeleteTextures(pbuffer_renderjob->m_num_textures,
                     pbuffer_renderjob->m_textures);
    delete [] pbuffer_renderjob->m_textures;
    pbuffer_renderjob->m_num_textures = 0;

    shared_ptr<RenderJob> ppbuffer_renderjob = m_ppbuffer.getRenderJob();
    // Shared textures with gbuffer.
    ppbuffer_renderjob->m_num_textures = 0;
}

void Renderer::createDepthStencilBuffer(GLuint* buffer, const GLuint width,
                                        const GLuint height)
{
    glGenRenderbuffers(1, buffer);
    glBindRenderbuffer(GL_RENDERBUFFER, m_depth_stencil_buffers.gbuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH32F_STENCIL8, width, height);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER,
                              GL_DEPTH_STENCIL_ATTACHMENT,
                              GL_RENDERBUFFER, m_depth_stencil_buffers.gbuffer);
}

void Renderer::texParametersForRenderTargets() const
{
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1000);
}

bool Renderer::checkFramebuffer() const
{
    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    string error = "Framebuffer object error: ";

    switch (status)
    {
    case GL_FRAMEBUFFER_UNDEFINED:
        LOG(logERROR) << error << "GL_FRAMEBUFFER_UNDEFINED";
        break;
    case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
        LOG(logERROR) << error << "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
        break;
    case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
        LOG(logERROR) << error << "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
        break;
    case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
        LOG(logERROR) << error << "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER";
        break;
    case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
        LOG(logERROR) << error << "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER";
        break;
    case GL_FRAMEBUFFER_UNSUPPORTED:
        LOG(logERROR) << error << "GL_FRAMEBUFFER_UNSUPPORTED";
        break;
    case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
        LOG(logERROR) << error << "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE";
        break;
    case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS:
        LOG(logERROR) << error << "GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS";
        break;
    }

    return status == GL_FRAMEBUFFER_COMPLETE;
}

void Renderer::createTexturesForFBO(shared_ptr<RenderJob> renderjob,
                                    const GLuint num_textures,
                                    const GLenum internalformats[],
                                    const GLuint size_divisor[],
                                    const GLenum types[])
{
    renderjob->m_textures = new GLuint[num_textures];
    renderjob->m_num_textures = num_textures;
    glGenTextures(num_textures, renderjob->m_textures);

    for (int i = 0; i < num_textures; i++) {
        glBindTexture(GL_TEXTURE_2D, renderjob->m_textures[i]);

        texParametersForRenderTargets();

        glTexImage2D(
            GL_TEXTURE_2D,
            0,
            internalformats[i],
            m_display_width / size_divisor[i],
            m_display_height / size_divisor[i],
            0,
            GL_RGB,
            types[i],
            0
        );

        GLint attachment = GL_COLOR_ATTACHMENT0 + i;

        glFramebufferTexture(GL_FRAMEBUFFER, attachment,
                             renderjob->m_textures[i], 0);
    }
}

void Renderer::initBuffers(const GLuint width, const GLuint height)
{
    int num_textures = 4;

    // GBUFFER STAGE

    {
        m_gbuffer = Locator::getFileService().createEntity("gbuffer");
        glGenFramebuffers(1, &m_fbo.gbuffer);
        glBindFramebuffer(GL_FRAMEBUFFER, m_fbo.gbuffer);

        glActiveTexture(GL_TEXTURE0);
        shared_ptr<RenderJob> gbuffer_renderjob = m_gbuffer.getRenderJob();
        gbuffer_renderjob->m_textures = new GLuint[num_textures];
        gbuffer_renderjob->m_num_textures = num_textures;
        glGenTextures(num_textures, gbuffer_renderjob->m_textures);

        for (int i = 0; i < num_textures; i++) {
            glBindTexture(GL_TEXTURE_2D, gbuffer_renderjob->m_textures[i]);

            texParametersForRenderTargets();

            GLenum internalformat, type;
            switch (i) {
            case(renderjob_enums::OUTG_NORMAL):
                internalformat = GL_RGB16F;
                type = GL_FLOAT;
                break;

            case(renderjob_enums::OUTG_POSITION):
                internalformat = GL_RGB32F;
                type = GL_FLOAT;
                break;

            default:
                internalformat = GL_RGB8;
                type = GL_UNSIGNED_BYTE;
                break;
            }
            glTexImage2D(
                GL_TEXTURE_2D,
                0,
                internalformat,
                width,
                height,
                0,
                GL_RGB,
                type,
                0
            );

            GLint attachment = GL_COLOR_ATTACHMENT0 + i;

            glFramebufferTexture(GL_FRAMEBUFFER, attachment,
                                 gbuffer_renderjob->m_textures[i], 0);
        }

        createDepthStencilBuffer(&m_depth_stencil_buffers.gbuffer, width, height);

        bool status = checkFramebuffer();
        assert(status);

        GLenum draw_buffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,
                                 GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3
                                };
        glDrawBuffers(4, draw_buffers);

        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }

    // PBUFFER STAGE.
    {
        m_pbuffer = Locator::getFileService().createEntity("pbuffer");

        glGenFramebuffers(1, &m_fbo.pbuffer);
        glBindFramebuffer(GL_FRAMEBUFFER, m_fbo.pbuffer);

        glActiveTexture(GL_TEXTURE0);
        shared_ptr<RenderJob> pbuffer_renderjob = m_pbuffer.getRenderJob();
        pbuffer_renderjob->m_textures = new GLuint[num_textures];
        pbuffer_renderjob->m_num_textures = num_textures;
        glGenTextures(num_textures, pbuffer_renderjob->m_textures);

        for (int i = 0; i < num_textures; i++) {
            glBindTexture(GL_TEXTURE_2D, pbuffer_renderjob->m_textures[i]);

            texParametersForRenderTargets();

            glTexImage2D(
                GL_TEXTURE_2D,
                0,
                GL_RGB8,
                width,
                height,
                0,
                GL_RGB,
                GL_UNSIGNED_BYTE,
                0
            );

            GLint attachment = GL_COLOR_ATTACHMENT0 + i;

            glFramebufferTexture(GL_FRAMEBUFFER, attachment,
                                 pbuffer_renderjob->m_textures[i], 0);
        }

        createDepthStencilBuffer(&m_depth_stencil_buffers.pbuffer, width, height);

        bool status = checkFramebuffer();
        assert(status);

        GLenum draw_buffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,
                                 GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3
                                };
        glDrawBuffers(4, draw_buffers);

        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }

    // POSTPROCESSING STAGE
    {
        m_ppbuffer = Locator::getFileService().createEntity("ppbuffer");
        shared_ptr<RenderJob> ppbuffer_renderjob = m_ppbuffer.getRenderJob();

        // Use gbuffers diffuse and specular textures.
        m_fbo.ppbuffer = m_fbo.gbuffer;
        ppbuffer_renderjob->m_textures = m_gbuffer.getRenderJob()->m_textures;
        ppbuffer_renderjob->m_num_textures = 2;
    }
}

void Renderer::render()
{
    glEnable(GL_DEPTH_TEST);

    renderGBuffers();

    glDisable(GL_DEPTH_TEST);

    renderPBuffers();

    renderPPBuffers();

    glBindFramebuffer(GL_FRAMEBUFFER, 0); // Bind main window's framebuffer.
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    renderEntity(m_ppbuffer);
}

void Renderer::addToRenderQueue(const Entity& entity)
{
    m_render_queue.push(&entity);
}

void Renderer::renderEntity(const Entity& entity)
{
    shared_ptr<RenderJob> renderjob = entity.getRenderJob();
    GLuint program_id = renderjob->getShaderProgramID();
    glUseProgram(program_id);

    // Load textures.
    for (uint i = 0; i < renderjob->m_num_textures; i++) {
        glActiveTexture(GL_TEXTURE0 + i);
        glBindTexture(GL_TEXTURE_2D, renderjob->m_textures[i]);
        string uniform_name("texture");
        uniform_name += (char) '0' + i;
        GLint location = glGetUniformLocation(program_id, uniform_name.c_str());
        glUniform1i(location, i);
    }

    // Bind material uniform block.
    if (renderjob->m_uniforms.materials != 0) {
        glBindBufferBase(GL_UNIFORM_BUFFER, renderjob_enums::MATERIAL,
                         renderjob->m_uniforms.materials);
    }

    // Calculate and bind mvp.

    // Model orientation ...
   glm::mat4 model(glm::yawPitchRoll(entity.m_orientation.yaw,
                                    entity.m_orientation.pitch,
                                    entity.m_orientation.roll));
    // ... + translation
    model[3] = glm::vec4(entity.m_position, 1.0);

    // Normal transform.
    glm::mat4 normalmatrix = glm::transpose(glm::inverse(model));

    // View transform.
    glm::vec3 view_pos(0.0f, 0.0f, 0.0f);
    glm::mat4 view_orientation(glm::yawPitchRoll(0.0f, 0.0f, 0.0f));
    glm::mat4 view(glm::translate(glm::mat4(1.0f), -view_pos) * view_orientation);

    // Projection transform
    glm::mat4 projection = glm::perspective(45.0f, m_aspect_ratio, 0.1f, 100.f);

    glm::mat4 mvp = projection * view * model;

    // Bind the matrices to uniforms.
    GLint location_mvp = glGetUniformLocation(program_id, "mvp");
    glUniformMatrix4fv(location_mvp, 1, GL_FALSE, glm::value_ptr(mvp));
    GLint location_model = glGetUniformLocation(program_id, "model");
    glUniformMatrix4fv(location_model, 1, GL_FALSE, glm::value_ptr(model));
    GLint location_normalmatrix = glGetUniformLocation(program_id, "normalmatrix");
    glUniformMatrix4fv(location_normalmatrix, 1, GL_FALSE, glm::value_ptr(normalmatrix));

    // Bind display height and width uniforms.
    GLint location_width = glGetUniformLocation(program_id, "display_width");
    glUniform1f(location_width, m_display_width);
    GLint location_height = glGetUniformLocation(program_id, "display_height");
    glUniform1f(location_height, m_display_height);

    glBindVertexArray(renderjob->m_buffer_objects.vao);

    glEnableVertexAttribArray(renderjob_enums::POSITION);
    glEnableVertexAttribArray(renderjob_enums::NORMAL);
    glEnableVertexAttribArray(renderjob_enums::TEXCOORD);
    glEnableVertexAttribArray(renderjob_enums::MATERIAL_IDX);
    glDrawElements(GL_TRIANGLES, renderjob->m_vertex_count, GL_UNSIGNED_SHORT, 0);
    glDisableVertexAttribArray(renderjob_enums::POSITION);
    glDisableVertexAttribArray(renderjob_enums::NORMAL);
    glDisableVertexAttribArray(renderjob_enums::TEXCOORD);
    glDisableVertexAttribArray(renderjob_enums::MATERIAL_IDX);

    // Cleanup.
    glBindVertexArray(0);
    glUseProgram(0);
    glBindBufferBase(GL_UNIFORM_BUFFER, renderjob_enums::MATERIAL, 0);
}

void Renderer::renderGBuffers()
{
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo.gbuffer);
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    while (!m_render_queue.empty()) {
        const Entity* current_entity = m_render_queue.front();
        m_render_queue.pop();
        renderEntity(*current_entity);
    }
}

void Renderer::renderPBuffers()
{
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo.pbuffer);
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    GLuint program_id = m_gbuffer.getRenderJob()->getShaderProgramID();
    glUseProgram(program_id);
    glUniform3fv(glGetUniformLocation(program_id, "viewer_position"),
                 1, glm::value_ptr(m_camera->m_position));
    renderEntity(m_gbuffer);

}

void gamefw::Renderer::renderPPBuffers()
{
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo.ppbuffer);
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    renderEntity(m_pbuffer);
}
<commit_msg>Refactor Renderer FBO texture generation.<commit_after>
#include "../common.h"
#include "gamefw.h"

#include <glm/gtc/matrix_projection.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/euler_angles.hpp>

using namespace gamefw;

Renderer::Renderer(const GLuint display_width, const GLuint display_height) :
    m_display_width((float) display_width),
    m_display_height((float) display_height),
    m_aspect_ratio((float) display_width / (float) display_height),
    m_camera(new Entity())
{
    initBuffers(display_width, display_height);
    m_camera->setName("Camera");
}

Renderer::~Renderer()
{
    glDeleteRenderbuffers(1, &m_depth_stencil_buffers.gbuffer);
    glDeleteRenderbuffers(1, &m_depth_stencil_buffers.pbuffer);
    glDeleteFramebuffers(1, &m_fbo.gbuffer);
    glDeleteFramebuffers(1, &m_fbo.pbuffer);
    glDeleteFramebuffers(1, &m_fbo.ppbuffer);

    // Delete manually allocated textures.
    shared_ptr<RenderJob> gbuffer_renderjob = m_gbuffer.getRenderJob();
    glDeleteTextures(gbuffer_renderjob->m_num_textures,
                     gbuffer_renderjob->m_textures);
    delete [] gbuffer_renderjob->m_textures;
    gbuffer_renderjob->m_num_textures = 0;

    shared_ptr<RenderJob> pbuffer_renderjob = m_pbuffer.getRenderJob();
    glDeleteTextures(pbuffer_renderjob->m_num_textures,
                     pbuffer_renderjob->m_textures);
    delete [] pbuffer_renderjob->m_textures;
    pbuffer_renderjob->m_num_textures = 0;

    shared_ptr<RenderJob> ppbuffer_renderjob = m_ppbuffer.getRenderJob();
    // Shared textures with gbuffer.
    ppbuffer_renderjob->m_num_textures = 0;
}

void Renderer::createDepthStencilBuffer(GLuint* buffer, const GLuint width,
                                        const GLuint height)
{
    glGenRenderbuffers(1, buffer);
    glBindRenderbuffer(GL_RENDERBUFFER, m_depth_stencil_buffers.gbuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH32F_STENCIL8, width, height);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER,
                              GL_DEPTH_STENCIL_ATTACHMENT,
                              GL_RENDERBUFFER, m_depth_stencil_buffers.gbuffer);
}

void Renderer::texParametersForRenderTargets() const
{
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1000);
}

bool Renderer::checkFramebuffer() const
{
    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    string error = "Framebuffer object error: ";

    switch (status)
    {
    case GL_FRAMEBUFFER_UNDEFINED:
        LOG(logERROR) << error << "GL_FRAMEBUFFER_UNDEFINED";
        break;
    case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
        LOG(logERROR) << error << "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
        break;
    case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
        LOG(logERROR) << error << "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
        break;
    case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
        LOG(logERROR) << error << "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER";
        break;
    case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
        LOG(logERROR) << error << "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER";
        break;
    case GL_FRAMEBUFFER_UNSUPPORTED:
        LOG(logERROR) << error << "GL_FRAMEBUFFER_UNSUPPORTED";
        break;
    case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
        LOG(logERROR) << error << "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE";
        break;
    case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS:
        LOG(logERROR) << error << "GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS";
        break;
    }

    return status == GL_FRAMEBUFFER_COMPLETE;
}

void Renderer::createTexturesForFBO(shared_ptr<RenderJob> renderjob,
                                    const GLuint num_textures,
                                    const GLenum internalformats[],
                                    const GLuint size_divisor[],
                                    const GLenum types[])
{
    renderjob->m_textures = new GLuint[num_textures];
    renderjob->m_num_textures = num_textures;
    glGenTextures(num_textures, renderjob->m_textures);

    for (int i = 0; i < num_textures; i++) {
        glBindTexture(GL_TEXTURE_2D, renderjob->m_textures[i]);

        texParametersForRenderTargets();

        glTexImage2D(
            GL_TEXTURE_2D,
            0,
            internalformats[i],
            m_display_width / size_divisor[i],
            m_display_height / size_divisor[i],
            0,
            GL_RGB,
            types[i],
            0
        );

        GLint attachment = GL_COLOR_ATTACHMENT0 + i;

        glFramebufferTexture(GL_FRAMEBUFFER, attachment,
                             renderjob->m_textures[i], 0);
    }
}

void Renderer::initBuffers(const GLuint width, const GLuint height)
{
    int num_textures = 4;

    // GBUFFER STAGE

    {
        m_gbuffer = Locator::getFileService().createEntity("gbuffer");
        glGenFramebuffers(1, &m_fbo.gbuffer);
        glBindFramebuffer(GL_FRAMEBUFFER, m_fbo.gbuffer);

        const GLenum internalformats[] = {
            GL_RGB8,
            GL_RGB8,
            GL_RGB16F,
            GL_RGB32F
        };
        const GLuint size_divisor[] = {1, 1, 1, 1};
        const GLenum types[] = {
            GL_UNSIGNED_BYTE,
            GL_UNSIGNED_BYTE,
            GL_FLOAT,
            GL_FLOAT
        };

        glActiveTexture(GL_TEXTURE0);
        shared_ptr<RenderJob> gbuffer_renderjob = m_gbuffer.getRenderJob();

        createTexturesForFBO(gbuffer_renderjob, num_textures, internalformats,
                             size_divisor, types);

        createDepthStencilBuffer(&m_depth_stencil_buffers.gbuffer, width, height);

        bool status = checkFramebuffer();
        assert(status);
    }

    // PBUFFER STAGE.
    {
        m_pbuffer = Locator::getFileService().createEntity("pbuffer");

        glGenFramebuffers(1, &m_fbo.pbuffer);
        glBindFramebuffer(GL_FRAMEBUFFER, m_fbo.pbuffer);

        glActiveTexture(GL_TEXTURE0);
        shared_ptr<RenderJob> pbuffer_renderjob = m_pbuffer.getRenderJob();

        const GLenum internalformats[] = {
            GL_RGB8,
            GL_RGB8,
            GL_RGB8,
            GL_RGB8
        };
        const GLuint size_divisors[] = {1, 1, 1, 1};
        const GLenum types[] = {
            GL_UNSIGNED_BYTE,
            GL_UNSIGNED_BYTE,
            GL_UNSIGNED_BYTE,
            GL_UNSIGNED_BYTE
        };

        createTexturesForFBO(pbuffer_renderjob, num_textures, internalformats,
            size_divisors, types
        );

        createDepthStencilBuffer(&m_depth_stencil_buffers.pbuffer, width, height);

        bool status = checkFramebuffer();
        assert(status);

    }

    // POSTPROCESSING STAGE
    {
        m_ppbuffer = Locator::getFileService().createEntity("ppbuffer");
        shared_ptr<RenderJob> ppbuffer_renderjob = m_ppbuffer.getRenderJob();

        // Use gbuffers diffuse and specular textures.
        m_fbo.ppbuffer = m_fbo.gbuffer;
        ppbuffer_renderjob->m_textures = m_gbuffer.getRenderJob()->m_textures;
        ppbuffer_renderjob->m_num_textures = 2;
    }

    // Assign draw buffers.
    GLenum draw_buffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,
                             GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3
    };
    glBindFramebuffer(GL_FRAMEBUFFER, m_fbo.gbuffer);
    glDrawBuffers(4, draw_buffers);
    glBindFramebuffer(GL_FRAMEBUFFER, m_fbo.pbuffer);
    glDrawBuffers(4, draw_buffers);
    glBindFramebuffer(GL_FRAMEBUFFER, m_fbo.ppbuffer);
    glDrawBuffers(4, draw_buffers);

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

void Renderer::render()
{
    glEnable(GL_DEPTH_TEST);

    renderGBuffers();

    glDisable(GL_DEPTH_TEST);

    renderPBuffers();

    renderPPBuffers();

    glBindFramebuffer(GL_FRAMEBUFFER, 0); // Bind main window's framebuffer.
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    renderEntity(m_ppbuffer);
}

void Renderer::addToRenderQueue(const Entity& entity)
{
    m_render_queue.push(&entity);
}

void Renderer::renderEntity(const Entity& entity)
{
    shared_ptr<RenderJob> renderjob = entity.getRenderJob();
    GLuint program_id = renderjob->getShaderProgramID();
    glUseProgram(program_id);

    // Load textures.
    for (uint i = 0; i < renderjob->m_num_textures; i++) {
        glActiveTexture(GL_TEXTURE0 + i);
        glBindTexture(GL_TEXTURE_2D, renderjob->m_textures[i]);
        string uniform_name("texture");
        uniform_name += (char) '0' + i;
        GLint location = glGetUniformLocation(program_id, uniform_name.c_str());
        glUniform1i(location, i);
    }

    // Bind material uniform block.
    if (renderjob->m_uniforms.materials != 0) {
        glBindBufferBase(GL_UNIFORM_BUFFER, renderjob_enums::MATERIAL,
                         renderjob->m_uniforms.materials);
    }

    // Calculate and bind mvp.

    // Model orientation ...
   glm::mat4 model(glm::yawPitchRoll(entity.m_orientation.yaw,
                                    entity.m_orientation.pitch,
                                    entity.m_orientation.roll));
    // ... + translation
    model[3] = glm::vec4(entity.m_position, 1.0);

    // Normal transform.
    glm::mat4 normalmatrix = glm::transpose(glm::inverse(model));

    // View transform.
    glm::vec3 view_pos(0.0f, 0.0f, 0.0f);
    glm::mat4 view_orientation(glm::yawPitchRoll(0.0f, 0.0f, 0.0f));
    glm::mat4 view(glm::translate(glm::mat4(1.0f), -view_pos) * view_orientation);

    // Projection transform
    glm::mat4 projection = glm::perspective(45.0f, m_aspect_ratio, 0.1f, 100.f);

    glm::mat4 mvp = projection * view * model;

    // Bind the matrices to uniforms.
    GLint location_mvp = glGetUniformLocation(program_id, "mvp");
    glUniformMatrix4fv(location_mvp, 1, GL_FALSE, glm::value_ptr(mvp));
    GLint location_model = glGetUniformLocation(program_id, "model");
    glUniformMatrix4fv(location_model, 1, GL_FALSE, glm::value_ptr(model));
    GLint location_normalmatrix = glGetUniformLocation(program_id, "normalmatrix");
    glUniformMatrix4fv(location_normalmatrix, 1, GL_FALSE, glm::value_ptr(normalmatrix));

    // Bind display height and width uniforms.
    GLint location_width = glGetUniformLocation(program_id, "display_width");
    glUniform1f(location_width, m_display_width);
    GLint location_height = glGetUniformLocation(program_id, "display_height");
    glUniform1f(location_height, m_display_height);

    glBindVertexArray(renderjob->m_buffer_objects.vao);

    glEnableVertexAttribArray(renderjob_enums::POSITION);
    glEnableVertexAttribArray(renderjob_enums::NORMAL);
    glEnableVertexAttribArray(renderjob_enums::TEXCOORD);
    glEnableVertexAttribArray(renderjob_enums::MATERIAL_IDX);
    glDrawElements(GL_TRIANGLES, renderjob->m_vertex_count, GL_UNSIGNED_SHORT, 0);
    glDisableVertexAttribArray(renderjob_enums::POSITION);
    glDisableVertexAttribArray(renderjob_enums::NORMAL);
    glDisableVertexAttribArray(renderjob_enums::TEXCOORD);
    glDisableVertexAttribArray(renderjob_enums::MATERIAL_IDX);

    // Cleanup.
    glBindVertexArray(0);
    glUseProgram(0);
    glBindBufferBase(GL_UNIFORM_BUFFER, renderjob_enums::MATERIAL, 0);
}

void Renderer::renderGBuffers()
{
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo.gbuffer);
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    while (!m_render_queue.empty()) {
        const Entity* current_entity = m_render_queue.front();
        m_render_queue.pop();
        renderEntity(*current_entity);
    }
}

void Renderer::renderPBuffers()
{
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo.pbuffer);
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    GLuint program_id = m_gbuffer.getRenderJob()->getShaderProgramID();
    glUseProgram(program_id);
    glUniform3fv(glGetUniformLocation(program_id, "viewer_position"),
                 1, glm::value_ptr(m_camera->m_position));
    renderEntity(m_gbuffer);

}

void gamefw::Renderer::renderPPBuffers()
{
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo.ppbuffer);
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    renderEntity(m_pbuffer);
}
<|endoftext|>


<commit_before>//===========================================
//  Lumina-DE source code
//  Copyright (c) 2012-2015, Ken Moore
//  Available under the 3-clause BSD license
//  See the LICENSE file for full details
//===========================================
#include "LClock.h"
#include "LSession.h"
#include <LuminaThemes.h>
#include <LuminaXDG.h>

LClock::LClock(QWidget *parent, QString id, bool horizontal) : LPPlugin(parent, id, horizontal){
  button = new QToolButton(this);
    button->setAutoRaise(true);
    button->setToolButtonStyle(Qt::ToolButtonTextOnly);
    button->setStyleSheet("font-weight: bold;");
    button->setPopupMode(QToolButton::DelayedPopup); //make sure it runs the update routine first
    button->setMenu(new QMenu());
    connect(button, SIGNAL(clicked()), this, SLOT(openMenu()));
    connect(button->menu(), SIGNAL(aboutToHide()), this, SIGNAL(MenuClosed()));
  calendar = new QCalendarWidget(this);
  calAct = new QWidgetAction(this);
	calAct->setDefaultWidget(calendar);
  TZMenu = new QMenu(this);
    connect(TZMenu, SIGNAL(triggered(QAction*)), this, SLOT(ChangeTZ(QAction*)) );

  //Now assemble the menu
  button->menu()->addAction(calAct);
  button->menu()->addMenu(TZMenu);

  this->layout()->setContentsMargins(0,0,0,0); //reserve some space on left/right
  this->layout()->addWidget(button);

  //Setup the timer
  timer = new QTimer();
  //Load all the initial settings
  updateFormats();
  LocaleChange();
  ThemeChange();
  OrientationChange();
  //Now connect/start the timer
  connect(timer,SIGNAL(timeout()), this, SLOT(updateTime()) );
  connect(QApplication::instance(), SIGNAL(SessionConfigChanged()), this, SLOT(updateFormats()) );
  timer->start();
}

LClock::~LClock(){
  timer->stop();
  delete timer;
}

void LClock::updateTime(bool adjustformat){
  QDateTime CT = QDateTime::currentDateTime();
  //Now update the display
  QString label;
  QString timelabel;
  QString datelabel;
  if(deftime){ timelabel = CT.time().toString(Qt::DefaultLocaleShortDate) ; }
  else{ timelabel=CT.toString(timefmt); }
  if(defdate){ datelabel = CT.date().toString(Qt::DefaultLocaleShortDate); }
  else{ datelabel = CT.toString(datefmt); }
  if(datetimeorder == "dateonly"){
	  label = datelabel;
	  button->setToolTip(timelabel);
  }else if(datetimeorder == "timedate"){
	  label = timelabel + "\n" + datelabel;
	  button->setToolTip("");
  }else if(datetimeorder == "datetime"){
	  label = datelabel + "\n" + timelabel;
	  button->setToolTip("");
  }else{
	 label = timelabel;
	button->setToolTip(datelabel);
  }
  if( this->layout()->direction() == QBoxLayout::TopToBottom ){
    //different routine for vertical text (need newlines instead of spaces)
    label.replace(" ","\n");
  }
  if(adjustformat){
   //Check the font/spacing for the display and adjust as necessary
    /*double efflines = label.count("\n")+1; //effective lines (with wordwrap)
    if( (button->fontMetrics().height()*efflines) > button->height() ){
      //Force a pixel metric font size to fit everything
      int szH = qRound( (button->height() - button->fontMetrics().lineSpacing() )/efflines );
      //Need to supply a *width* pixel, not a height metric
      int szW = qRound( (szH*button->fontMetrics().maxWidth())/( (double) button->fontMetrics().height()) );
      qDebug() << "Change Clock font:" << button->height() << szH << szW << efflines << button->fontMetrics().height() << button->fontMetrics().lineSpacing();
      button->setStyleSheet("font-weight: bold; font-size: "+QString::number(szW)+"px;");
    }else{
      button->setStyleSheet("font-weight: bold;");
    }*/
  }
  button->setText(label);

}

void LClock::updateFormats(){
  qDebug() << "Updating clock format";
  timefmt = LSession::handle()->sessionSettings()->value("TimeFormat","").toString();
  datefmt = LSession::handle()->sessionSettings()->value("DateFormat","").toString();
  deftime = timefmt.simplified().isEmpty();
  defdate = datefmt.simplified().isEmpty();
  //Adjust the timer interval based on the smallest unit displayed
  if(deftime){ timer->setInterval(500); } //1/2 second
  else if(timefmt.contains("z")){ timer->setInterval(1); } //every millisecond (smallest unit)
  else if(timefmt.contains("s")){ timer->setInterval(500); } //1/2 second
  else if(timefmt.contains("m")){ timer->setInterval(2000); } //2 seconds
  else{ timer->setInterval(1000); } //unknown format - use 1 second interval
  datetimeorder = LSession::handle()->sessionSettings()->value("DateTimeOrder", "timeonly").toString().toLower();
  updateTime(true);
}

void LClock::updateMenu(){
  QDateTime cdt = QDateTime::currentDateTime();
  TZMenu->setTitle(QString(tr("Time Zone (%1)")).arg(cdt.timeZoneAbbreviation()) );
  calendar->showToday(); //make sure the current month is visible
  calendar->setSelectedDate(QDate::currentDate()); //select the actual date for today
}

void LClock::openMenu(){
  updateMenu();
  button->showMenu();
}

void LClock::closeMenu(){
  button->menu()->hide();
}

void LClock::ChangeTZ(QAction *act){
  LTHEME::setCustomEnvSetting("TZ",act->whatsThis());
  QTimer::singleShot(500, this, SLOT(updateTime()) );
}

void LClock::LocaleChange(){
  //Refresh all the time zone information
  TZMenu->clear();
    TZMenu->addAction(tr("Use System Time"));
    TZMenu->addSeparator();
  QList<QByteArray> TZList = QTimeZone::availableTimeZoneIds();
  //Orgnize time zones for smaller menus (Continent/Country/City)
  // Note: id = Continent/City
  QStringList info;
  for(int i=0; i<TZList.length(); i++){
    QTimeZone tz(TZList[i]);
    if(!QString(tz.id()).contains("/")){ continue; }
    info << "::::"+QString(tz.id()).section("/",0,0)+"::::"+QLocale::countryToString(tz.country())+"::::"+QString(tz.id()).section("/",1,100).replace("_"," ")+"::::"+QString(tz.id());
  }
  //Now sort alphabetically
  info.sort();
  //Now create the menu tree
  QString continent, country; //current continent/country
  QMenu *tmpC=0; //continent menu
  QMenu *tmpCM=0; //country menu
  for(int i=0; i<info.length(); i++){
    //Check if different continent
    if(info[i].section("::::",1,1)!=continent){
      if(tmpC!=0){
        if(tmpCM!=0 && !tmpCM->isEmpty()){
	  tmpC->addMenu(tmpCM);
	}
	if(!tmpC->isEmpty()){ TZMenu->addMenu(tmpC); }
      }
      tmpC = new QMenu(this);
	tmpC->setTitle(info[i].section("::::",1,1));
      tmpCM = new QMenu(this);
	  tmpCM->setTitle(info[i].section("::::",2,2));
    //Check if different country
    }else if(info[i].section("::::",2,2)!=country){
        if(tmpC!=0 && tmpCM!=0 && !tmpCM->isEmpty()){
	  tmpC->addMenu(tmpCM);
	}
	tmpCM = new QMenu(this);
	  tmpCM->setTitle(info[i].section("::::",2,2));
    }
    //Now create the entry within the country menu
    if(tmpCM!=0){
      QAction *act = new QAction(info[i].section("::::",3,3), this);
	act->setWhatsThis(info[i].section("::::",4,4) );
      tmpCM->addAction(act);
    }
    //Save the values for the next run
    continent = info[i].section("::::",1,1);
    country = info[i].section("::::",2,2);

    if(i== info.length()-1){
      //last go through - save all menus
      if(tmpCM!=0 && tmpC!=0 && !tmpCM->isEmpty()){ tmpC->addMenu(tmpCM); }
      if(tmpC!=0 && !tmpC->isEmpty()){ TZMenu->addMenu(tmpC); }
    }
  }

  //qDebug() << "Found Time Zones:" << TZList.length();
  /*QDateTime cur = QDateTime::currentDateTime();

  QMenu *tmpCM = 0;
  QString ccat; //current category
  QStringList catAbb;
  for(int i=0; i<TZList.length(); i++){
    QTimeZone tmp(TZList[i]);
    QString abbr = tmp.abbreviation(cur);
    if(abbr.startsWith("UTC")){ continue; } //skip all the manual options at the end of the list
    if(QString(tmp.id()).section("/",0,0)!=ccat){
      //New category - save the old one and start a new one
      if(!catAbb.isEmpty()){
	catAbb.sort();
	QMenu *tmpM = new QMenu(this);
	  tmpM->setTitle(ccat);
	for(int j=0; j<catAbb.length(); j++){
	  QAction *act = new QAction(catAbb[j].section("::::",3,3)+" ("+catAbb[j].section("::::",1,1)+")",this);
	    act->setWhatsThis(catAbb[j].section("::::",2,2));
	  tmpM->addAction(act);
	}
	TZMenu->addMenu(tmpM);
      }
      ccat = QString(tmp.id()).section("/",0,0);
      catAbb.clear();
    }
    if(!catAbb.filter("::::"+abbr+"::::").isEmpty()){ continue; } //duplicate timezone/abbreviation for this cat
    catAbb << "::::"+abbr+"::::"+tmp.id()+"::::"+tmp.displayName(QTimeZone::GenericTime, QTimeZone::LongName); //add new abbreviation to the list
  }
  //Now add the last category to the menu
  if(tmpCM!=0 && !catAbb.isEmpty()){
    catAbb.sort();
    QMenu *tmpM = new QMenu(this);
      tmpM->setTitle(ccat);
    for(int j=0; j<catAbb.length(); j++){
	QAction *act = new QAction(catAbb[j].section("::::",3,3)+" ("+catAbb[j].section("::::",1,1)+")",this);
	  act->setWhatsThis(catAbb[j].section("::::",2,2));
	tmpM->addAction(act);
    }
    TZMenu->addMenu(tmpM);
  }*/

}

void LClock::ThemeChange(){
  TZMenu->setIcon(LXDG::findIcon("clock",""));
}

void LClock::OrientationChange(){
  if(this->layout()->direction()==QBoxLayout::LeftToRight){
    this->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
    button->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
  }else{
    this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
    button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
  }
  updateTime(true); //re-adjust the font/spacings
  this->layout()->update();
}
<commit_msg>For the clock plugin, add a smarter minimum width based on the time format chosen. This should prevent the clock from changing sizes regularly if the font is not mono-spaced or non-padded seconds/minutes is desired.<commit_after>//===========================================
//  Lumina-DE source code
//  Copyright (c) 2012-2015, Ken Moore
//  Available under the 3-clause BSD license
//  See the LICENSE file for full details
//===========================================
#include "LClock.h"
#include "LSession.h"
#include <LuminaThemes.h>
#include <LuminaXDG.h>

LClock::LClock(QWidget *parent, QString id, bool horizontal) : LPPlugin(parent, id, horizontal){
  button = new QToolButton(this);
    button->setAutoRaise(true);
    button->setToolButtonStyle(Qt::ToolButtonTextOnly);
    button->setStyleSheet("font-weight: bold;");
    button->setPopupMode(QToolButton::DelayedPopup); //make sure it runs the update routine first
    button->setMenu(new QMenu());
    connect(button, SIGNAL(clicked()), this, SLOT(openMenu()));
    connect(button->menu(), SIGNAL(aboutToHide()), this, SIGNAL(MenuClosed()));
  calendar = new QCalendarWidget(this);
  calAct = new QWidgetAction(this);
	calAct->setDefaultWidget(calendar);
  TZMenu = new QMenu(this);
    connect(TZMenu, SIGNAL(triggered(QAction*)), this, SLOT(ChangeTZ(QAction*)) );

  //Now assemble the menu
  button->menu()->addAction(calAct);
  button->menu()->addMenu(TZMenu);

  this->layout()->setContentsMargins(0,0,0,0); //reserve some space on left/right
  this->layout()->addWidget(button);

  //Setup the timer
  timer = new QTimer();
  //Load all the initial settings
  updateFormats();
  LocaleChange();
  ThemeChange();
  OrientationChange();
  //Now connect/start the timer
  connect(timer,SIGNAL(timeout()), this, SLOT(updateTime()) );
  connect(QApplication::instance(), SIGNAL(SessionConfigChanged()), this, SLOT(updateFormats()) );
  timer->start();
}

LClock::~LClock(){
  timer->stop();
  delete timer;
}

void LClock::updateTime(bool adjustformat){
  QDateTime CT = QDateTime::currentDateTime();
  //Now update the display
  QString label;
  QString timelabel;
  QString datelabel;
  if(deftime){ timelabel = CT.time().toString(Qt::DefaultLocaleShortDate) ; }
  else{ timelabel=CT.toString(timefmt); }
  if(defdate){ datelabel = CT.date().toString(Qt::DefaultLocaleShortDate); }
  else{ datelabel = CT.toString(datefmt); }
  if(datetimeorder == "dateonly"){
	  label = datelabel;
	  button->setToolTip(timelabel);
  }else if(datetimeorder == "timedate"){
	  label = timelabel + "\n" + datelabel;
	  button->setToolTip("");
  }else if(datetimeorder == "datetime"){
	  label = datelabel + "\n" + timelabel;
	  button->setToolTip("");
  }else{
	 label = timelabel;
	button->setToolTip(datelabel);
  }
  if( this->layout()->direction() == QBoxLayout::TopToBottom ){
    //different routine for vertical text (need newlines instead of spaces)
    label.replace(" ","\n");
  }
  if(adjustformat){
   //Check the font/spacing for the display and adjust as necessary
    /*double efflines = label.count("\n")+1; //effective lines (with wordwrap)
    if( (button->fontMetrics().height()*efflines) > button->height() ){
      //Force a pixel metric font size to fit everything
      int szH = qRound( (button->height() - button->fontMetrics().lineSpacing() )/efflines );
      //Need to supply a *width* pixel, not a height metric
      int szW = qRound( (szH*button->fontMetrics().maxWidth())/( (double) button->fontMetrics().height()) );
      qDebug() << "Change Clock font:" << button->height() << szH << szW << efflines << button->fontMetrics().height() << button->fontMetrics().lineSpacing();
      button->setStyleSheet("font-weight: bold; font-size: "+QString::number(szW)+"px;");
    }else{
      button->setStyleSheet("font-weight: bold;");
    }*/
  }
  button->setText(label);

}

void LClock::updateFormats(){
  qDebug() << "Updating clock format";
  timefmt = LSession::handle()->sessionSettings()->value("TimeFormat","").toString();
  datefmt = LSession::handle()->sessionSettings()->value("DateFormat","").toString();
  deftime = timefmt.simplified().isEmpty();
  defdate = datefmt.simplified().isEmpty();
  this->setMinimumSize(button->fontMetrics().width(timefmt+"MMM")+10, 5);
  //Adjust the timer interval based on the smallest unit displayed
  if(deftime){ timer->setInterval(500); } //1/2 second
  else if(timefmt.contains("z")){ timer->setInterval(1); } //every millisecond (smallest unit)
  else if(timefmt.contains("s")){ timer->setInterval(500); } //1/2 second
  else if(timefmt.contains("m")){ timer->setInterval(2000); } //2 seconds
  else{ timer->setInterval(1000); } //unknown format - use 1 second interval
  datetimeorder = LSession::handle()->sessionSettings()->value("DateTimeOrder", "timeonly").toString().toLower();
  updateTime(true);
}

void LClock::updateMenu(){
  QDateTime cdt = QDateTime::currentDateTime();
  TZMenu->setTitle(QString(tr("Time Zone (%1)")).arg(cdt.timeZoneAbbreviation()) );
  calendar->showToday(); //make sure the current month is visible
  calendar->setSelectedDate(QDate::currentDate()); //select the actual date for today
}

void LClock::openMenu(){
  updateMenu();
  button->showMenu();
}

void LClock::closeMenu(){
  button->menu()->hide();
}

void LClock::ChangeTZ(QAction *act){
  LTHEME::setCustomEnvSetting("TZ",act->whatsThis());
  QTimer::singleShot(500, this, SLOT(updateTime()) );
}

void LClock::LocaleChange(){
  //Refresh all the time zone information
  TZMenu->clear();
    TZMenu->addAction(tr("Use System Time"));
    TZMenu->addSeparator();
  QList<QByteArray> TZList = QTimeZone::availableTimeZoneIds();
  //Orgnize time zones for smaller menus (Continent/Country/City)
  // Note: id = Continent/City
  QStringList info;
  for(int i=0; i<TZList.length(); i++){
    QTimeZone tz(TZList[i]);
    if(!QString(tz.id()).contains("/")){ continue; }
    info << "::::"+QString(tz.id()).section("/",0,0)+"::::"+QLocale::countryToString(tz.country())+"::::"+QString(tz.id()).section("/",1,100).replace("_"," ")+"::::"+QString(tz.id());
  }
  //Now sort alphabetically
  info.sort();
  //Now create the menu tree
  QString continent, country; //current continent/country
  QMenu *tmpC=0; //continent menu
  QMenu *tmpCM=0; //country menu
  for(int i=0; i<info.length(); i++){
    //Check if different continent
    if(info[i].section("::::",1,1)!=continent){
      if(tmpC!=0){
        if(tmpCM!=0 && !tmpCM->isEmpty()){
	  tmpC->addMenu(tmpCM);
	}
	if(!tmpC->isEmpty()){ TZMenu->addMenu(tmpC); }
      }
      tmpC = new QMenu(this);
	tmpC->setTitle(info[i].section("::::",1,1));
      tmpCM = new QMenu(this);
	  tmpCM->setTitle(info[i].section("::::",2,2));
    //Check if different country
    }else if(info[i].section("::::",2,2)!=country){
        if(tmpC!=0 && tmpCM!=0 && !tmpCM->isEmpty()){
	  tmpC->addMenu(tmpCM);
	}
	tmpCM = new QMenu(this);
	  tmpCM->setTitle(info[i].section("::::",2,2));
    }
    //Now create the entry within the country menu
    if(tmpCM!=0){
      QAction *act = new QAction(info[i].section("::::",3,3), this);
	act->setWhatsThis(info[i].section("::::",4,4) );
      tmpCM->addAction(act);
    }
    //Save the values for the next run
    continent = info[i].section("::::",1,1);
    country = info[i].section("::::",2,2);

    if(i== info.length()-1){
      //last go through - save all menus
      if(tmpCM!=0 && tmpC!=0 && !tmpCM->isEmpty()){ tmpC->addMenu(tmpCM); }
      if(tmpC!=0 && !tmpC->isEmpty()){ TZMenu->addMenu(tmpC); }
    }
  }

}

void LClock::ThemeChange(){
  TZMenu->setIcon(LXDG::findIcon("clock",""));
}

void LClock::OrientationChange(){
  if(this->layout()->direction()==QBoxLayout::LeftToRight){
    this->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
    button->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
  }else{
    this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
    button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
  }
  updateTime(true); //re-adjust the font/spacings
  this->layout()->update();
}
<|endoftext|>


<commit_before>/*  Adapted from diffdrive gazebo plugin.
    Copyright (c) 2010, Daniel Hewlett, Antons Rebguns
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
        * Redistributions of source code must retain the above copyright
        notice, this list of conditions and the following disclaimer.
        * Redistributions in binary form must reproduce the above copyright
        notice, this list of conditions and the following disclaimer in the
        documentation and/or other materials provided with the distribution.
        * Neither the name of the <organization> nor the
        names of its contributors may be used to endorse or promote products
        derived from this software without specific prior written permission.

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

#include <algorithm>
#include <assert.h>

#include <paladin_drcsim_plugins/joint_actuation_plugin.h>

#include <common/common.h>
#include <math/gzmath.h>
#include <physics/physics.h>
#include <sdf/sdf.h>

#include <ros/ros.h>
#include <tf/transform_broadcaster.h>
#include <tf/transform_listener.h>
#include <geometry_msgs/Twist.h>
#include <nav_msgs/Odometry.h>
#include <boost/bind.hpp>

namespace gazebo
{

// Constructor
JointActuationPlugin::JointActuationPlugin()
{
}

// Destructor
JointActuationPlugin::~JointActuationPlugin()
{
  // Finalize the controller
  alive_ = false;
  queue_.clear();
  queue_.disable();
  rosnode_->shutdown();
  callback_queue_thread_.join();

  delete rosnode_;
}

// Load the controller
void JointActuationPlugin::Load(physics::ModelPtr _parent, sdf::ElementPtr _sdf)
{
  this->parent = _parent;
  this->world = _parent->GetWorld();

  gzdbg << "plugin parent sensor name: " << parent->GetName() << "\n";

  if (!this->parent) { gzthrow("Joint Actuation controller requires a Model as its parent"); }

  this->robotNamespace = "";
  if (_sdf->HasElement("robotNamespace"))
  {
    this->robotNamespace = _sdf->GetElement("robotNamespace")->GetValueString() + "/";
  }

  if (!_sdf->HasElement("topicName"))
  {
    ROS_WARN("Joint Actuation plugin missing <topicName>, defaults to ACTUATOR_CMDS");
    this->topicName = "ACTUATOR_CMDS";
  }
  else
  {
    this->topicName = _sdf->GetElement("topicName")->GetValueString();
  }

  alive_ = true;

  ActuationCmdStruc zero_cmd;
  zero_cmd.value = 0;
  zero_cmd.start_time = 0;
  zero_cmd.duration = 0;
  zero_cmd.on_flag = false;

  for (unsigned int i = 0; i < this->parent->GetJointCount(); i ++)
  {
     joint = this->parent->GetJoint(i);
     std::string joint_name = joint->GetName();
     _joint_actuation_values.insert(make_pair(joint_name, zero_cmd));
  }

  // Initialize the ROS node and subscribe to joint actuation command topic
  int argc = 0;
  char** argv = NULL;
  ros::init(argc, argv, "joint_actuation_plugin", ros::init_options::NoSigintHandler | ros::init_options::AnonymousName);
  rosnode_ = new ros::NodeHandle(this->robotNamespace);

  ROS_INFO("starting joint_actuation_plugin in ns: %s", this->robotNamespace.c_str());

  // ROS: Subscribe to the joint actuation command topic
  ros::SubscribeOptions so =
      ros::SubscribeOptions::create<atlas_gazebo_msgs::ActuatorCmd>(topicName, 1,
                                                          boost::bind(&JointActuationPlugin::actuationCmdCallback, this, _1),
                                                          ros::VoidPtr(), &queue_);
  sub_ = rosnode_->subscribe(so);

  // start custom queue for diff drive
  this->callback_queue_thread_ = boost::thread(boost::bind(&JointActuationPlugin::QueueThread, this));

  // listen to the update event (broadcast every simulation iteration)
  this->updateConnection = event::Events::ConnectWorldUpdateStart(boost::bind(&JointActuationPlugin::UpdateChild, this));
}

// Update the controller
void JointActuationPlugin::UpdateChild()
{

  //update forces of all joints that are active
  //if (this->world->IsPaused())
  // this->world->SetPaused(false);
  // Loop through all Joints
  std::map<std::string, ActuationCmdStruc>::iterator it;

  for (unsigned int i = 0; i < this->parent->GetJointCount(); i ++)
  {
    std::string joint_name = this->parent->GetJoint(i)->GetName();

    it=_joint_actuation_values.find(joint_name);

    // both time_now, duration and start_time must also in simTime.
    double time_now = this->world->GetSimTime().Double();
    lock.lock();
    double duration = it->second.duration; // in seconds
    double start_time =  it->second.start_time;
    bool on_flag = it->second.on_flag;
    lock.unlock();

    if(on_flag==true) // if flag is on
    {
      if (time_now <= start_time + duration)
      {
        this->parent->GetJoint(i)->SetForce(0,it->second.value);
      }
      else  // duration has expired, so clear forces. (duration is reset if a new torque command is received)
      {
        //clear force
        this->parent->GetJoint(i)->SetForce(0,0);
        lock.lock();
        it->second.on_flag = false;
        lock.unlock();
      }
    }
  } // end for loop

}// end update child.

void JointActuationPlugin::actuationCmdCallback(const atlas_gazebo_msgs::ActuatorCmd::ConstPtr& cmd_msg)
{

  //Double check that the msg is for the correct robot name (this->parent->getName()).
  if(cmd_msg->robot_name == this->parent->GetName())
  {
    lock.lock();
    int64_t t   =  cmd_msg->header.stamp.toNSec();
    double msg_start_time  = t*1e-9; // from nsec to sec
    //double msg_start_time  = this->world->GetSimTime().Double(); // All timing is done relative to sim time.
    //for all joints in message update ActuationCmd Buffer.
    for (std::vector<int>::size_type i = 0; i != cmd_msg->actuator_name.size(); i++)
    {
      std::string joint_name = cmd_msg->actuator_name[i];
      std::map<std::string, ActuationCmdStruc>::iterator it;
      it=_joint_actuation_values.find(joint_name);
      ActuationCmdStruc act_cmd;
      act_cmd.start_time = msg_start_time; // sim time when msg was received.
      act_cmd.value = cmd_msg->actuator_effort[i];
      act_cmd.duration = cmd_msg->effort_duration[i];
      act_cmd.on_flag = true;
      it->second = act_cmd;
    }// end for
    lock.unlock();
  }

}

void JointActuationPlugin::QueueThread()
{
  static const double timeout = 0.01;

  while (alive_ && rosnode_->ok())
  {
    queue_.callAvailable(ros::WallDuration(timeout));
  }
}

GZ_REGISTER_MODEL_PLUGIN(JointActuationPlugin)
}

<commit_msg>adding transport hints to joint actuation subscribe to enable tcpNodelay option and also increased timeout in callback queue to 0.1 from 0.01<commit_after>/*  Adapted from diffdrive gazebo plugin.
    Copyright (c) 2010, Daniel Hewlett, Antons Rebguns
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
        * Redistributions of source code must retain the above copyright
        notice, this list of conditions and the following disclaimer.
        * Redistributions in binary form must reproduce the above copyright
        notice, this list of conditions and the following disclaimer in the
        documentation and/or other materials provided with the distribution.
        * Neither the name of the <organization> nor the
        names of its contributors may be used to endorse or promote products
        derived from this software without specific prior written permission.

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

#include <algorithm>
#include <assert.h>

#include <paladin_drcsim_plugins/joint_actuation_plugin.h>

#include <common/common.h>
#include <math/gzmath.h>
#include <physics/physics.h>
#include <sdf/sdf.h>

#include <ros/ros.h>
#include <tf/transform_broadcaster.h>
#include <tf/transform_listener.h>
#include <geometry_msgs/Twist.h>
#include <nav_msgs/Odometry.h>
#include <boost/bind.hpp>

namespace gazebo
{

// Constructor
JointActuationPlugin::JointActuationPlugin()
{
}

// Destructor
JointActuationPlugin::~JointActuationPlugin()
{
  // Finalize the controller
  alive_ = false;
  queue_.clear();
  queue_.disable();
  rosnode_->shutdown();
  callback_queue_thread_.join();

  delete rosnode_;
}

// Load the controller
void JointActuationPlugin::Load(physics::ModelPtr _parent, sdf::ElementPtr _sdf)
{
  this->parent = _parent;
  this->world = _parent->GetWorld();

  gzdbg << "plugin parent sensor name: " << parent->GetName() << "\n";

  if (!this->parent) { gzthrow("Joint Actuation controller requires a Model as its parent"); }

  this->robotNamespace = "";
  if (_sdf->HasElement("robotNamespace"))
  {
    this->robotNamespace = _sdf->GetElement("robotNamespace")->GetValueString() + "/";
  }

  if (!_sdf->HasElement("topicName"))
  {
    ROS_WARN("Joint Actuation plugin missing <topicName>, defaults to ACTUATOR_CMDS");
    this->topicName = "ACTUATOR_CMDS";
  }
  else
  {
    this->topicName = _sdf->GetElement("topicName")->GetValueString();
  }

  alive_ = true;

  ActuationCmdStruc zero_cmd;
  zero_cmd.value = 0;
  zero_cmd.start_time = 0;
  zero_cmd.duration = 0;
  zero_cmd.on_flag = false;

  for (unsigned int i = 0; i < this->parent->GetJointCount(); i ++)
  {
     joint = this->parent->GetJoint(i);
     std::string joint_name = joint->GetName();
     _joint_actuation_values.insert(make_pair(joint_name, zero_cmd));
  }

  // Initialize the ROS node and subscribe to joint actuation command topic
  int argc = 0;
  char** argv = NULL;
  ros::init(argc, argv, "joint_actuation_plugin", ros::init_options::NoSigintHandler | ros::init_options::AnonymousName);
  rosnode_ = new ros::NodeHandle(this->robotNamespace);

  ROS_INFO("starting joint_actuation_plugin in ns: %s", this->robotNamespace.c_str());

  // ROS: Subscribe to the joint actuation command topic
  ros::SubscribeOptions so =
      ros::SubscribeOptions::create<atlas_gazebo_msgs::ActuatorCmd>(topicName, 1,
                                                          boost::bind(&JointActuationPlugin::actuationCmdCallback, this, _1),
                                                          ros::VoidPtr(), &queue_);
  so.transport_hints = ros::TransportHints()
        .unreliable()
        .maxDatagramSize(1000)
        .tcpNoDelay();
  sub_ = rosnode_->subscribe(so);

  // start custom queue for diff drive
  this->callback_queue_thread_ = boost::thread(boost::bind(&JointActuationPlugin::QueueThread, this));

  // listen to the update event (broadcast every simulation iteration)
  this->updateConnection = event::Events::ConnectWorldUpdateStart(boost::bind(&JointActuationPlugin::UpdateChild, this));
}

// Update the controller
void JointActuationPlugin::UpdateChild()
{

  //update forces of all joints that are active
  //if (this->world->IsPaused())
  // this->world->SetPaused(false);
  // Loop through all Joints
  std::map<std::string, ActuationCmdStruc>::iterator it;

  for (unsigned int i = 0; i < this->parent->GetJointCount(); i ++)
  {
    std::string joint_name = this->parent->GetJoint(i)->GetName();

    it=_joint_actuation_values.find(joint_name);

    // both time_now, duration and start_time must also in simTime.
    double time_now = this->world->GetSimTime().Double();
    lock.lock();
    double duration = it->second.duration; // in seconds
    double start_time =  it->second.start_time;
    bool on_flag = it->second.on_flag;
    lock.unlock();

    if(on_flag==true) // if flag is on
    {
      if (time_now <= start_time + duration)
      {
        this->parent->GetJoint(i)->SetForce(0,it->second.value);
      }
      else  // duration has expired, so clear forces. (duration is reset if a new torque command is received)
      {
        //clear force
        this->parent->GetJoint(i)->SetForce(0,0);
        lock.lock();
        it->second.on_flag = false;
        lock.unlock();
      }
    }
  } // end for loop

}// end update child.

void JointActuationPlugin::actuationCmdCallback(const atlas_gazebo_msgs::ActuatorCmd::ConstPtr& cmd_msg)
{

  //Double check that the msg is for the correct robot name (this->parent->getName()).
  if(cmd_msg->robot_name == this->parent->GetName())
  {
    lock.lock();
    int64_t t   =  cmd_msg->header.stamp.toNSec();
    double msg_start_time  = t*1e-9; // from nsec to sec
    //double msg_start_time  = this->world->GetSimTime().Double(); // All timing is done relative to sim time.
    //for all joints in message update ActuationCmd Buffer.
    for (std::vector<int>::size_type i = 0; i != cmd_msg->actuator_name.size(); i++)
    {
      std::string joint_name = cmd_msg->actuator_name[i];
      std::map<std::string, ActuationCmdStruc>::iterator it;
      it=_joint_actuation_values.find(joint_name);
      ActuationCmdStruc act_cmd;
      act_cmd.start_time = msg_start_time; // sim time when msg was received.
      act_cmd.value = cmd_msg->actuator_effort[i];
      act_cmd.duration = cmd_msg->effort_duration[i];
      act_cmd.on_flag = true;
      it->second = act_cmd;
    }// end for
    lock.unlock();
  }

}

void JointActuationPlugin::QueueThread()
{
  static const double timeout = 0.1;

  while (alive_ && rosnode_->ok())
  {
    queue_.callAvailable(ros::WallDuration(timeout));
  }
}

GZ_REGISTER_MODEL_PLUGIN(JointActuationPlugin)
}

<|endoftext|>