<commit_before>/*//////////////////////////////////////////////////////////////////
////       SKIRT -- an advanced radiative transfer code         ////
////       © Astronomical Observatory, Ghent University         ////
///////////////////////////////////////////////////////////////// */

#ifndef DUSTGRIDPATH_HPP
#define DUSTGRIDPATH_HPP

#include <cfloat>
#include <vector>
#include "Direction.hpp"
#include "Position.hpp"
class Box;

//////////////////////////////////////////////////////////////////////

/** A DustGridPath object contains the details of a path through a dust grid structure. Given a
    dust grid structure, i.e. an object of a DustGridStucture subclass, a starting position
    \f${\bf{r}}\f$ and a propagation direction \f${\bf{k}}\f$, one can calculate the path through
    the dust grid structure. A DustGridPath object keeps record of all the cells that are crossed
    by this path, together with the physical path length \f$\Delta s\f$ covered within each cell,
    and the path length \f$s\f$ covered along the entire path up to the end of the cell. Given
    additional information about the dust properties in each cell (at a particular wavelength), one
    can also calculate optical depth information for the path. A DustGridPath object keeps record
    of the optical depth \f$\Delta\tau\f$ along the path segment within each cell, and the optical
    depth \f$\tau\f$ along the entire path up to the end of the cell. */
class DustGridPath
{
public:

    // ------- Constructors; handling position and directions -------

    /** This constructor creates an empty path with the specified initial position and propagation
        direction. */
    DustGridPath(const Position& bfr, const Direction& bfk);

    /** This constructor creates an empty path with the initial position and propagation direction
        initialized to null values. After using this constructor, invoke the setPosition() and
        setDirection() functions to set these properties to appropriate values. */
    DustGridPath();

    /** This function sets the initial position of the path to a new value. */
    void setPosition(const Position& bfr) { _bfr = bfr; }

    /** This function sets the propagation direction along the path to a new value. */
    void setDirection(const Direction& bfk) { _bfk = bfk; }

    /** This function returns the initial position of the path. */
    Position position() const { return _bfr; }

    /** This function returns the propagation direction along the path. */
    Direction direction() const { return _bfk; }

    // ------- Handling geometric data on path segments -------

    /** This function removes all path segments, resulting in an empty path with the original
        initial position and propagation direction. */
    void clear();

    /** This function adds a segment in cell \f$m\f$ with length \f$\Delta s\f$ to the path,
        assuming \f$\Delta s>0\f$. Otherwise the function does nothing. */
    void addSegment(int m, double ds);

    /** This function adds the segments to the path that are needed to move the initial position
        along the propagation direction (both specified in the constructor) inside a given box, and
        returns the final position. If the initial position is already inside the box, no segments
        are added. If the half-ray formed by the initial position and the propagation direction
        does not intersect the box, the function returns some arbitrary position outside the box.
        The small value specified by \em eps is added to the path length beyond the intersection
        point so that the final position is well inside the box, guarding against rounding errors.
        */
    Position moveInside(const Box &box, double eps);

    /** This function returns the number of cells crossed along the path. */
    int size() const { return _v.size(); }

    /** This function returns the cell number \f$m\f$ for segment $i$ in the path. */
    int m(int i) const { return _v[i].m; }

    /** This function returns the path length covered within the cell in segment $i$ in the path.
        */
    double ds(int i) const { return _v[i].ds; }

    /** This function returns the path length covered from the initial position of the path until
        the end point of the cell in segment $i$ in the path. */
    double s(int i) const { return _v[i].s; }

    // ------- Handling data on optical depth -------

    /** This function calculates the optical depth for the specified distance along the path (or,
        if the second argument is missing, for the complete path), using the path segment lengths
        \f$\Delta s_i\f$ already stored within the path object, and the multiplication factors
        \f$(\kappa\rho)_{m_i}\f$ provided by the caller through a call-back function, where
        \f$m_i\f$ is the number of the dust cell being crossed in path segment \f$i\f$. The
        call-back function must have the signature "double kapparho(int m)". The optical depth
        information in the path is neither used nor stored. */
    template<typename Functor> double opticalDepth(Functor kapparho, double distance=DBL_MAX) const
    {
        int N = _v.size();
        double tau = 0;
        for (int i=0; i<N; i++)
        {
            const Segment& segment = _v[i];
            tau += kapparho(segment.m) * segment.ds;
            if (segment.s > distance) break;
        }
        return tau;
    }

    /** This function calculates and stores the optical depth details for the path \f[
        (\Delta\tau)_i = (\Delta s)_i \times (\kappa\rho)_{m_i}, \f] \f[ \tau_i = \sum_{j=0}^i
        (\Delta\tau)_j,\f] using the path segment lengths \f$\Delta s_i\f$ already stored within
        the path object, and the multiplication factors \f$(\kappa\rho)_{m_i}\f$ provided by the
        caller through a call-back function, where \f$m_i\f$ is the number of the dust cell being
        crossed in path segment \f$i\f$. The call-back function must have the signature
        "double kapparho(int m)". */
    template<typename Functor> inline void fillOpticalDepth(Functor kapparho)
    {
        int N = _v.size();
        double tau = 0;
        for (int i=0; i<N; i++)
        {
            Segment& segment = _v[i];
            double dtau = kapparho(segment.m) * segment.ds;
            tau += dtau;
            segment.dtau = dtau;
            segment.tau = tau;
        }
    }

    /** This function returns the optical depth covered within the cell in segment $i$ in the path.
        It assumes that the fillOpticalDepth() function was previously invoked for the path. */
    double dtau(int i) const { return _v[i].dtau; }

    /** This function returns the optical depth covered from the initial position of the path until
        the end point of the cell in segment $i$ in the path. It assumes that the
        fillOpticalDepth() function was previously invoked for the path. */
    double tau(int i) const { return _v[i].tau; }

    /** This function returns the total optical depth along the entire path. It assumes that the
        fillOpticalDepth() function was previously invoked for the path. */
    double tau() const;

    /** This function calculates the path length a photon package can travel along the path until
        it has covered an optical depth \f$\tau\f$. In other words, it converts an optical depth
        \f$\tau\f$ to a physical path length \f$s\f$. The function assumes that the
        fillOpticalDepth() function was previously invoked for the path. We have to determine the
        first cell along the path for which the cumulative optical depth \f$\tau_{m}\f$ becomes
        larger than \f$\tau\f$. This means that the position we are looking for lies within the
        \f$m\f$'th dust cell. The exact path length corresponding to \f$\tau\f$ is then found by
        linear interpolation within this cell. */
    double pathlength(double tau) const;

    // ------- Data members -------

protected:
    Position _bfr;
    Direction _bfk;
private:
    double _s;
    struct Segment
    {
        int m;
        double ds, s, dtau, tau;
        bool operator<(Segment other) const { return tau < other.tau; }
    };
    std::vector<Segment> _v;
};

//////////////////////////////////////////////////////////////////////

#endif // DUSTGRIDPATH_HPP
<commit_msg>Very minor changes in documentation of DustGridPath class<commit_after>/*//////////////////////////////////////////////////////////////////
////       SKIRT -- an advanced radiative transfer code         ////
////       © Astronomical Observatory, Ghent University         ////
///////////////////////////////////////////////////////////////// */

#ifndef DUSTGRIDPATH_HPP
#define DUSTGRIDPATH_HPP

#include <cfloat>
#include <vector>
#include "Direction.hpp"
#include "Position.hpp"
class Box;

//////////////////////////////////////////////////////////////////////

/** A DustGridPath object contains the details of a path through a dust grid structure. Given a
    dust grid structure, i.e. an object of a DustGridStucture subclass, a starting position
    \f${\bf{r}}\f$ and a propagation direction \f${\bf{k}}\f$, one can calculate the path through
    the dust grid structure. A DustGridPath object keeps record of all the cells that are crossed
    by this path, together with the physical path length \f$\Delta s\f$ covered within each cell,
    and the path length \f$s\f$ covered along the entire path up to the end of the cell. Given
    additional information about the dust properties in each cell (at a particular wavelength), one
    can also calculate optical depth information for the path. A DustGridPath object keeps record
    of the optical depth \f$\Delta\tau\f$ along the path segment within each cell, and the optical
    depth \f$\tau\f$ along the entire path up to the end of the cell. */
class DustGridPath
{
public:

    // ------- Constructors; handling position and directions -------

    /** This constructor creates an empty path with the specified initial position and propagation
        direction. */
    DustGridPath(const Position& bfr, const Direction& bfk);

    /** This constructor creates an empty path with the initial position and propagation direction
        initialized to null values. After using this constructor, invoke the setPosition() and
        setDirection() functions to set these properties to appropriate values. */
    DustGridPath();

    /** This function sets the initial position of the path to a new value. */
    void setPosition(const Position& bfr) { _bfr = bfr; }

    /** This function sets the propagation direction along the path to a new value. */
    void setDirection(const Direction& bfk) { _bfk = bfk; }

    /** This function returns the initial position of the path. */
    Position position() const { return _bfr; }

    /** This function returns the propagation direction along the path. */
    Direction direction() const { return _bfk; }

    // ------- Handling geometric data on path segments -------

    /** This function removes all path segments, resulting in an empty path with the original
        initial position and propagation direction. */
    void clear();

    /** This function adds a segment in cell \f$m\f$ with length \f$\Delta s\f$ to the path,
        assuming \f$\Delta s>0\f$. Otherwise the function does nothing. */
    void addSegment(int m, double ds);

    /** This function adds the segments to the path that are needed to move the initial position
        along the propagation direction (both specified in the constructor) inside a given box, and
        returns the final position. If the initial position is already inside the box, no segments
        are added. If the half-ray formed by the initial position and the propagation direction
        does not intersect the box, the function returns some arbitrary position outside the box.
        The small value specified by \em eps is added to the path length beyond the intersection
        point so that the final position is well inside the box, guarding against rounding errors.
        */
    Position moveInside(const Box &box, double eps);

    /** This function returns the number of cells crossed along the path. */
    int size() const { return _v.size(); }

    /** This function returns the cell number \f$m\f$ for segment \f$i\f$ in the path. */
    int m(int i) const { return _v[i].m; }

    /** This function returns the path length covered within the cell in segment \f$i\f$ in the path.
        */
    double ds(int i) const { return _v[i].ds; }

    /** This function returns the path length covered from the initial position of the path until
        the end point of the cell in segment \f$i\f$ in the path. */
    double s(int i) const { return _v[i].s; }

    // ------- Handling data on optical depth -------

    /** This function calculates the optical depth for the specified distance along the path (or,
        if the second argument is missing, for the complete path), using the path segment lengths
        \f$\Delta s_i\f$ already stored within the path object, and the multiplication factors
        \f$(\kappa\rho)_{m_i}\f$ provided by the caller through a call-back function, where
        \f$m_i\f$ is the number of the dust cell being crossed in path segment \f$i\f$. The
        call-back function must have the signature "double kapparho(int m)". The optical depth
        information in the path is neither used nor stored. */
    template<typename Functor> double opticalDepth(Functor kapparho, double distance=DBL_MAX) const
    {
        int N = _v.size();
        double tau = 0;
        for (int i=0; i<N; i++)
        {
            const Segment& segment = _v[i];
            tau += kapparho(segment.m) * segment.ds;
            if (segment.s > distance) break;
        }
        return tau;
    }

    /** This function calculates and stores the optical depth details for the path \f[
        (\Delta\tau)_i = (\Delta s)_i \times (\kappa\rho)_{m_i}, \f] \f[ \tau_i = \sum_{j=0}^i
        (\Delta\tau)_j,\f] using the path segment lengths \f$\Delta s_i\f$ already stored within
        the path object, and the multiplication factors \f$(\kappa\rho)_{m_i}\f$ provided by the
        caller through a call-back function, where \f$m_i\f$ is the number of the dust cell being
        crossed in path segment \f$i\f$. The call-back function must have the signature
        "double kapparho(int m)". */
    template<typename Functor> inline void fillOpticalDepth(Functor kapparho)
    {
        int N = _v.size();
        double tau = 0;
        for (int i=0; i<N; i++)
        {
            Segment& segment = _v[i];
            double dtau = kapparho(segment.m) * segment.ds;
            tau += dtau;
            segment.dtau = dtau;
            segment.tau = tau;
        }
    }

    /** This function returns the optical depth covered within the cell in segment $i$ in the path.
        It assumes that the fillOpticalDepth() function was previously invoked for the path. */
    double dtau(int i) const { return _v[i].dtau; }

    /** This function returns the optical depth covered from the initial position of the path until
        the end point of the cell in segment $i$ in the path. It assumes that the
        fillOpticalDepth() function was previously invoked for the path. */
    double tau(int i) const { return _v[i].tau; }

    /** This function returns the total optical depth along the entire path. It assumes that the
        fillOpticalDepth() function was previously invoked for the path. */
    double tau() const;

    /** This function calculates the path length a photon package can travel along the path until
        it has covered an optical depth \f$\tau\f$. In other words, it converts an optical depth
        \f$\tau\f$ to a physical path length \f$s\f$. The function assumes that the
        fillOpticalDepth() function was previously invoked for the path. We have to determine the
        first cell along the path for which the cumulative optical depth \f$\tau_{m}\f$ becomes
        larger than \f$\tau\f$. This means that the position we are looking for lies within the
        \f$m\f$'th dust cell. The exact path length corresponding to \f$\tau\f$ is then found by
        linear interpolation within this cell. */
    double pathlength(double tau) const;

    // ------- Data members -------

protected:
    Position _bfr;
    Direction _bfk;
private:
    double _s;
    struct Segment
    {
        int m;
        double ds, s, dtau, tau;
        bool operator<(Segment other) const { return tau < other.tau; }
    };
    std::vector<Segment> _v;
};

//////////////////////////////////////////////////////////////////////

#endif // DUSTGRIDPATH_HPP
<|endoftext|>


<commit_before>#include "ResourceGUI.h"
#include "IO/XmlWorld.h"
#include "utils/stringutils.h"
#include "utils/ioutils.h"

ResourceGUIBackend::ResourceGUIBackend(RobotWorld* world,ResourceManager* library)
  :WorldGUIBackend(world),resources(library)
{
}

inline bool LoadResources(const char* fn,ResourceTree& lib)
{
  size_t origsize = lib.topLevel.size();
  if(!lib.LoadFolder(fn)) {
    lib.TreeFromLibrary();
    fprintf(stderr,"Warning, couldn't load library %s\n",fn);
    return false;
  }
  else {
    printf("Loaded %d items from %s\n",lib.topLevel.size()-origsize,fn);
    return true;
  }
  return false;
}

inline bool LoadResources(TiXmlElement* e,ResourceTree& lib)
{
  size_t origsize = lib.topLevel.size();
  if(!lib.library.Load(e)) {
    fprintf(stderr,"Warning, couldn't load library from XML\n");
    lib.TreeFromLibrary();
    return false;
  }
  else {
    lib.TreeFromLibrary();
    printf("Loaded %d items from XML\n",lib.topLevel.size()-origsize);
    return true;
  }
  return false;
}

inline bool LoadItem(const char* fn,ResourceTree& lib)
{
  ResourceNodePtr r=lib.LoadFile(fn);
  if(r != NULL) {
    printf("Loaded %s as type %s\n",fn,r->Type());
    return true;
  }
  else {
    fprintf(stderr,"Couldn't load resource file %s\n",fn);
    return false;
  }
}

bool ResourceGUIBackend::LoadCommandLine(int argc,const char** argv)
{
  for(int i=1;i<argc;i++) {
    if(argv[i][0] == '-') {
      if(0==strcmp(argv[i],"-l")) {
	LoadResources(argv[i+1],*resources);
	i++;
      }
      else {
	printf("Unknown option %s",argv[i]);
	return 0;
      }
    }
    else {
      const char* ext=FileExtension(argv[i]);
      if(0==strcmp(ext,"xml")) {
	TiXmlDocument doc;
	if(!doc.LoadFile(argv[i])) {
	  printf("Error loading XML file %s\n",argv[i]);
	  return false;
	}
	if(0 == strcmp(doc.RootElement()->Value(),"world")) {
	  XmlWorld xmlWorld;
	  if(!xmlWorld.Load(doc.RootElement(),GetFilePath(argv[i]))) {
	    printf("Error loading world file %s\n",argv[i]);
	    return 0;
	  }
	  if(!xmlWorld.GetWorld(*world)) {
	    printf("Error loading world from %s\n",argv[i]);
	    return 0;
	  }
	}
	else if(0 == strcmp(doc.RootElement()->Value(),"resource_library")) {
	  LoadResources(doc.RootElement(),*resources);
	}
	else {
	  if(!LoadItem(argv[i],*resources))
	    return 0;
	}
      }
      else {
	//try loading into the world
	const char* ext = FileExtension(argv[i]);
	if(world->CanLoadElementExt(ext) && world->LoadElement(argv[i])>= 0) {
	  //loaded successfully
	}
	else {
	  //failed, now try resource library load
	  if(!LoadItem(argv[i],*resources))
	    return 0;
	}
      }
    }
  }
  return true;
}

ResourceNodePtr ResourceGUIBackend::Add(ResourcePtr r)
{
  if(resources == NULL) return NULL;
  ResourceNode* parent = (resources->selected != NULL ? resources->selected->parent : NULL);
  if(r->name.empty()) {
      stringstream ss;
      if(parent == NULL){
	ss<<r->Type()<<"["<<resources->topLevel.size()<<"]";
      }
      else{
	ss<<r->Type()<<"["<<parent->children.size()<<"]";
      }
      r->name = ss.str();
  }
  //last_added = resources->AddChildOfSelected(r);
  if(parent == NULL)
    last_added = resources->Add(r);
  else
    last_added = parent->AddChild(r);
  //SendCommand("new_resource", r->Type()+string(" ")+r->name);
  SendCommand("new_resource", last_added->Identifier());
  return last_added;
}

ResourceNodePtr ResourceGUIBackend::Add(const string& name,const string& type)
{
  if(resources->library.knownTypes.count(type)==0) return NULL;
  ResourcePtr r=resources->library.knownTypes[type][0]->Make();
  r->name = name;
  return Add(r);
}

void ResourceGUIBackend::SaveCur(const string& file)
{
  resources->SaveSelected(file);
}

bool ResourceGUIBackend::LoadNew(const string& file)
{
  return resources->LoadFile(file) != NULL;
}

void ResourceGUIBackend::SaveAll(const string& path)
{
  resources->SaveFolder(path);
}

bool ResourceGUIBackend::LoadAll(const string& path)
{
  if(!resources->LoadFolder(path)) {
    fprintf(stderr,"Error loading resources from %s\n",path.c_str());
    return false;
    }
    else {
    fprintf(stderr,"Loaded all resources from %s\n",path.c_str());
    return true;
  }
  return false;
}

void ResourceGUIBackend::SetLastActive()
{
  if(last_added == NULL) {
    resources->selected = NULL;
  }
  else {
    resources->selected = last_added;
  }
}

void ResourceGUIBackend::SetActive(const string& identifier)
{
  resources->Select(identifier);
}

void ResourceGUIBackend::SetPathTime(double time){
  viewResource.pathTime = time;
}

bool ResourceGUIBackend::OnCommand(const string& cmd,const string& args)
{
  if(cmd == "set_resource") {
    resources->Select(args);
    return true;
  }
  else if(cmd == "get_resource") {
    stringstream ss;
    ss<<resources->selected->Identifier();
    SendCommand("current_resource",ss.str());
    return true;
  }
  else if(cmd == "set_resource_name") {
    if(resources->selected) resources->selected->resource->name = args;
    printf("Updating name to %s\n",args.c_str());
  }
  else if(cmd == "delete_resource") {
    resources->DeleteSelected();
  }
  else if(cmd == "add_resource") {
    string type,name;
    stringstream ss(args);
    if(!SafeInputString(ss,type)) {
      cout<<"Error reading resource type from args \""<<args<<"\""<<endl;
      return true;
    }
    if(!SafeInputString(ss,name)) {
      cout<<"Error reading resource name from args \""<<args<<"\""<<endl;
      return true;
    }
    last_added = Add(name,type);
  }
  else if(cmd == "load_resource") {
    if(LoadNew(args)) {
      SendCommand("new_resource",last_added->Identifier());
    }
  }
  else if(cmd == "save_resource") {
    SaveCur(args);
  }
  else if(cmd == "load_resource_dir") {
    if(LoadAll(args)) {
      SendCommand("refresh_resources","");
    }
  }
  else if(cmd == "save_resource_dir") {
    SaveAll(args);
  }
  else if(cmd == "convert") {
    ResourcePtr r=CurrentResource();
    ResourcePtr res = CastResource(r,args.c_str());
    if(!res) {
      fprintf(stderr,"Conversion failed\n");
      return true;
    }
    res->name = r->name;
    Add(res);
    SetLastActive();
  }
  else if(cmd == "extract") {
    ResourcePtr r=CurrentResource();
    if(!r) return true;
    vector<ResourcePtr> res = ExtractResources(r,args.c_str());
    for(size_t i=0;i<res.size();i++){
      Add(res[i]);
    }
    if(!res.empty())
      SetLastActive();
  }
  else if(cmd == "set_path_time") {
    stringstream ss(args);
    double time;
    ss>>time;
    SetPathTime(time);
  }
  else {
    return WorldGUIBackend::OnCommand(cmd,args);
  }
  return true;
}

ResourcePtr ResourceGUIBackend::CurrentResource()
{
    if(resources && resources->selected)
        return resources->selected->resource;
    else return 0;
}

void ResourceGUIBackend::RenderCurResource()
{
  /*
    ResourcePtr current = CurrentResource();
    if(current)
    viewResource.DrawGL(current);
  */
  //separate open?
  viewResource.SetRobot(world->robots[0].robot);
  if(resources && resources->selected)
    viewResource.DrawGL(resources->selected->resource);
}
<commit_msg>Fixed path refresh<commit_after>#include "ResourceGUI.h"
#include "IO/XmlWorld.h"
#include "utils/stringutils.h"
#include "utils/ioutils.h"

ResourceGUIBackend::ResourceGUIBackend(RobotWorld* world,ResourceManager* library)
  :WorldGUIBackend(world),resources(library)
{
}

inline bool LoadResources(const char* fn,ResourceTree& lib)
{
  size_t origsize = lib.topLevel.size();
  if(!lib.LoadFolder(fn)) {
    lib.TreeFromLibrary();
    fprintf(stderr,"Warning, couldn't load library %s\n",fn);
    return false;
  }
  else {
    printf("Loaded %d items from %s\n",lib.topLevel.size()-origsize,fn);
    return true;
  }
  return false;
}

inline bool LoadResources(TiXmlElement* e,ResourceTree& lib)
{
  size_t origsize = lib.topLevel.size();
  if(!lib.library.Load(e)) {
    fprintf(stderr,"Warning, couldn't load library from XML\n");
    lib.TreeFromLibrary();
    return false;
  }
  else {
    lib.TreeFromLibrary();
    printf("Loaded %d items from XML\n",lib.topLevel.size()-origsize);
    return true;
  }
  return false;
}

inline bool LoadItem(const char* fn,ResourceTree& lib)
{
  ResourceNodePtr r=lib.LoadFile(fn);
  if(r != NULL) {
    printf("Loaded %s as type %s\n",fn,r->Type());
    return true;
  }
  else {
    fprintf(stderr,"Couldn't load resource file %s\n",fn);
    return false;
  }
}

bool ResourceGUIBackend::LoadCommandLine(int argc,const char** argv)
{
  for(int i=1;i<argc;i++) {
    if(argv[i][0] == '-') {
      if(0==strcmp(argv[i],"-l")) {
	LoadResources(argv[i+1],*resources);
	i++;
      }
      else {
	printf("Unknown option %s",argv[i]);
	return 0;
      }
    }
    else {
      const char* ext=FileExtension(argv[i]);
      if(0==strcmp(ext,"xml")) {
	TiXmlDocument doc;
	if(!doc.LoadFile(argv[i])) {
	  printf("Error loading XML file %s\n",argv[i]);
	  return false;
	}
	if(0 == strcmp(doc.RootElement()->Value(),"world")) {
	  XmlWorld xmlWorld;
	  if(!xmlWorld.Load(doc.RootElement(),GetFilePath(argv[i]))) {
	    printf("Error loading world file %s\n",argv[i]);
	    return 0;
	  }
	  if(!xmlWorld.GetWorld(*world)) {
	    printf("Error loading world from %s\n",argv[i]);
	    return 0;
	  }
	}
	else if(0 == strcmp(doc.RootElement()->Value(),"resource_library")) {
	  LoadResources(doc.RootElement(),*resources);
	}
	else {
	  if(!LoadItem(argv[i],*resources))
	    return 0;
	}
      }
      else {
	//try loading into the world
	const char* ext = FileExtension(argv[i]);
	if(world->CanLoadElementExt(ext) && world->LoadElement(argv[i])>= 0) {
	  //loaded successfully
	}
	else {
	  //failed, now try resource library load
	  if(!LoadItem(argv[i],*resources))
	    return 0;
	}
      }
    }
  }
  return true;
}

ResourceNodePtr ResourceGUIBackend::Add(ResourcePtr r)
{
  if(resources == NULL) return NULL;
  ResourceNode* parent = (resources->selected != NULL ? resources->selected->parent : NULL);
  if(r->name.empty()) {
      stringstream ss;
      if(parent == NULL){
	ss<<r->Type()<<"["<<resources->topLevel.size()<<"]";
      }
      else{
	ss<<r->Type()<<"["<<parent->children.size()<<"]";
      }
      r->name = ss.str();
  }
  //last_added = resources->AddChildOfSelected(r);
  if(parent == NULL)
    last_added = resources->Add(r);
  else
    last_added = parent->AddChild(r);
  //SendCommand("new_resource", r->Type()+string(" ")+r->name);
  SendCommand("new_resource", last_added->Identifier());
  return last_added;
}

ResourceNodePtr ResourceGUIBackend::Add(const string& name,const string& type)
{
  if(resources->library.knownTypes.count(type)==0) return NULL;
  ResourcePtr r=resources->library.knownTypes[type][0]->Make();
  r->name = name;
  return Add(r);
}

void ResourceGUIBackend::SaveCur(const string& file)
{
  resources->SaveSelected(file);
}

bool ResourceGUIBackend::LoadNew(const string& file)
{
  return resources->LoadFile(file) != NULL;
}

void ResourceGUIBackend::SaveAll(const string& path)
{
  resources->SaveFolder(path);
}

bool ResourceGUIBackend::LoadAll(const string& path)
{
  if(!resources->LoadFolder(path)) {
    fprintf(stderr,"Error loading resources from %s\n",path.c_str());
    return false;
    }
    else {
    fprintf(stderr,"Loaded all resources from %s\n",path.c_str());
    return true;
  }
  return false;
}

void ResourceGUIBackend::SetLastActive()
{
  if(last_added == NULL) {
    resources->selected = NULL;
  }
  else {
    resources->selected = last_added;
  }
}

void ResourceGUIBackend::SetActive(const string& identifier)
{
  resources->Select(identifier);
}

void ResourceGUIBackend::SetPathTime(double time){
  viewResource.pathTime = time;
}

bool ResourceGUIBackend::OnCommand(const string& cmd,const string& args)
{
  if(cmd == "set_resource") {
    resources->Select(args);
    return true;
  }
  else if(cmd == "get_resource") {
    stringstream ss;
    ss<<resources->selected->Identifier();
    SendCommand("current_resource",ss.str());
    return true;
  }
  else if(cmd == "set_resource_name") {
    if(resources->selected) resources->selected->resource->name = args;
    printf("Updating name to %s\n",args.c_str());
  }
  else if(cmd == "delete_resource") {
    resources->DeleteSelected();
  }
  else if(cmd == "add_resource") {
    string type,name;
    stringstream ss(args);
    if(!SafeInputString(ss,type)) {
      cout<<"Error reading resource type from args \""<<args<<"\""<<endl;
      return true;
    }
    if(!SafeInputString(ss,name)) {
      cout<<"Error reading resource name from args \""<<args<<"\""<<endl;
      return true;
    }
    last_added = Add(name,type);
  }
  else if(cmd == "load_resource") {
    if(LoadNew(args)) {
      SendCommand("new_resource",last_added->Identifier());
    }
  }
  else if(cmd == "save_resource") {
    SaveCur(args);
  }
  else if(cmd == "load_resource_dir") {
    if(LoadAll(args)) {
      SendCommand("refresh_resources","");
    }
  }
  else if(cmd == "save_resource_dir") {
    SaveAll(args);
  }
  else if(cmd == "convert") {
    ResourcePtr r=CurrentResource();
    ResourcePtr res = CastResource(r,args.c_str());
    if(!res) {
      fprintf(stderr,"Conversion failed\n");
      return true;
    }
    res->name = r->name;
    Add(res);
    SetLastActive();
  }
  else if(cmd == "extract") {
    ResourcePtr r=CurrentResource();
    if(!r) return true;
    vector<ResourcePtr> res = ExtractResources(r,args.c_str());
    for(size_t i=0;i<res.size();i++){
      Add(res[i]);
    }
    if(!res.empty())
      SetLastActive();
  }
  else if(cmd == "set_path_time") {
    stringstream ss(args);
    double time;
    ss>>time;
    SetPathTime(time);
    SendRefresh();
  }
  else {
    return WorldGUIBackend::OnCommand(cmd,args);
  }
  return true;
}

ResourcePtr ResourceGUIBackend::CurrentResource()
{
    if(resources && resources->selected)
        return resources->selected->resource;
    else return 0;
}

void ResourceGUIBackend::RenderCurResource()
{
  /*
    ResourcePtr current = CurrentResource();
    if(current)
    viewResource.DrawGL(current);
  */
  //separate open?
  viewResource.SetRobot(world->robots[0].robot);
  if(resources && resources->selected)
    viewResource.DrawGL(resources->selected->resource);
}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "CtrlrUtilities.h"
#include "CtrlrPanel/CtrlrPanel.h"
#include "CtrlrManager/CtrlrManager.h"
#include "CtrlrFontPropertyComponent.h"
#include "CtrlrProcessor.h"

CtrlrFontPropertyComponent::CtrlrFontPropertyComponent (const Value &_valueToControl, CtrlrPanel *_owner)
    : valueToControl(_valueToControl), owner(_owner),
      typeface (0),
      fontBold (0),
      fontItalic (0),
      fontUnderline (0),
      fontSize (0),
	  kerning(0),
	  horizontalScale(0)
{
    addAndMakeVisible (typeface = new ComboBox (String::empty));
    typeface->setEditableText (false);
    typeface->setJustificationType (Justification::centredLeft);
    typeface->setTextWhenNothingSelected (L"<Sans-Serif>");
    typeface->setTextWhenNoChoicesAvailable (L"<Sans-Serif>");
    typeface->addListener (this);

    addAndMakeVisible (fontBold = new ImageButton (String::empty));
    fontBold->setTooltip (L"Bold");
    fontBold->setButtonText (L"new button");
    fontBold->addListener (this);

    fontBold->setImages (false, true, true,
                         IMAGE (ico_font_bold_png), 0.5000f, Colour (0x0),
                         IMAGE (ico_font_bold_png), 0.7500f, Colour (0xa0ffffff),
                         IMAGE (ico_font_bold_png), 1.0000f, Colour (0x0));
    addAndMakeVisible (fontItalic = new ImageButton (String::empty));
    fontItalic->setTooltip (L"Italic");
    fontItalic->setButtonText (L"new button");
    fontItalic->addListener (this);

    fontItalic->setImages (false, true, true,
                           IMAGE (ico_font_italic_png), 0.5000f, Colour (0x0),
                           IMAGE (ico_font_italic_png), 0.7500f, Colour (0xa0ffffff),
                           IMAGE (ico_font_italic_png), 1.0000f, Colour (0x0));
    addAndMakeVisible (fontUnderline = new ImageButton (String::empty));
    fontUnderline->setTooltip (L"Underline");
    fontUnderline->setButtonText (L"new button");
    fontUnderline->addListener (this);

    fontUnderline->setImages (false, true, true,
                              IMAGE (ico_font_underline_png), 0.5000f, Colour (0x0),
                              IMAGE (ico_font_underline_png), 0.7500f, Colour (0xa0ffffff),
                              IMAGE (ico_font_underline_png), 1.0000f, Colour (0x0));

    addAndMakeVisible (fontSize = new Slider (String::empty));
	fontSize->setLookAndFeel (this);
    fontSize->setTooltip (L"Size");
    fontSize->setRange (1, 999, 1);
    fontSize->setSliderStyle (Slider::RotaryVerticalDrag);
    fontSize->setTextBoxStyle (Slider::TextBoxRight, false, 34, 16);
    fontSize->addListener (this);

	addAndMakeVisible (horizontalScale = new Slider (String::empty));
	horizontalScale->setLookAndFeel (this);
    horizontalScale->setTooltip (L"Horizontal Scale");
    horizontalScale->setRange (0.0, 10.0, 0.01);
    horizontalScale->setSliderStyle (Slider::RotaryVerticalDrag);
    horizontalScale->setTextBoxStyle (Slider::TextBoxRight, false, 34, 16);
    horizontalScale->addListener (this);

	addAndMakeVisible (kerning = new Slider (String::empty));
    kerning->setLookAndFeel (this);
	kerning->setTooltip (L"Extra Kerning");
    kerning->setRange (0.0, 10.0, 0.01);
    kerning->setSliderStyle (Slider::RotaryVerticalDrag);
    kerning->setTextBoxStyle (Slider::TextBoxRight, false, 34, 16);
    kerning->addListener (this);

	fontBold->setClickingTogglesState (true);
	fontBold->setMouseCursor (MouseCursor::PointingHandCursor);
	fontItalic->setClickingTogglesState (true);
	fontItalic->setMouseCursor (MouseCursor::PointingHandCursor);
	fontUnderline->setClickingTogglesState (true);
	fontUnderline->setMouseCursor (MouseCursor::PointingHandCursor);

    owner->getCtrlrManagerOwner().getFontManager().fillCombo (*typeface, true, true, true, true);

    setSize (300, 32);
}

CtrlrFontPropertyComponent::~CtrlrFontPropertyComponent()
{
    deleteAndZero (typeface);
    deleteAndZero (fontBold);
    deleteAndZero (fontItalic);
    deleteAndZero (fontUnderline);
    deleteAndZero (fontSize);
	deleteAndZero (kerning);
	deleteAndZero (horizontalScale);
}

void CtrlrFontPropertyComponent::resized()
{
    typeface->setBounds (0, 0, getWidth() * 0.4f, getHeight());

	fontBold->setBounds (getWidth() * 0.4f,									0, getWidth() * 0.05f,	getHeight());
    fontItalic->setBounds ((getWidth() * 0.4f) + (getWidth() * 0.05f),		0, getWidth() * 0.05f,	getHeight());
	fontUnderline->setBounds ((getWidth() * 0.4f) + 2*(getWidth() * 0.05f), 0, getWidth() * 0.05f,	getHeight());

    fontSize->setBounds			((getWidth() * 0.4f) + 3*(getWidth() * 0.05f),							0, getWidth() * 0.14f,	getHeight());
	horizontalScale->setBounds	((getWidth() * 0.4f) + 3*(getWidth() * 0.05f) + (getWidth() * 0.14f),	0, getWidth() * 0.14f,	getHeight());
	kerning->setBounds			((getWidth() * 0.4f) + 3*(getWidth() * 0.05f) + 2*(getWidth() * 0.14f),	0, getWidth() * 0.14f,	getHeight());
}

void CtrlrFontPropertyComponent::comboBoxChanged (ComboBox* comboBoxThatHasChanged)
{
	valueToControl = owner->getCtrlrManagerOwner().getFontManager().getStringFromFont(getFont());
}

void CtrlrFontPropertyComponent::buttonClicked (Button* buttonThatWasClicked)
{
    if (buttonThatWasClicked == fontBold || buttonThatWasClicked == fontItalic || buttonThatWasClicked == fontUnderline)
    {
		valueToControl = owner->getCtrlrManagerOwner().getFontManager().getStringFromFont(getFont());
    }
}

void CtrlrFontPropertyComponent::sliderValueChanged (Slider* sliderThatWasMoved)
{
	valueToControl = owner->getCtrlrManagerOwner().getFontManager().getStringFromFont(getFont());
}

void CtrlrFontPropertyComponent::refresh()
{
	Font font = owner->getCtrlrManagerOwner().getFontManager().getFontFromString(valueToControl.toString());
	typeface->setText (font.getTypefaceName(), sendNotification);
	fontSize->setValue (font.getHeight(), dontSendNotification);
	fontBold->setToggleState (font.isBold(), sendNotification);
	fontItalic->setToggleState (font.isItalic(), sendNotification);
	fontUnderline->setToggleState (font.isUnderlined(), sendNotification);
	kerning->setValue (font.getExtraKerningFactor(), dontSendNotification);
	horizontalScale->setValue (font.getHorizontalScale(), dontSendNotification);
}

Font CtrlrFontPropertyComponent::getFont()
{
	Font font;

	if (typeface)
		font.setTypefaceName (typeface->getText());
	else
		return (font);

	font.setHeight (fontSize->getValue());
	font.setBold (fontBold->getToggleState());
	font.setItalic (fontItalic->getToggleState());
	font.setUnderline (fontUnderline->getToggleState());
	font.setExtraKerningFactor (kerning->getValue());
	font.setHorizontalScale (horizontalScale->getValue());
	return (font);
}

Label* CtrlrFontPropertyComponent::createSliderTextBox (Slider& slider)
{
    Label* const l = new CtrlrFontPropertyComponent::SliderLabelComp();

	l->setFont (Font(10.0f,Font::bold));
    l->setJustificationType (Justification::centred);

    l->setColour (Label::textColourId, slider.findColour (Slider::textBoxTextColourId));

    l->setColour (Label::backgroundColourId,
                  (slider.getSliderStyle() == Slider::LinearBar || slider.getSliderStyle() == Slider::LinearBarVertical)
                            ? Colours::transparentBlack
                            : slider.findColour (Slider::textBoxBackgroundColourId));
    l->setColour (Label::outlineColourId, slider.findColour (Slider::textBoxOutlineColourId));

    l->setColour (TextEditor::textColourId, slider.findColour (Slider::textBoxTextColourId));

    l->setColour (TextEditor::backgroundColourId,
                  slider.findColour (Slider::textBoxBackgroundColourId)
                        .withAlpha ((slider.getSliderStyle() == Slider::LinearBar || slider.getSliderStyle() == Slider::LinearBarVertical)
                                        ? 0.7f : 1.0f));

    l->setColour (TextEditor::outlineColourId, slider.findColour (Slider::textBoxOutlineColourId));

    return l;
}
<commit_msg>Fixed font attribute setting order to prevent multiple modifications of the ValueTree and underlying change notifications (i.e. several modifications of font property when italic status is set while horizontal scale does not yet reflect the actual font's value)<commit_after>#include "stdafx.h"
#include "CtrlrUtilities.h"
#include "CtrlrPanel/CtrlrPanel.h"
#include "CtrlrManager/CtrlrManager.h"
#include "CtrlrFontPropertyComponent.h"
#include "CtrlrProcessor.h"

CtrlrFontPropertyComponent::CtrlrFontPropertyComponent (const Value &_valueToControl, CtrlrPanel *_owner)
    : valueToControl(_valueToControl), owner(_owner),
      typeface (0),
      fontBold (0),
      fontItalic (0),
      fontUnderline (0),
      fontSize (0),
	  kerning(0),
	  horizontalScale(0)
{
    addAndMakeVisible (typeface = new ComboBox (String::empty));
    typeface->setEditableText (false);
    typeface->setJustificationType (Justification::centredLeft);
    typeface->setTextWhenNothingSelected (L"<Sans-Serif>");
    typeface->setTextWhenNoChoicesAvailable (L"<Sans-Serif>");
    typeface->addListener (this);

    addAndMakeVisible (fontBold = new ImageButton (String::empty));
    fontBold->setTooltip (L"Bold");
    fontBold->setButtonText (L"new button");
    fontBold->addListener (this);

    fontBold->setImages (false, true, true,
                         IMAGE (ico_font_bold_png), 0.5000f, Colour (0x0),
                         IMAGE (ico_font_bold_png), 0.7500f, Colour (0xa0ffffff),
                         IMAGE (ico_font_bold_png), 1.0000f, Colour (0x0));
    addAndMakeVisible (fontItalic = new ImageButton (String::empty));
    fontItalic->setTooltip (L"Italic");
    fontItalic->setButtonText (L"new button");
    fontItalic->addListener (this);

    fontItalic->setImages (false, true, true,
                           IMAGE (ico_font_italic_png), 0.5000f, Colour (0x0),
                           IMAGE (ico_font_italic_png), 0.7500f, Colour (0xa0ffffff),
                           IMAGE (ico_font_italic_png), 1.0000f, Colour (0x0));
    addAndMakeVisible (fontUnderline = new ImageButton (String::empty));
    fontUnderline->setTooltip (L"Underline");
    fontUnderline->setButtonText (L"new button");
    fontUnderline->addListener (this);

    fontUnderline->setImages (false, true, true,
                              IMAGE (ico_font_underline_png), 0.5000f, Colour (0x0),
                              IMAGE (ico_font_underline_png), 0.7500f, Colour (0xa0ffffff),
                              IMAGE (ico_font_underline_png), 1.0000f, Colour (0x0));

    addAndMakeVisible (fontSize = new Slider (String::empty));
	fontSize->setLookAndFeel (this);
    fontSize->setTooltip (L"Size");
    fontSize->setRange (1, 999, 1);
    fontSize->setSliderStyle (Slider::RotaryVerticalDrag);
    fontSize->setTextBoxStyle (Slider::TextBoxRight, false, 34, 16);
    fontSize->addListener (this);

	addAndMakeVisible (horizontalScale = new Slider (String::empty));
	horizontalScale->setLookAndFeel (this);
    horizontalScale->setTooltip (L"Horizontal Scale");
    horizontalScale->setRange (0.0, 10.0, 0.01);
    horizontalScale->setSliderStyle (Slider::RotaryVerticalDrag);
    horizontalScale->setTextBoxStyle (Slider::TextBoxRight, false, 34, 16);
    horizontalScale->addListener (this);

	addAndMakeVisible (kerning = new Slider (String::empty));
    kerning->setLookAndFeel (this);
	kerning->setTooltip (L"Extra Kerning");
    kerning->setRange (0.0, 10.0, 0.01);
    kerning->setSliderStyle (Slider::RotaryVerticalDrag);
    kerning->setTextBoxStyle (Slider::TextBoxRight, false, 34, 16);
    kerning->addListener (this);

	fontBold->setClickingTogglesState (true);
	fontBold->setMouseCursor (MouseCursor::PointingHandCursor);
	fontItalic->setClickingTogglesState (true);
	fontItalic->setMouseCursor (MouseCursor::PointingHandCursor);
	fontUnderline->setClickingTogglesState (true);
	fontUnderline->setMouseCursor (MouseCursor::PointingHandCursor);

    owner->getCtrlrManagerOwner().getFontManager().fillCombo (*typeface, true, true, true, true);

    setSize (300, 32);
}

CtrlrFontPropertyComponent::~CtrlrFontPropertyComponent()
{
    deleteAndZero (typeface);
    deleteAndZero (fontBold);
    deleteAndZero (fontItalic);
    deleteAndZero (fontUnderline);
    deleteAndZero (fontSize);
	deleteAndZero (kerning);
	deleteAndZero (horizontalScale);
}

void CtrlrFontPropertyComponent::resized()
{
    typeface->setBounds (0, 0, getWidth() * 0.4f, getHeight());

	fontBold->setBounds (getWidth() * 0.4f,									0, getWidth() * 0.05f,	getHeight());
    fontItalic->setBounds ((getWidth() * 0.4f) + (getWidth() * 0.05f),		0, getWidth() * 0.05f,	getHeight());
	fontUnderline->setBounds ((getWidth() * 0.4f) + 2*(getWidth() * 0.05f), 0, getWidth() * 0.05f,	getHeight());

    fontSize->setBounds			((getWidth() * 0.4f) + 3*(getWidth() * 0.05f),							0, getWidth() * 0.14f,	getHeight());
	horizontalScale->setBounds	((getWidth() * 0.4f) + 3*(getWidth() * 0.05f) + (getWidth() * 0.14f),	0, getWidth() * 0.14f,	getHeight());
	kerning->setBounds			((getWidth() * 0.4f) + 3*(getWidth() * 0.05f) + 2*(getWidth() * 0.14f),	0, getWidth() * 0.14f,	getHeight());
}

void CtrlrFontPropertyComponent::comboBoxChanged (ComboBox* comboBoxThatHasChanged)
{
	valueToControl = owner->getCtrlrManagerOwner().getFontManager().getStringFromFont(getFont());
}

void CtrlrFontPropertyComponent::buttonClicked (Button* buttonThatWasClicked)
{
    if (buttonThatWasClicked == fontBold || buttonThatWasClicked == fontItalic || buttonThatWasClicked == fontUnderline)
    {
		valueToControl = owner->getCtrlrManagerOwner().getFontManager().getStringFromFont(getFont());
	}
}

void CtrlrFontPropertyComponent::sliderValueChanged (Slider* sliderThatWasMoved)
{
	valueToControl = owner->getCtrlrManagerOwner().getFontManager().getStringFromFont(getFont());
}

void CtrlrFontPropertyComponent::refresh()
{
	Font font = owner->getCtrlrManagerOwner().getFontManager().getFontFromString(valueToControl.toString());
	typeface->setText (font.getTypefaceName(), sendNotification);
	fontSize->setValue (font.getHeight(), dontSendNotification);
	kerning->setValue(font.getExtraKerningFactor(), dontSendNotification);
	horizontalScale->setValue(font.getHorizontalScale(), dontSendNotification);
	fontBold->setToggleState (font.isBold(), sendNotification);
	fontItalic->setToggleState (font.isItalic(), sendNotification);
	fontUnderline->setToggleState (font.isUnderlined(), sendNotification);
}

Font CtrlrFontPropertyComponent::getFont()
{
	Font font;

	if (typeface)
		font.setTypefaceName (typeface->getText());
	else
		return (font);

	font.setHeight (fontSize->getValue());
	font.setBold (fontBold->getToggleState());
	font.setItalic (fontItalic->getToggleState());
	font.setUnderline (fontUnderline->getToggleState());
	font.setExtraKerningFactor (kerning->getValue());
	font.setHorizontalScale (horizontalScale->getValue());
	return (font);
}

Label* CtrlrFontPropertyComponent::createSliderTextBox (Slider& slider)
{
    Label* const l = new CtrlrFontPropertyComponent::SliderLabelComp();

	l->setFont (Font(10.0f,Font::bold));
    l->setJustificationType (Justification::centred);

    l->setColour (Label::textColourId, slider.findColour (Slider::textBoxTextColourId));

    l->setColour (Label::backgroundColourId,
                  (slider.getSliderStyle() == Slider::LinearBar || slider.getSliderStyle() == Slider::LinearBarVertical)
                            ? Colours::transparentBlack
                            : slider.findColour (Slider::textBoxBackgroundColourId));
    l->setColour (Label::outlineColourId, slider.findColour (Slider::textBoxOutlineColourId));

    l->setColour (TextEditor::textColourId, slider.findColour (Slider::textBoxTextColourId));

    l->setColour (TextEditor::backgroundColourId,
                  slider.findColour (Slider::textBoxBackgroundColourId)
                        .withAlpha ((slider.getSliderStyle() == Slider::LinearBar || slider.getSliderStyle() == Slider::LinearBarVertical)
                                        ? 0.7f : 1.0f));

    l->setColour (TextEditor::outlineColourId, slider.findColour (Slider::textBoxOutlineColourId));

    return l;
}
<|endoftext|>


<commit_before>/**
 *  @copyright Copyright 2016 The J-PET Framework Authors. All rights reserved.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may find a copy of the License in the LICENCE file.
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *  @file JPetWriter.cpp
 */

#include "JPetWriter.h"
#include "../JPetUserInfoStructure/JPetUserInfoStructure.h"

JPetWriter::JPetWriter(const char* p_fileName) :
  fFileName(p_fileName),			// string z nazwą pliku
  fFile(0),	// plik
  fIsBranchCreated(false),
  fTree(0)
{
  fFile = new TFile(fFileName.c_str(), "RECREATE");
  if (!isOpen()) {
    ERROR("Could not open file to write.");
  } else {
    fTree = new TTree("tree", "tree");
    fTree->SetAutoSave(10000);
  }
}

JPetWriter::~JPetWriter()
{
  if (isOpen()) {
    fTree->AutoSave("SaveSelf");
    delete fFile;
    fFile = 0;
    fTree = 0;
  }
}

void JPetWriter::closeFile()
{
  if (isOpen() ) {
    fTree->AutoSave("SaveSelf");
    delete fFile;
    fFile = 0;
  }
  fFileName.clear();
  fIsBranchCreated = false;
}

void JPetWriter::writeHeader(TObject* header)
{
  // @todo as the second argument should be passed some enum to indicate position of header
  fTree->GetUserInfo()->AddAt(header, JPetUserInfoStructure::kHeader);
}

<commit_msg>In JPetWriter destructor add check if fFile is empty before deleting it<commit_after>/**
 *  @copyright Copyright 2016 The J-PET Framework Authors. All rights reserved.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may find a copy of the License in the LICENCE file.
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *  @file JPetWriter.cpp
 */

#include "JPetWriter.h"
#include "../JPetUserInfoStructure/JPetUserInfoStructure.h"

JPetWriter::JPetWriter(const char* p_fileName) :
  fFileName(p_fileName),			// string z nazwą pliku
  fFile(0),	// plik
  fIsBranchCreated(false),
  fTree(0)
{
  fFile = new TFile(fFileName.c_str(), "RECREATE");
  if (!isOpen()) {
    ERROR("Could not open file to write.");
  } else {
    fTree = new TTree("tree", "tree");
    fTree->SetAutoSave(10000);
  }
}

JPetWriter::~JPetWriter()
{
  if (isOpen()) {
    fTree->AutoSave("SaveSelf");
    if (fFile) {
      delete fFile;
      fFile = 0;
    }
    fTree = 0;
  }
}

void JPetWriter::closeFile()
{
  if (isOpen() ) {
    fTree->AutoSave("SaveSelf");
    delete fFile;
    fFile = 0;
  }
  fFileName.clear();
  fIsBranchCreated = false;
}

void JPetWriter::writeHeader(TObject* header)
{
  // @todo as the second argument should be passed some enum to indicate position of header
  fTree->GetUserInfo()->AddAt(header, JPetUserInfoStructure::kHeader);
}

<|endoftext|>


<commit_before>#include "atlas/utils/Mesh.hpp"
#include "atlas/gl/Buffer.hpp"
#include "atlas/gl/VertexArrayObject.hpp"
#include "atlas/core/Log.hpp"

#include <unordered_set>
#include <functional>

namespace atlas
{
    namespace utils
    {
        struct Mesh::MeshImpl
        {
            MeshImpl() :
                vertexBuffer(GL_ARRAY_BUFFER),
                normalBuffer(GL_ARRAY_BUFFER),
                textureBuffer(GL_ARRAY_BUFFER),
                indexBuffer(GL_ELEMENT_ARRAY_BUFFER),
                isValid(false)
            { }

            MeshImpl(MeshImpl&& impl) = default;
            ~MeshImpl() = default;

            MeshImpl& operator=(MeshImpl&& rhs) = default;

            gl::Buffer vertexBuffer;
            gl::Buffer normalBuffer;
            gl::Buffer textureBuffer;
            gl::Buffer indexBuffer;
            gl::VertexArrayObject vao;

            GLuint numIndices;
            bool isValid;
            bool hasNormals;
            bool hasTextures;
        };

        Mesh::Mesh() :
            mImpl(std::make_unique<MeshImpl>())
        { }

        Mesh::Mesh(Mesh&& rhs) :
            mImpl(std::make_unique<MeshImpl>(std::move(*rhs.mImpl)))
        { }

        Mesh& Mesh::operator=(Mesh&& rhs)
        {
            *mImpl = std::move(*rhs.mImpl);
            return *this;
        }

        Mesh::~Mesh()
        { }

        void Mesh::fromTriangleSoup(
            std::vector<atlas::math::Point> const& vertices,
            std::vector<GLuint> const& indices,
            Mesh& mesh,
            std::vector<atlas::math::Normal> const& normals,
            std::vector<atlas::math::Point2> const& uvs)
        {
            struct MeshVertex
            {
                bool operator==(MeshVertex const& rhs) const
                {
                    return
                        (vertex == rhs.vertex) &&
                        (normal == rhs.normal) &&
                        (uv == rhs.uv);
                }

                bool operator!=(MeshVertex const& rhs) const
                {
                    return !(*this == rhs);
                }

                math::Point vertex;
                math::Normal normal;
                math::Point2 uv;
                GLuint index;
            };

            struct MeshVertexHasher
            {
                std::size_t operator()(MeshVertex const& mv) const
                {
                    return std::hash<float>()(mv.vertex.x + mv.vertex.y +
                        mv.vertex.z);
                }
            };

            bool hasNormals, hasTextures;

            hasNormals = !normals.empty();
            hasTextures = !uvs.empty();

            if (hasNormals && vertices.size() != normals.size())
            {
                WARN_LOG("Number of normals and vertices doesn't match.");
                return;
            }

            if (hasTextures && vertices.size() != uvs.size())
            {
                WARN_LOG("Number of texture coordinates and vertices doesn't\
                         match.");
                return;
            }

            std::unordered_set<MeshVertex, MeshVertexHasher> uniqueVertices;
            std::vector<std::size_t> normalCount;
            GLuint current = 0;
            for (auto& idx : indices)
            {
                MeshVertex v;
                v.vertex = vertices[idx];

                if (hasNormals)
                {
                    v.normal = normals[idx];
                }

                if (hasTextures)
                {
                    v.uv = uvs[idx];
                }

                // Check if this vertex already exists.
                if (uniqueVertices.find(v) == uniqueVertices.end())
                {
                    // It doesn't, so increase the count and insert.
                    mesh.indices().push_back(current);
                    mesh.vertices().push_back(v.vertex);
                    normalCount.push_back(1);

                    if (hasNormals)
                    {
                        mesh.normals().push_back(v.normal);
                    }

                    if (hasTextures)
                    {
                        mesh.uvs().push_back(v.uv);
                    }

                    v.index = current;
                    uniqueVertices.insert(v);
                    current++;
                }
                else
                {
                    // We have already seen this vertex, so grab it's index.
                    auto uniqueV = *uniqueVertices.find(v);
                    mesh.indices().push_back(uniqueV.index);

                    normalCount[uniqueV.index]++;
                    auto k = normalCount[uniqueV.index];
                    auto mK = mesh.normals()[uniqueV.index];
                    mK = mK + ((v.normal - mK) / (float)k);
                    mesh.normals()[uniqueV.index] = mK;
                }
            }

            // Tell the mesh to update itself to reflect the new data.
            mesh.updateMesh();
            mesh.updateIndices();
        }

        std::vector<atlas::math::Point>& Mesh::vertices()
        {
            return mVertices;
        }

        std::vector<atlas::math::Normal>& Mesh::normals()
        {
            return mNormals;
        }

        std::vector<atlas::math::Point2>& Mesh::uvs()
        {
            return mUvs;
        }

        std::vector<GLuint>& Mesh::indices()
        {
            return mIndices;
        }

        bool Mesh::isValid() const
        {
            return mImpl->isValid;
        }

        void Mesh::setVertexAttribArrays(std::vector<GLuint> const& arrays)
        {
            if (arrays.size() < 1)
            {
                WARN_LOG("No indices provided for vertex attribute arrays.");
                mImpl->isValid = false;
                return;
            }

            mImpl->vao.bindVertexArray();
            for (auto& idx : arrays)
            {
                mImpl->vao.enableVertexAttribArray(idx);
            }

            mImpl->vertexBuffer.bindBuffer();
            mImpl->vertexBuffer.vertexAttribPointer(arrays[0],
                3, GL_FLOAT, GL_FALSE, gl::stride<math::Point>(0),
                gl::bufferOffset<math::Point>(0));

            if (mImpl->hasNormals && arrays.size() < 2)
            {
                WARN_LOG(std::string("No index for normal vertex attribute") +
                    " array provided. Normals will not be bound.");
                return;
            }

            mImpl->normalBuffer.bindBuffer();
            mImpl->normalBuffer.vertexAttribPointer(arrays[1],
                3, GL_FLOAT, GL_FALSE, gl::stride<math::Normal>(0),
                gl::bufferOffset<math::Normal>(0));

            if (mImpl->hasTextures && arrays.size() < 3)
            {
                WARN_LOG("No index for texture coordinates vertex attribute \
                    array provided. Texture coordinates will not be bound.");
                return;
            }

            mImpl->textureBuffer.bindBuffer();
            mImpl->textureBuffer.vertexAttribPointer(arrays[2],
                2, GL_FLOAT, GL_FALSE, gl::stride<math::Point2>(0),
                gl::bufferOffset<math::Point2>(0));

            mImpl->textureBuffer.unBindBuffer();
            mImpl->vao.unBindVertexArray();
        }

        void Mesh::updateMesh()
        {
            if (mVertices.empty())
            {
                WARN_LOG("Attempting to create a mesh with no vertices.");
                mImpl->isValid = false;
                return;
            }

            // Now check if we have normals or texture coordinates.
            mImpl->hasNormals = !mNormals.empty();
            mImpl->hasTextures= !mUvs.empty();

            // Now check if all the arrays have the same size.
            if (mImpl->hasNormals && mVertices.size() != mNormals.size())
            {
                WARN_LOG("Number of normals and vertices don't match.");
                mImpl->isValid = false;
                return;
            }

            if (mImpl->hasTextures && mVertices.size() != mUvs.size())
            {
                WARN_LOG("Number of texture coordinates and vertices don't \
                        match.");
                mImpl->isValid = false;
                return;
            }

            mImpl->vertexBuffer.bindBuffer();
            mImpl->vertexBuffer.bufferData(
                gl::size<math::Point>(mVertices.size()), mVertices.data(),
                GL_DYNAMIC_DRAW);
            mImpl->vertexBuffer.unBindBuffer();

            if (mImpl->hasNormals)
            {
                mImpl->normalBuffer.bindBuffer();
                mImpl->normalBuffer.bufferData(
                    gl::size<math::Normal>(mNormals.size()),
                    mNormals.data(), GL_DYNAMIC_DRAW);
                mImpl->normalBuffer.unBindBuffer();
            }

            if (mImpl->hasTextures)
            {
                mImpl->textureBuffer.bindBuffer();
                mImpl->textureBuffer.bufferData(
                    gl::size<math::Point2>(mUvs.size()), mUvs.data(),
                    GL_DYNAMIC_DRAW);
                mImpl->textureBuffer.unMapBuffer();
            }

            // At this point everything is bound and ready to go, so the mesh
            // is valid.
            mImpl->isValid = true;
        }

        void Mesh::updateIndices()
        {
            mImpl->indexBuffer.bindBuffer();
            mImpl->indexBuffer.bufferData(gl::size<GLuint>(mIndices.size()),
                mIndices.data(), GL_DYNAMIC_DRAW);
            mImpl->indexBuffer.unBindBuffer();
            mImpl->numIndices = (GLuint)mIndices.size();
        }

        void Mesh::renderMesh()
        {
            if (!mImpl->isValid)
            {
                return;
            }

            mImpl->vao.bindVertexArray();
            mImpl->indexBuffer.bindBuffer();
            glDrawElements(GL_TRIANGLES, mImpl->numIndices,
                GL_UNSIGNED_INT, gl::bufferOffset<GLuint>(0));
            mImpl->vao.unBindVertexArray();
            mImpl->indexBuffer.unBindBuffer();
        }
    }
}<commit_msg>[brief] Fixes warning message formatting for Mesh.<commit_after>#include "atlas/utils/Mesh.hpp"
#include "atlas/gl/Buffer.hpp"
#include "atlas/gl/VertexArrayObject.hpp"
#include "atlas/core/Log.hpp"

#include <unordered_set>
#include <functional>

namespace atlas
{
    namespace utils
    {
        struct Mesh::MeshImpl
        {
            MeshImpl() :
                vertexBuffer(GL_ARRAY_BUFFER),
                normalBuffer(GL_ARRAY_BUFFER),
                textureBuffer(GL_ARRAY_BUFFER),
                indexBuffer(GL_ELEMENT_ARRAY_BUFFER),
                isValid(false)
            { }

            MeshImpl(MeshImpl&& impl) = default;
            ~MeshImpl() = default;

            MeshImpl& operator=(MeshImpl&& rhs) = default;

            gl::Buffer vertexBuffer;
            gl::Buffer normalBuffer;
            gl::Buffer textureBuffer;
            gl::Buffer indexBuffer;
            gl::VertexArrayObject vao;

            GLuint numIndices;
            bool isValid;
            bool hasNormals;
            bool hasTextures;
        };

        Mesh::Mesh() :
            mImpl(std::make_unique<MeshImpl>())
        { }

        Mesh::Mesh(Mesh&& rhs) :
            mImpl(std::make_unique<MeshImpl>(std::move(*rhs.mImpl)))
        { }

        Mesh& Mesh::operator=(Mesh&& rhs)
        {
            *mImpl = std::move(*rhs.mImpl);
            return *this;
        }

        Mesh::~Mesh()
        { }

        void Mesh::fromTriangleSoup(
            std::vector<atlas::math::Point> const& vertices,
            std::vector<GLuint> const& indices,
            Mesh& mesh,
            std::vector<atlas::math::Normal> const& normals,
            std::vector<atlas::math::Point2> const& uvs)
        {
            struct MeshVertex
            {
                bool operator==(MeshVertex const& rhs) const
                {
                    return
                        (vertex == rhs.vertex) &&
                        (normal == rhs.normal) &&
                        (uv == rhs.uv);
                }

                bool operator!=(MeshVertex const& rhs) const
                {
                    return !(*this == rhs);
                }

                math::Point vertex;
                math::Normal normal;
                math::Point2 uv;
                GLuint index;
            };

            struct MeshVertexHasher
            {
                std::size_t operator()(MeshVertex const& mv) const
                {
                    return std::hash<float>()(mv.vertex.x + mv.vertex.y +
                        mv.vertex.z);
                }
            };

            bool hasNormals, hasTextures;

            hasNormals = !normals.empty();
            hasTextures = !uvs.empty();

            if (hasNormals && vertices.size() != normals.size())
            {
                WARN_LOG("Number of normals and vertices doesn't match.");
                return;
            }

            if (hasTextures && vertices.size() != uvs.size())
            {
                WARN_LOG("Number of texture coordinates and vertices doesn't\
                         match.");
                return;
            }

            std::unordered_set<MeshVertex, MeshVertexHasher> uniqueVertices;
            std::vector<std::size_t> normalCount;
            GLuint current = 0;
            for (auto& idx : indices)
            {
                MeshVertex v;
                v.vertex = vertices[idx];

                if (hasNormals)
                {
                    v.normal = normals[idx];
                }

                if (hasTextures)
                {
                    v.uv = uvs[idx];
                }

                // Check if this vertex already exists.
                if (uniqueVertices.find(v) == uniqueVertices.end())
                {
                    // It doesn't, so increase the count and insert.
                    mesh.indices().push_back(current);
                    mesh.vertices().push_back(v.vertex);
                    normalCount.push_back(1);

                    if (hasNormals)
                    {
                        mesh.normals().push_back(v.normal);
                    }

                    if (hasTextures)
                    {
                        mesh.uvs().push_back(v.uv);
                    }

                    v.index = current;
                    uniqueVertices.insert(v);
                    current++;
                }
                else
                {
                    // We have already seen this vertex, so grab it's index.
                    auto uniqueV = *uniqueVertices.find(v);
                    mesh.indices().push_back(uniqueV.index);

                    normalCount[uniqueV.index]++;
                    auto k = normalCount[uniqueV.index];
                    auto mK = mesh.normals()[uniqueV.index];
                    mK = mK + ((v.normal - mK) / (float)k);
                    mesh.normals()[uniqueV.index] = mK;
                }
            }

            // Tell the mesh to update itself to reflect the new data.
            mesh.updateMesh();
            mesh.updateIndices();
        }

        std::vector<atlas::math::Point>& Mesh::vertices()
        {
            return mVertices;
        }

        std::vector<atlas::math::Normal>& Mesh::normals()
        {
            return mNormals;
        }

        std::vector<atlas::math::Point2>& Mesh::uvs()
        {
            return mUvs;
        }

        std::vector<GLuint>& Mesh::indices()
        {
            return mIndices;
        }

        bool Mesh::isValid() const
        {
            return mImpl->isValid;
        }

        void Mesh::setVertexAttribArrays(std::vector<GLuint> const& arrays)
        {
            if (arrays.size() < 1)
            {
                WARN_LOG("No indices provided for vertex attribute arrays.");
                mImpl->isValid = false;
                return;
            }

            mImpl->vao.bindVertexArray();
            for (auto& idx : arrays)
            {
                mImpl->vao.enableVertexAttribArray(idx);
            }

            mImpl->vertexBuffer.bindBuffer();
            mImpl->vertexBuffer.vertexAttribPointer(arrays[0],
                3, GL_FLOAT, GL_FALSE, gl::stride<math::Point>(0),
                gl::bufferOffset<math::Point>(0));

            if (mImpl->hasNormals && arrays.size() < 2)
            {
                WARN_LOG(std::string("No index for normal vertex attribute") +
                    " array provided. Normals will not be bound.");
                return;
            }

            mImpl->normalBuffer.bindBuffer();
            mImpl->normalBuffer.vertexAttribPointer(arrays[1],
                3, GL_FLOAT, GL_FALSE, gl::stride<math::Normal>(0),
                gl::bufferOffset<math::Normal>(0));

            if (mImpl->hasTextures && arrays.size() < 3)
            {
                WARN_LOG(std::string("No index for texture coordinates ") +
                    "vertex attribute array provided. Texture coordinates will" +
                    " not be bound.");
                return;
            }

            mImpl->textureBuffer.bindBuffer();
            mImpl->textureBuffer.vertexAttribPointer(arrays[2],
                2, GL_FLOAT, GL_FALSE, gl::stride<math::Point2>(0),
                gl::bufferOffset<math::Point2>(0));

            mImpl->textureBuffer.unBindBuffer();
            mImpl->vao.unBindVertexArray();
        }

        void Mesh::updateMesh()
        {
            if (mVertices.empty())
            {
                WARN_LOG("Attempting to create a mesh with no vertices.");
                mImpl->isValid = false;
                return;
            }

            // Now check if we have normals or texture coordinates.
            mImpl->hasNormals = !mNormals.empty();
            mImpl->hasTextures= !mUvs.empty();

            // Now check if all the arrays have the same size.
            if (mImpl->hasNormals && mVertices.size() != mNormals.size())
            {
                WARN_LOG("Number of normals and vertices don't match.");
                mImpl->isValid = false;
                return;
            }

            if (mImpl->hasTextures && mVertices.size() != mUvs.size())
            {
                WARN_LOG(std::string("Number of texture coordinates and ") +
                    "vertices don't  match.");
                mImpl->isValid = false;
                return;
            }

            mImpl->vertexBuffer.bindBuffer();
            mImpl->vertexBuffer.bufferData(
                gl::size<math::Point>(mVertices.size()), mVertices.data(),
                GL_DYNAMIC_DRAW);
            mImpl->vertexBuffer.unBindBuffer();

            if (mImpl->hasNormals)
            {
                mImpl->normalBuffer.bindBuffer();
                mImpl->normalBuffer.bufferData(
                    gl::size<math::Normal>(mNormals.size()),
                    mNormals.data(), GL_DYNAMIC_DRAW);
                mImpl->normalBuffer.unBindBuffer();
            }

            if (mImpl->hasTextures)
            {
                mImpl->textureBuffer.bindBuffer();
                mImpl->textureBuffer.bufferData(
                    gl::size<math::Point2>(mUvs.size()), mUvs.data(),
                    GL_DYNAMIC_DRAW);
                mImpl->textureBuffer.unMapBuffer();
            }

            // At this point everything is bound and ready to go, so the mesh
            // is valid.
            mImpl->isValid = true;
        }

        void Mesh::updateIndices()
        {
            mImpl->indexBuffer.bindBuffer();
            mImpl->indexBuffer.bufferData(gl::size<GLuint>(mIndices.size()),
                mIndices.data(), GL_DYNAMIC_DRAW);
            mImpl->indexBuffer.unBindBuffer();
            mImpl->numIndices = (GLuint)mIndices.size();
        }

        void Mesh::renderMesh()
        {
            if (!mImpl->isValid)
            {
                return;
            }

            mImpl->vao.bindVertexArray();
            mImpl->indexBuffer.bindBuffer();
            glDrawElements(GL_TRIANGLES, mImpl->numIndices,
                GL_UNSIGNED_INT, gl::bufferOffset<GLuint>(0));
            mImpl->vao.unBindVertexArray();
            mImpl->indexBuffer.unBindBuffer();
        }
    }
}<|endoftext|>


<commit_before>#include "cetech/task_manager/task_manager.h"

#include "celib/memory/memory.h"
#include "celib/container/array.inl.h"
#include "cetech/thread/thread.h"

#include "cetech/application/application.h"
#include "cetech/log_system/log_system.h"

#define TASK_INITIALIZER { { 0 }, { 0 }, { 0 }, 0, 0, { 0, 0 } }

//TODO: REWRITE !!! #62
namespace cetech {
    namespace {
        using namespace task_manager;

        /*!
         * Task worker callback.
         */
        struct TaskWorkCallback {
            TaskWorkFce_t fce;    //!< Worker fce.
            void* data;           //!< Worker data.
        };

        struct Task {
            TaskID id;                  //!< Task id
            TaskID depend;              //!< Task depend
            TaskID parent;              //!< Task parent

            uint32_t priority;         //!< Task priority
            uint32_t job_count;        //!< Task child active job
            TaskWorkCallback clb;      //!< Callback
        };

        enum {
            MAX_TASK = 512
        };

        struct TaskManagerData {
            Spinlock _lock;               //!< Spinlock

            uint32_t _last_id;                //!< Last id
            uint32_t _task_count;             //!< Task count
            uint32_t _open_task_count;        //!< Open task count

            uint32_t _task_queue[MAX_TASK];   //!< Task queue
            uint32_t _open_task[MAX_TASK];    //!< Open task
            Task _task_pool[MAX_TASK];        //!< Task pool

            Array < Thread > _workers;

            struct {
                char run : 1;
            } flags;

            TaskManagerData(Allocator & allocator) : _last_id(0),
                                                     _task_count(0),
                                                     _open_task_count(0),
                                                     _workers(allocator) {

                memset(_task_queue, 0, sizeof(uint32_t) * MAX_TASK);
                memset(_open_task, 0, sizeof(uint32_t) * MAX_TASK);
                memset(_task_pool, 0, sizeof(Task) * MAX_TASK);
            }

            ~TaskManagerData() {
                for (uint32_t i = 0; i < array::size(_workers); ++i) {
                    log::debug("task", "Killing worker%u.", i);
                    thread::kill(_workers[i]);
                }
            };

        };

        struct Globals {
            static const int MEMORY = sizeof(TaskManagerData);
            char buffer[MEMORY];

            TaskManagerData* data;

            Globals() : data(0) {}
        } _globals;

        uint32_t _core_count() {
#if defined(CETECH_SDL2)
            return SDL_GetCPUCount();
#endif
        }

        static int task_worker(void* data) {
            while (_globals.data->flags.run) {
                task_manager::do_work();
            }

            return 0;
        }

        /*! NOP task.
         */
        static void _task_nop(void*) {}

        /*! Get new task idx from pool.
         * \return Task idx.
         */
        CE_INLINE uint32_t _new_task_from_pool() {
            for (uint32_t i = 0; i < MAX_TASK; ++i) {
                if (_globals.data->_task_pool[i].id.i != 0) {
                    continue;
                }

                return i;
            }

            /* TODO =( */
            log::error("task", "Pool overflow");
            abort();
        }

        /*! Find task in pool
         * \param id Task id.
         * \return Task ptr.
         * \retval NULL Task not found.
         */
        CE_INLINE Task* _find_task_in_pool(TaskID id) {
            for (uint32_t i = 0; i < MAX_TASK; ++i) {
                if (_globals.data->_task_pool[i].id.i != id.i) {
                    continue;
                }

                return &_globals.data->_task_pool[i];
            }

            return NULL;
        }

        /*! Mark job as done.
         * \param id Task id.
         */
        void _mark_task_job_done(TaskID id) {
            //thread::spin_lock(_globals.data->_lock);

            for (uint32_t i = 0; i < _globals.data->_open_task_count; ++i) {
                Task* t = &_globals.data->_task_pool[_globals.data->_open_task[i]];

                if (t->id.i != id.i) {
                    continue;
                }

                t->id.i = 0;

                if (t->parent.i != 0) {
                    Task* parent_task = _find_task_in_pool(t->parent);
                    --parent_task->job_count;
                }

                _globals.data->_open_task[i] = _globals.data->_open_task[_globals.data->_open_task_count - 1];
                --_globals.data->_open_task_count;
                break;
            }

            //thread::spin_unlock(_globals.data->_lock);
        }

        /*! Is task done?
         * \param id Task id.
         * \retval 0 Not done.
         * \retval 1 Done.
         */
        CE_INLINE uint8_t _is_task_done(TaskID id) {
            uint8_t is_done = 1;

            for (uint32_t i = 0; i < _globals.data->_open_task_count; ++i) {
                if (_globals.data->_task_pool[_globals.data->_open_task[i]].id.i != id.i) {
                    continue;
                }

                is_done = 0;
                break;
            }

            return is_done;
        }

        int8_t task_is_null(TaskID id) {
            return id.i == 0;
        }

        uint32_t task_get_worker_id() {
            uint32_t id = thread::id();

            for (uint8_t i = 0; i < array::size(_globals.data->_workers); ++i) {
                if (thread::get_id(_globals.data->_workers[i]) != id) {
                    continue;
                }

                return i + 1;
            }

            return 0;
        }

        uint8_t task_is_done(TaskID id) {
            // thread::spin_lock(_lock);
            uint8_t is_done = _is_task_done(id);
            // thread::spin_unlock(_lock);
            return is_done;
        }

        Task task_pop_new_work() {
            //thread::spin_lock(_globals.data->_lock);

            if (_globals.data->_task_count < 1) {
                //thread::spin_unlock(_globals.data->_lock);
                return (Task)TASK_INITIALIZER;
            }

            for (int32_t i = _globals.data->_task_count - 1; i >= 0; --i) {
                Task t = _globals.data->_task_pool[_globals.data->_task_queue[i]];

                if (t.job_count != 1) {
                    continue;
                }

                if (t.depend.i > 0) {
                    if (!_is_task_done(t.depend)) {
                        continue;
                    }
                }

                for (; i < _globals.data->_task_count; ++i) {
                    _globals.data->_task_queue[i] = _globals.data->_task_queue[i + 1];
                }

                --_globals.data->_task_count;
                CE_ASSERT(_globals.data->_task_count != 4294967295);

                //thread::spin_unlock(_globals.data->_lock);
                return t;
            }

            //thread::spin_unlock(_globals.data->_lock);
            return (Task)TASK_INITIALIZER;
        }

    }

    namespace task_manager {
        TaskID add_begin(const TaskWorkFce_t fce,
                         void* data,
                         const uint32_t priority,
                         const TaskID depend,
                         const TaskID parent) {
            TaskWorkCallback callback = { fce, data };

            //thread::spin_lock(_globals.data->_lock);

            const uint32_t id = ++_globals.data->_last_id;

            uint32_t task = _new_task_from_pool();

            /* First? */
            if (_globals.data->_task_count == 0) {
                Task t;
                t.id = { id },
                t.priority = priority,
                t.clb = callback,
                t.job_count = 2,
                t.depend = depend,
                t.parent = parent,

                _globals.data->_task_pool[task] = t;

                _globals.data->_task_queue[0] = task;
            } else {

                /* push item to queue */
                uint32_t i = _globals.data->_task_count;

                while (i > 0 && _globals.data->_task_pool[_globals.data->_task_queue[i - 1]].priority > priority) {
                    _globals.data->_task_queue[i] = _globals.data->_task_queue[i - 1];
                    --i;
                }

                Task t;
                t.id = { id },
                t.priority = priority,
                t.clb = callback,
                t.job_count = 2,
                t.depend = depend,
                t.parent = parent,

                _globals.data->_task_pool[task] = t;

                _globals.data->_task_queue[i] = task;
            }

            if (parent.i != 0) {
                Task* t = _find_task_in_pool(parent);
                ++t->job_count;
            }

            _globals.data->_open_task[_globals.data->_open_task_count] = task;
            ++_globals.data->_open_task_count;
            ++_globals.data->_task_count;

            //thread::spin_unlock(_globals.data->_lock);
            return (TaskID) {
                       id
            };

        }

        TaskID add_empty_begin(const uint32_t priority, const TaskID depend, const TaskID parent) {
            return add_begin(_task_nop, 0, priority, depend, parent);
        }

        void add_end(const TaskID* tasks, const uint32_t count) {
            //thread::spin_lock(_globals.data->_lock);

            for (uint32_t i = 0; i < MAX_TASK; ++i) {
                for (uint32_t j = 0; j < count; ++j) {
                    if (_globals.data->_task_pool[i].id.i != tasks[j].i) {
                        continue;
                    }

                    --_globals.data->_task_pool[i].job_count;
                    break;
                }
            }

            //thread::spin_unlock(_globals.data->_lock);
        }

        void do_work() {
            Task t = task_pop_new_work();

            if (t.id.i == 0) {
                return;
            }

            CE_ASSERT(t.clb.fce != NULL);

            t.clb.fce(t.clb.data);

            _mark_task_job_done(t.id);
        }

        void wait(const TaskID id) {
            while (_globals.data->flags.run && (array::size(_globals.data->_workers) > 0) &&
                   !task_is_done(id)) {
                do_work();
            }
        }

        void spawn_workers() {
            uint32_t core_count = _core_count() * 2;

            static const uint32_t main_threads_count = 1 + 1;
            const uint32_t worker_count = core_count - main_threads_count;

            log::info("task", "Core count: %u", core_count);
            log::info("task", "Main thread count: %u", main_threads_count);
            log::info("task", "Worker count: %u", worker_count);

            if (worker_count > 0) {
                for (uint32_t i = 0; i < worker_count; ++i) {
                    log::debug("task", "Creating worker %u.", i);
                    array::push_back(_globals.data->_workers, thread::create_thread(task_worker, "Worker", 0));
                }
            }

            _globals.data->flags.run = 1;
        }

        void stop() {
            _globals.data->flags.run = 0;
        }

    }

    namespace task_manager_globals {
        void init() {
            log::info("task_manager_globals", "Init");
            char* p = _globals.buffer;
            _globals.data = new(p) TaskManagerData(memory_globals::default_allocator());

            spawn_workers();
        }

        void shutdown() {
            log::info("task_manager_globals", "Shutdown");

            _globals.data->~TaskManagerData();
            _globals = Globals();
        }
    }

}<commit_msg>new queue to task manager #62<commit_after>#include "cetech/task_manager/task_manager.h"

#include "celib/memory/memory.h"
#include "celib/container/array.inl.h"
#include "celib/container/queue.inl.h"

#include "cetech/thread/thread.h"
#include "cetech/application/application.h"
#include "cetech/log_system/log_system.h"

#define TASK_INITIALIZER { { 0 }, { 0 }, { 0 }, 0, 0, { 0, 0 } }

//TODO: REWRITE !!! #62
namespace cetech {
    namespace {
        using namespace task_manager;

        /*!
         * Task worker callback.
         */
        struct TaskWorkCallback {
            TaskWorkFce_t fce;    //!< Worker fce.
            void* data;           //!< Worker data.
        };

        struct Task {
            TaskID id;                  //!< Task id
            TaskID depend;              //!< Task depend
            TaskID parent;              //!< Task parent

            uint32_t priority;         //!< Task priority
            uint32_t job_count;        //!< Task child active job
            TaskWorkCallback clb;      //!< Callback
        };

        enum {
            MAX_TASK = 512
        };

        struct TaskManagerData {
            Spinlock _lock;               //!< Spinlock

            uint32_t _last_id;                //!< Last id
            uint32_t _task_count;             //!< Task count
            uint32_t _open_task_count;        //!< Open task count

            uint32_t _open_task[MAX_TASK];    //!< Open task
            Task _task_pool[MAX_TASK];        //!< Task pool

            Array < Thread > _workers;
            Queue<uint32_t> _queue;

            struct {
                char run : 1;
            } flags;

            TaskManagerData(Allocator & allocator) : _last_id(0),
                                                     _task_count(0),
                                                     _open_task_count(0),
                                                     _workers(allocator), _queue(allocator) {

                memset(_open_task, 0, sizeof(uint32_t) * MAX_TASK);
                memset(_task_pool, 0, sizeof(Task) * MAX_TASK);
            }

            ~TaskManagerData() {
                for (uint32_t i = 0; i < array::size(_workers); ++i) {
                    log::debug("task", "Killing worker%u.", i);
                    thread::kill(_workers[i]);
                }
            };

        };

        struct Globals {
            static const int MEMORY = sizeof(TaskManagerData);
            char buffer[MEMORY];

            TaskManagerData* data;

            Globals() : data(0) {}
        } _globals;

        uint32_t _core_count() {
#if defined(CETECH_SDL2)
            return SDL_GetCPUCount();
#endif
        }

        static int task_worker(void* data) {
            while (_globals.data->flags.run) {
                task_manager::do_work();
            }

            return 0;
        }

        /*! NOP task.
         */
        static void _task_nop(void*) {}

        /*! Get new task idx from pool.
         * \return Task idx.
         */
        CE_INLINE uint32_t _new_task_from_pool() {
            for (uint32_t i = 0; i < MAX_TASK; ++i) {
                if (_globals.data->_task_pool[i].id.i != 0) {
                    continue;
                }

                return i;
            }
            CE_ASSERT_MSG(false, "Pool overflow");
            abort();
        }

        /*! Find task in pool
         * \param id Task id.
         * \return Task ptr.
         * \retval NULL Task not found.
         */
        CE_INLINE Task* _find_task_in_pool(TaskID id) {
            for (uint32_t i = 0; i < MAX_TASK; ++i) {
                if (_globals.data->_task_pool[i].id.i != id.i) {
                    continue;
                }

                return &_globals.data->_task_pool[i];
            }

            return NULL;
        }

        /*! Mark job as done.
         * \param id Task id.
         */
        void _mark_task_job_done(TaskID id) {
            //thread::spin_lock(_globals.data->_lock);

            for (uint32_t i = 0; i < _globals.data->_open_task_count; ++i) {
                Task* t = &_globals.data->_task_pool[_globals.data->_open_task[i]];

                if (t->id.i != id.i) {
                    continue;
                }

                t->id.i = 0;

                if (t->parent.i != 0) {
                    Task* parent_task = _find_task_in_pool(t->parent);
                    --parent_task->job_count;
                }

                _globals.data->_open_task[i] = _globals.data->_open_task[_globals.data->_open_task_count - 1];
                --_globals.data->_open_task_count;
                break;
            }

            //thread::spin_unlock(_globals.data->_lock);
        }

        /*! Is task done?
         * \param id Task id.
         * \retval 0 Not done.
         * \retval 1 Done.
         */
        CE_INLINE uint8_t _is_task_done(TaskID id) {
            uint8_t is_done = 1;

            for (uint32_t i = 0; i < _globals.data->_open_task_count; ++i) {
                if (_globals.data->_task_pool[_globals.data->_open_task[i]].id.i != id.i) {
                    continue;
                }

                is_done = 0;
                break;
            }

            return is_done;
        }

        int8_t task_is_null(TaskID id) {
            return id.i == 0;
        }

        uint32_t task_get_worker_id() {
            uint32_t id = thread::id();

            for (uint8_t i = 0; i < array::size(_globals.data->_workers); ++i) {
                if (thread::get_id(_globals.data->_workers[i]) != id) {
                    continue;
                }

                return i + 1;
            }

            return 0;
        }

        uint8_t task_is_done(TaskID id) {
            // thread::spin_lock(_lock);
            uint8_t is_done = _is_task_done(id);
            // thread::spin_unlock(_lock);
            return is_done;
        }

        Task task_pop_new_work() {
            //thread::spin_lock(_globals.data->_lock);

            while(1) {
                if(queue::size(_globals.data->_queue) < 1) {
                    return (Task)TASK_INITIALIZER;
                }

                uint32_t poped_task = _globals.data->_queue[0];
                queue::pop_front(_globals.data->_queue);

                Task t = _globals.data->_task_pool[poped_task];

                if (t.job_count != 1) {
                    queue::push_back(_globals.data->_queue, poped_task);
                    continue;
                }

                if (t.depend.i > 0) {
                    if (!_is_task_done(t.depend)) {
                        queue::push_back(_globals.data->_queue, poped_task);
                        continue;
                    }
                }

                --_globals.data->_task_count;
                return t;
            }

            return (Task)TASK_INITIALIZER;

            //thread::spin_unlock(_globals.data->_lock);
            //return (Task)TASK_INITIALIZER;
        }

    }

    namespace task_manager {
        TaskID add_begin(const TaskWorkFce_t fce,
                         void* data,
                         const uint32_t priority,
                         const TaskID depend,
                         const TaskID parent) {
            TaskWorkCallback callback = { fce, data };

            //thread::spin_lock(_globals.data->_lock);

            const uint32_t id = ++_globals.data->_last_id;

            uint32_t task = _new_task_from_pool();

            Task t;
            t.id = { id },
            t.priority = priority,
            t.clb = callback,
            t.job_count = 2,
            t.depend = depend,
            t.parent = parent,

            _globals.data->_task_pool[task] = t;

            if (parent.i != 0) {
                Task* t = _find_task_in_pool(parent);
                ++t->job_count;
            }

            _globals.data->_open_task[_globals.data->_open_task_count] = task;
            ++_globals.data->_open_task_count;
            ++_globals.data->_task_count;

            //thread::spin_unlock(_globals.data->_lock);
            return (TaskID) {
                       id
            };

        }

        TaskID add_empty_begin(const uint32_t priority, const TaskID depend, const TaskID parent) {
            return add_begin(_task_nop, 0, priority, depend, parent);
        }

        void add_end(const TaskID* tasks, const uint32_t count) {
            //thread::spin_lock(_globals.data->_lock);

            for (uint32_t i = 0; i < MAX_TASK; ++i) {
                for (uint32_t j = 0; j < count; ++j) {
                    if (_globals.data->_task_pool[i].id.i != tasks[j].i) {
                        continue;
                    }

                    --_globals.data->_task_pool[i].job_count;
                    queue::push_back(_globals.data->_queue, i);
                    break;
                }
            }

            //thread::spin_unlock(_globals.data->_lock);
        }

        void do_work() {
            Task t = task_pop_new_work();

            if (t.id.i == 0) {
                return;
            }

            CE_ASSERT(t.clb.fce != NULL);

            t.clb.fce(t.clb.data);

            _mark_task_job_done(t.id);
        }

        void wait(const TaskID id) {
            while (_globals.data->flags.run && (array::size(_globals.data->_workers) > 0) &&
                   !task_is_done(id)) {
                do_work();
            }
        }

        void spawn_workers() {
            uint32_t core_count = _core_count() * 2;

            static const uint32_t main_threads_count = 1 + 1;
            const uint32_t worker_count = core_count - main_threads_count;

            log::info("task", "Core count: %u", core_count);
            log::info("task", "Main thread count: %u", main_threads_count);
            log::info("task", "Worker count: %u", worker_count);

            if (worker_count > 0) {
                for (uint32_t i = 0; i < worker_count; ++i) {
                    log::debug("task", "Creating worker %u.", i);
                    array::push_back(_globals.data->_workers, thread::create_thread(task_worker, "Worker", 0));
                }
            }

            _globals.data->flags.run = 1;
        }

        void stop() {
            _globals.data->flags.run = 0;
        }

    }

    namespace task_manager_globals {
        void init() {
            log::info("task_manager_globals", "Init");
            char* p = _globals.buffer;
            _globals.data = new(p) TaskManagerData(memory_globals::default_allocator());

            spawn_workers();
        }

        void shutdown() {
            log::info("task_manager_globals", "Shutdown");

            _globals.data->~TaskManagerData();
            _globals = Globals();
        }
    }

}<|endoftext|>