<commit_before>#define SPICA_TRIMESH_EXPORT
#include "trimesh.h"

#include <cstdio>
#include <cstring>
#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>

#include "../utils/common.h"

namespace spica {

    Trimesh::Trimesh()
        : _numVerts(0)
        , _numFaces(0)
        , _vertices(NULL)
        , _faces(NULL)
        , _normals(NULL)
        , _accel(NULL)
        , _accelType(QBVH_ACCEL)
    {
    }

    Trimesh::Trimesh(const std::string& filename)
        : _numVerts(0)
        , _numFaces(0)
        , _vertices(NULL)
        , _faces(NULL)
        , _normals(NULL)
        , _accel(NULL)
        , _accelType(QBVH_ACCEL)
    {
        load(filename);
    }

    Trimesh::Trimesh(const Trimesh& trimesh)
        : _numVerts(0)
        , _numFaces(0)
        , _vertices(NULL)
        , _faces(NULL)
        , _normals(NULL)
        , _accel(NULL)
        , _accelType(QBVH_ACCEL)
    {
        operator=(trimesh);
    }

    Trimesh::~Trimesh()
    {
        release();
    }

    void Trimesh::release() {
        delete[] _vertices;
        delete[] _faces;
        delete[] _normals;
        delete   _accel;
        _numVerts = 0;
        _numFaces = 0;
        _vertices = NULL;
        _faces    = NULL;
        _normals  = NULL;
        _accel    = NULL;
    }

    Trimesh& Trimesh::operator=(const Trimesh& trimesh) {
        release();

        _numVerts = trimesh._numVerts;
        _numFaces = trimesh._numFaces;
        _vertices = new Vector3[trimesh._numVerts];
        _faces = new int[trimesh._numFaces * 3];
        _normals = new Vector3[trimesh._numFaces];
        _accel = NULL;
        _accelType = trimesh._accelType;

        memcpy(_vertices, trimesh._vertices, sizeof(Vector3) * _numVerts);
        memcpy(_faces, trimesh._faces, sizeof(int) * (_numFaces * 3));
        memcpy(_normals, trimesh._normals, sizeof(Vector3) * _numFaces);

        buildAccel();

        return *this;
    }

    bool Trimesh::intersect(const Ray& ray, Hitpoint* hitpoint) const {
        msg_assert(_accel != NULL, "Accelerator is not constructed");
        hitpoint->setDistance(INFTY);
        return _accel->intersect(ray, hitpoint);
    }

    double Trimesh::area() const {
        double ret = 0.0;
        for (int i = 0; i < _numFaces; i++) {
            Triangle tri = this->getTriangle(i);
            ret += tri.area();
        }
        return ret;
    }

    void Trimesh::setAccelType(AccelType accelType, bool doBuild) {
        this->_accelType = accelType;
        if (doBuild) {
            buildAccel();
        }
    }

    void Trimesh::buildAccel() {
        std::vector<Triangle> triangles(_numFaces);
        for (int i = 0; i < _numFaces; i++) {
            Vector3& p0 = _vertices[_faces[i * 3 + 0]];
            Vector3& p1 = _vertices[_faces[i * 3 + 1]];
            Vector3& p2 = _vertices[_faces[i * 3 + 2]];
            triangles[i] = Triangle(p0, p1, p2);
        }

        switch(_accelType) {
        case KD_TREE_ACCEL:
            printf("Accelerator: K-D tree\n");
            _accel = new KdTreeAccel();
            break;
        case QBVH_ACCEL:
            printf("Accelerator: QBVH\n");
            _accel = new QBVHAccel();
            break;
        default:
            msg_assert(false, "Unknown accelerator type!!");
            break;
        }
        _accel->construct(triangles);
    }

    void Trimesh::load(const std::string& filename) {
        release();

        int dotPos = filename.find_last_of(".");
        std::string ext = filename.substr(dotPos);

        if (ext == ".ply") {
            this->loadPly(filename);
        } else if (ext == ".obj") {
            this->loadObj(filename);
        } else {
            msg_assert(ext == ".ply" || ext == ".obj", "Mesh loader only accepts .ply and .obj file format");
        }
    }

    void Trimesh::loadPly(const std::string& filename) {
        std::ifstream in(filename.c_str(), std::ios::in);
        msg_assert(in.is_open(), "Failed to open mesh file");

        std::string format, key, name, val;
        int numVerts = -1;
        int numFaces = -1;

        in >> format;
        msg_assert(format == "ply", "Invalid format identifier");

        bool isBody = false;
        while(!in.eof()) {
            if (!isBody) {
                in >> key;
                if (key == "format" || key == "property") {
                    in >> name >> val;
                    // std::cout << key << " " << name << " " << val << std::endl;
                } else if (key == "element") {
                    in >> name;
                    if (name == "vertex") {
                        in >> numVerts;
                    } else if (name == "face") {
                        in >> numFaces;
                    } else {
                        msg_assert(false, "Invalid element indentifier");
                    }
                } else if (key == "end_header") {
                    isBody = true;
                    continue;
                } else {
                    continue;
                }
            } else {
                std::string line;
                std::stringstream ss;
                double vx, vy, vz;
                int nv, p0, p1, p2;

                msg_assert(numVerts > 0 && numFaces > 0, "numVerts and numFaces must be positive");

                _numVerts = numVerts;
                _numFaces = numFaces;
                _vertices = new Vector3[numVerts];
                _faces = new int[numFaces * 3];
                _normals = new Vector3[numFaces];

                std::getline(in, line);  // skip end_header line

                int cnt = 0;
                for (int i = 0; i < numVerts; i++) {
                    std::getline(in, line);
                    ss.str("");
                    ss.clear(std::stringstream::goodbit);
                    ss << line;
                    ss >> vx >> vy >> vz;
                    _vertices[i] = Vector3(vx, vy, vz);
                }

                for (int i = 0; i < numFaces; i++) {
                    std::getline(in, line);
                    ss.str("");
                    ss.clear(std::stringstream::goodbit);
                    ss << line;
                    ss >> nv >> p0 >> p1 >> p2;
                    _faces[i * 3 + 0] = p0;
                    _faces[i * 3 + 1] = p1;
                    _faces[i * 3 + 2] = p2;

                    _normals[i] = Vector3::cross(_vertices[p1] - _vertices[p0], _vertices[p2] - _vertices[p0]).normalized();
                }
                break;
            }
        }
    }

    void Trimesh::loadObj(const std::string& filename) {
        std::ifstream in(filename.c_str(), std::ios::in);
        msg_assert(in.is_open(), "Failed to open mesh file");

        std::string typ;
        this->_numVerts = 0;
        this->_numFaces = 0;
        std::vector<Vector3> verts;
        std::vector<int> faces;
        while (!in.eof()) {
            in >> typ;
            if (typ == "v") {
                _numVerts++;

                double x, y, z;
                in >> x >> y >> z;
                verts.emplace_back(x, y, z);
            } else if (typ == "f") {
                _numFaces++;

                int v0, v1, v2;
                in >> v0 >> v1 >> v2;
                faces.push_back(v0);
                faces.push_back(v1);
                faces.push_back(v2);
            } else {
                msg_assert(false, "Unknown type is found while reading .obj file!!");
            }
        }

        _vertices = new Vector3[_numVerts];
        _faces    = new int[_numFaces * 3];
        _normals  = new Vector3[_numFaces];
        memcpy(_vertices, &verts[0], sizeof(Vector3) * _numVerts);
        memcpy(_faces, &faces[0], sizeof(int) * _numFaces * 3);
        for (int i = 0; i < _numFaces; i++) {
            int p0 = _faces[i * 3 + 0];
            int p1 = _faces[i * 3 + 1];
            int p2 = _faces[i * 3 + 2];
            _normals[i] = Vector3::cross(_vertices[p1] - _vertices[p0], _vertices[p2] - _vertices[p0]);
        }
    }

    void Trimesh::translate(const Vector3& move) {
        for (int i = 0; i < _numVerts; i++) {
            _vertices[i] += move;
        }
    }

    void Trimesh::scale(const double scaleX, const double scaleY, const double scaleZ) {
        for (int i = 0; i < _numVerts; i++) {
            _vertices[i].setX(_vertices[i].x() * scaleX);
            _vertices[i].setY(_vertices[i].y() * scaleY);
            _vertices[i].setZ(_vertices[i].z() * scaleZ);
        }
    }

    void Trimesh::putOnPlane(const Plane& plane) {
        // Find nearest point
        double minval = INFTY;
        for (int i = 0; i < _numVerts; i++) {
            minval = std::min(minval, Vector3::dot(plane.normal(), _vertices[i]));
        }

        for (int i = 0; i < _numVerts; i++) {
            _vertices[i] -= (minval + plane.distance()) * plane.normal();
        }
    }

    Vector3 Trimesh::getNormal(int id) const {
        msg_assert(id >= 0 && id < _numFaces, "Triangle index out of bounds");
        return _normals[id];
    }

    Triangle Trimesh::getTriangle(int id) const {
        msg_assert(id >= 0 && id < _numFaces, "Triangle index out of bounds");
        const Vector3& p0 = _vertices[_faces[id * 3 + 0]];
        const Vector3& p1 = _vertices[_faces[id * 3 + 1]];
        const Vector3& p2 = _vertices[_faces[id * 3 + 2]];
        return Triangle(p0, p1, p2);
    }

}  // namesapce spica
<commit_msg>Fix function to load .obj file format.<commit_after>#define SPICA_TRIMESH_EXPORT
#include "trimesh.h"

#include <cstdio>
#include <cstring>
#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>

#include "../utils/common.h"

namespace spica {

    Trimesh::Trimesh()
        : _numVerts(0)
        , _numFaces(0)
        , _vertices(NULL)
        , _faces(NULL)
        , _normals(NULL)
        , _accel(NULL)
        , _accelType(QBVH_ACCEL)
    {
    }

    Trimesh::Trimesh(const std::string& filename)
        : _numVerts(0)
        , _numFaces(0)
        , _vertices(NULL)
        , _faces(NULL)
        , _normals(NULL)
        , _accel(NULL)
        , _accelType(QBVH_ACCEL)
    {
        load(filename);
    }

    Trimesh::Trimesh(const Trimesh& trimesh)
        : _numVerts(0)
        , _numFaces(0)
        , _vertices(NULL)
        , _faces(NULL)
        , _normals(NULL)
        , _accel(NULL)
        , _accelType(QBVH_ACCEL)
    {
        operator=(trimesh);
    }

    Trimesh::~Trimesh()
    {
        release();
    }

    void Trimesh::release() {
        delete[] _vertices;
        delete[] _faces;
        delete[] _normals;
        delete   _accel;
        _numVerts = 0;
        _numFaces = 0;
        _vertices = NULL;
        _faces    = NULL;
        _normals  = NULL;
        _accel    = NULL;
    }

    Trimesh& Trimesh::operator=(const Trimesh& trimesh) {
        release();

        _numVerts = trimesh._numVerts;
        _numFaces = trimesh._numFaces;
        _vertices = new Vector3[trimesh._numVerts];
        _faces = new int[trimesh._numFaces * 3];
        _normals = new Vector3[trimesh._numFaces];
        _accel = NULL;
        _accelType = trimesh._accelType;

        memcpy(_vertices, trimesh._vertices, sizeof(Vector3) * _numVerts);
        memcpy(_faces, trimesh._faces, sizeof(int) * (_numFaces * 3));
        memcpy(_normals, trimesh._normals, sizeof(Vector3) * _numFaces);

        buildAccel();

        return *this;
    }

    bool Trimesh::intersect(const Ray& ray, Hitpoint* hitpoint) const {
        msg_assert(_accel != NULL, "Accelerator is not constructed");
        hitpoint->setDistance(INFTY);
        return _accel->intersect(ray, hitpoint);
    }

    double Trimesh::area() const {
        double ret = 0.0;
        for (int i = 0; i < _numFaces; i++) {
            Triangle tri = this->getTriangle(i);
            ret += tri.area();
        }
        return ret;
    }

    void Trimesh::setAccelType(AccelType accelType, bool doBuild) {
        this->_accelType = accelType;
        if (doBuild) {
            buildAccel();
        }
    }

    void Trimesh::buildAccel() {
        std::vector<Triangle> triangles(_numFaces);
        for (int i = 0; i < _numFaces; i++) {
            Vector3& p0 = _vertices[_faces[i * 3 + 0]];
            Vector3& p1 = _vertices[_faces[i * 3 + 1]];
            Vector3& p2 = _vertices[_faces[i * 3 + 2]];
            triangles[i] = Triangle(p0, p1, p2);
        }

        switch(_accelType) {
        case KD_TREE_ACCEL:
            printf("Accelerator: K-D tree\n");
            _accel = new KdTreeAccel();
            break;
        case QBVH_ACCEL:
            printf("Accelerator: QBVH\n");
            _accel = new QBVHAccel();
            break;
        default:
            msg_assert(false, "Unknown accelerator type!!");
            break;
        }
        _accel->construct(triangles);
    }

    void Trimesh::load(const std::string& filename) {
        release();

        int dotPos = filename.find_last_of(".");
        std::string ext = filename.substr(dotPos);

        if (ext == ".ply") {
            this->loadPly(filename);
        } else if (ext == ".obj") {
            this->loadObj(filename);
        } else {
            msg_assert(ext == ".ply" || ext == ".obj", "Mesh loader only accepts .ply and .obj file format");
        }
    }

    void Trimesh::loadPly(const std::string& filename) {
        std::ifstream in(filename.c_str(), std::ios::in);
        msg_assert(in.is_open(), "Failed to open mesh file");

        std::string format, key, name, val;
        int numVerts = -1;
        int numFaces = -1;

        in >> format;
        msg_assert(format == "ply", "Invalid format identifier");

        bool isBody = false;
        while(!in.eof()) {
            if (!isBody) {
                in >> key;
                if (key == "format" || key == "property") {
                    in >> name >> val;
                    // std::cout << key << " " << name << " " << val << std::endl;
                } else if (key == "element") {
                    in >> name;
                    if (name == "vertex") {
                        in >> numVerts;
                    } else if (name == "face") {
                        in >> numFaces;
                    } else {
                        msg_assert(false, "Invalid element indentifier");
                    }
                } else if (key == "end_header") {
                    isBody = true;
                    continue;
                } else {
                    continue;
                }
            } else {
                std::string line;
                std::stringstream ss;
                double vx, vy, vz;
                int nv, p0, p1, p2;

                msg_assert(numVerts > 0 && numFaces > 0, "numVerts and numFaces must be positive");

                _numVerts = numVerts;
                _numFaces = numFaces;
                _vertices = new Vector3[numVerts];
                _faces = new int[numFaces * 3];
                _normals = new Vector3[numFaces];

                std::getline(in, line);  // skip end_header line

                int cnt = 0;
                for (int i = 0; i < numVerts; i++) {
                    std::getline(in, line);
                    ss.str("");
                    ss.clear(std::stringstream::goodbit);
                    ss << line;
                    ss >> vx >> vy >> vz;
                    _vertices[i] = Vector3(vx, vy, vz);
                }

                for (int i = 0; i < numFaces; i++) {
                    std::getline(in, line);
                    ss.str("");
                    ss.clear(std::stringstream::goodbit);
                    ss << line;
                    ss >> nv >> p0 >> p1 >> p2;
                    _faces[i * 3 + 0] = p0 - 1;
                    _faces[i * 3 + 1] = p1 - 1;
                    _faces[i * 3 + 2] = p2 - 1;

                    _normals[i] = Vector3::cross(_vertices[p1] - _vertices[p0], _vertices[p2] - _vertices[p0]).normalized();
                }
                break;
            }
        }
    }

    void Trimesh::loadObj(const std::string& filename) {
        std::ifstream in(filename.c_str(), std::ios::in);
        msg_assert(in.is_open(), "Failed to open mesh file");

        std::string typ;
        this->_numVerts = 0;
        this->_numFaces = 0;
        std::vector<Vector3> verts;
        std::vector<int> faces;
        while (!in.eof()) {
            in >> typ;
            if (typ == "v") {
                _numVerts++;

                double x, y, z;
                in >> x >> y >> z;
                verts.emplace_back(x, y, z);
            } else if (typ == "f") {
                _numFaces++;

                int v0, v1, v2;
                in >> v0 >> v1 >> v2;
                faces.push_back(v0);
                faces.push_back(v1);
                faces.push_back(v2);
            } else {
                msg_assert(false, "Unknown type is found while reading .obj file!!");
            }
        }

        _vertices = new Vector3[_numVerts];
        _faces    = new int[_numFaces * 3];
        _normals  = new Vector3[_numFaces];
        memcpy(_vertices, &verts[0], sizeof(Vector3) * _numVerts);
        memcpy(_faces, &faces[0], sizeof(int) * _numFaces * 3);
        for (int i = 0; i < _numFaces; i++) {
            int p0 = _faces[i * 3 + 0];
            int p1 = _faces[i * 3 + 1];
            int p2 = _faces[i * 3 + 2];
            _normals[i] = Vector3::cross(_vertices[p1] - _vertices[p0], _vertices[p2] - _vertices[p0]);
        }
    }

    void Trimesh::translate(const Vector3& move) {
        for (int i = 0; i < _numVerts; i++) {
            _vertices[i] += move;
        }
    }

    void Trimesh::scale(const double scaleX, const double scaleY, const double scaleZ) {
        for (int i = 0; i < _numVerts; i++) {
            _vertices[i].setX(_vertices[i].x() * scaleX);
            _vertices[i].setY(_vertices[i].y() * scaleY);
            _vertices[i].setZ(_vertices[i].z() * scaleZ);
        }
    }

    void Trimesh::putOnPlane(const Plane& plane) {
        // Find nearest point
        double minval = INFTY;
        for (int i = 0; i < _numVerts; i++) {
            minval = std::min(minval, Vector3::dot(plane.normal(), _vertices[i]));
        }

        for (int i = 0; i < _numVerts; i++) {
            _vertices[i] -= (minval + plane.distance()) * plane.normal();
        }
    }

    Vector3 Trimesh::getNormal(int id) const {
        msg_assert(id >= 0 && id < _numFaces, "Triangle index out of bounds");
        return _normals[id];
    }

    Triangle Trimesh::getTriangle(int id) const {
        msg_assert(id >= 0 && id < _numFaces, "Triangle index out of bounds");
        const Vector3& p0 = _vertices[_faces[id * 3 + 0]];
        const Vector3& p1 = _vertices[_faces[id * 3 + 1]];
        const Vector3& p2 = _vertices[_faces[id * 3 + 2]];
        return Triangle(p0, p1, p2);
    }

}  // namesapce spica
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////

#ifndef BOOST_INTERPROCESS_SHARED_MEMORY_OBJECT_HPP
#define BOOST_INTERPROCESS_SHARED_MEMORY_OBJECT_HPP

#ifndef BOOST_CONFIG_HPP
#  include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
#  pragma once
#endif

#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/move/utility_core.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/detail/shared_dir_helpers.hpp>
#include <boost/interprocess/permissions.hpp>
#include <boost/move/adl_move_swap.hpp>
#include <cstddef>
#include <string>

#if defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS)
#  include <fcntl.h>        //O_CREAT, O_*...
#  include <sys/mman.h>     //shm_xxx
#  include <unistd.h>       //ftruncate, close
#  include <sys/stat.h>     //mode_t, S_IRWXG, S_IRWXO, S_IRWXU,
#  if defined(BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
#     if defined(__FreeBSD__)
#        include <sys/sysctl.h>
#     endif
#  endif
#else
//
#endif

//!\file
//!Describes a shared memory object management class.

namespace boost {
namespace interprocess {

//!A class that wraps a shared memory mapping that can be used to
//!create mapped regions from the mapped files
class shared_memory_object
{
   #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
   //Non-copyable and non-assignable
   BOOST_MOVABLE_BUT_NOT_COPYABLE(shared_memory_object)
   #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED

   public:
   //!Default constructor. Represents an empty shared_memory_object.
   shared_memory_object();

   //!Creates a shared memory object with name "name" and mode "mode", with the access mode "mode"
   //!If the file previously exists, throws an error.*/
   shared_memory_object(create_only_t, const char *name, mode_t mode, const permissions &perm = permissions())
   {  this->priv_open_or_create(ipcdetail::DoCreate, name, mode, perm);  }

   //!Tries to create a shared memory object with name "name" and mode "mode", with the
   //!access mode "mode". If the file previously exists, it tries to open it with mode "mode".
   //!Otherwise throws an error.
   shared_memory_object(open_or_create_t, const char *name, mode_t mode, const permissions &perm = permissions())
   {  this->priv_open_or_create(ipcdetail::DoOpenOrCreate, name, mode, perm);  }

   //!Tries to open a shared memory object with name "name", with the access mode "mode".
   //!If the file does not previously exist, it throws an error.
   shared_memory_object(open_only_t, const char *name, mode_t mode)
   {  this->priv_open_or_create(ipcdetail::DoOpen, name, mode, permissions());  }

   //!Moves the ownership of "moved"'s shared memory object to *this.
   //!After the call, "moved" does not represent any shared memory object.
   //!Does not throw
   shared_memory_object(BOOST_RV_REF(shared_memory_object) moved)
      :  m_handle(file_handle_t(ipcdetail::invalid_file()))
      ,  m_mode(read_only)
   {  this->swap(moved);   }

   //!Moves the ownership of "moved"'s shared memory to *this.
   //!After the call, "moved" does not represent any shared memory.
   //!Does not throw
   shared_memory_object &operator=(BOOST_RV_REF(shared_memory_object) moved)
   {
      shared_memory_object tmp(boost::move(moved));
      this->swap(tmp);
      return *this;
   }

   //!Swaps the shared_memory_objects. Does not throw
   void swap(shared_memory_object &moved);

   //!Erases a shared memory object from the system.
   //!Returns false on error. Never throws
   static bool remove(const char *name);

   //!Sets the size of the shared memory mapping
   void truncate(offset_t length);

   //!Destroys *this and indicates that the calling process is finished using
   //!the resource. All mapped regions are still
   //!valid after destruction. The destructor function will deallocate
   //!any system resources allocated by the system for use by this process for
   //!this resource. The resource can still be opened again calling
   //!the open constructor overload. To erase the resource from the system
   //!use remove().
   ~shared_memory_object();

   //!Returns the name of the shared memory object.
   const char *get_name() const;

   //!Returns true if the size of the shared memory object
   //!can be obtained and writes the size in the passed reference
   bool get_size(offset_t &size) const;

   //!Returns access mode
   mode_t get_mode() const;

   //!Returns mapping handle. Never throws.
   mapping_handle_t get_mapping_handle() const;

   #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
   private:

   //!Closes a previously opened file mapping. Never throws.
   void priv_close();

   //!Opens or creates a shared memory object.
   bool priv_open_or_create(ipcdetail::create_enum_t type, const char *filename, mode_t mode, const permissions &perm);

   file_handle_t  m_handle;
   mode_t         m_mode;
   std::string    m_filename;
   #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};

#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)

inline shared_memory_object::shared_memory_object()
   :  m_handle(file_handle_t(ipcdetail::invalid_file()))
   ,  m_mode(read_only)
{}

inline shared_memory_object::~shared_memory_object()
{  this->priv_close(); }

inline const char *shared_memory_object::get_name() const
{  return m_filename.c_str(); }

inline bool shared_memory_object::get_size(offset_t &size) const
{  return ipcdetail::get_file_size((file_handle_t)m_handle, size);  }

inline void shared_memory_object::swap(shared_memory_object &other)
{
   boost::adl_move_swap(m_handle, other.m_handle);
   boost::adl_move_swap(m_mode,   other.m_mode);
   m_filename.swap(other.m_filename);
}

inline mapping_handle_t shared_memory_object::get_mapping_handle() const
{
   return ipcdetail::mapping_handle_from_file_handle(m_handle);
}

inline mode_t shared_memory_object::get_mode() const
{  return m_mode; }

#if !defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS)

inline bool shared_memory_object::priv_open_or_create
   (ipcdetail::create_enum_t type, const char *filename, mode_t mode, const permissions &perm)
{
   m_filename = filename;
   std::string shmfile;
   ipcdetail::create_shared_dir_cleaning_old_and_get_filepath(filename, shmfile);

   //Set accesses
   if (mode != read_write && mode != read_only){
      error_info err = other_error;
      throw interprocess_exception(err);
   }

   switch(type){
      case ipcdetail::DoOpen:
         m_handle = ipcdetail::open_existing_file(shmfile.c_str(), mode, true);
      break;
      case ipcdetail::DoCreate:
         m_handle = ipcdetail::create_new_file(shmfile.c_str(), mode, perm, true);
      break;
      case ipcdetail::DoOpenOrCreate:
         m_handle = ipcdetail::create_or_open_file(shmfile.c_str(), mode, perm, true);
      break;
      default:
         {
            error_info err = other_error;
            throw interprocess_exception(err);
         }
   }

   //Check for error
   if(m_handle == ipcdetail::invalid_file()){
      error_info err = system_error_code();
      this->priv_close();
      throw interprocess_exception(err);
   }

   m_mode = mode;
   return true;
}

inline bool shared_memory_object::remove(const char *filename)
{
   try{
      //Make sure a temporary path is created for shared memory
      std::string shmfile;
      ipcdetail::shared_filepath(filename, shmfile);
      return ipcdetail::delete_file(shmfile.c_str());
   }
   catch(...){
      return false;
   }
}

inline void shared_memory_object::truncate(offset_t length)
{
   if(!ipcdetail::truncate_file(m_handle, length)){
      error_info err = system_error_code();
      throw interprocess_exception(err);
   }
}

inline void shared_memory_object::priv_close()
{
   if(m_handle != ipcdetail::invalid_file()){
      ipcdetail::close_file(m_handle);
      m_handle = ipcdetail::invalid_file();
   }
}

#else //!defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS)

namespace shared_memory_object_detail {

#ifdef BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY

#if defined(__FreeBSD__)

inline bool use_filesystem_based_posix()
{
   int jailed = 0;
   std::size_t len = sizeof(jailed);
   ::sysctlbyname("security.jail.jailed", &jailed, &len, NULL, 0);
   return jailed != 0;
}

#else
#error "Not supported platform for BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY"
#endif

#endif

}  //shared_memory_object_detail

inline bool shared_memory_object::priv_open_or_create
   (ipcdetail::create_enum_t type,
    const char *filename,
    mode_t mode, const permissions &perm)
{
   #if defined(BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
   const bool add_leading_slash = false;
   #elif defined(BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
   const bool add_leading_slash = !shared_memory_object_detail::use_filesystem_based_posix();
   #else
   const bool add_leading_slash = true;
   #endif
   if(add_leading_slash){
      ipcdetail::add_leading_slash(filename, m_filename);
   }
   else{
      ipcdetail::create_shared_dir_cleaning_old_and_get_filepath(filename, m_filename);
   }

   //Create new mapping
   int oflag = 0;
   if(mode == read_only){
      oflag |= O_RDONLY;
   }
   else if(mode == read_write){
      oflag |= O_RDWR;
   }
   else{
      error_info err(mode_error);
      throw interprocess_exception(err);
   }
   int unix_perm = perm.get_permissions();

   switch(type){
      case ipcdetail::DoOpen:
      {
         //No oflag addition
         m_handle = shm_open(m_filename.c_str(), oflag, unix_perm);
      }
      break;
      case ipcdetail::DoCreate:
      {
         oflag |= (O_CREAT | O_EXCL);
         m_handle = shm_open(m_filename.c_str(), oflag, unix_perm);
         if(m_handle >= 0){
            ::fchmod(m_handle, unix_perm);
         }
      }
      break;
      case ipcdetail::DoOpenOrCreate:
      {
         //We need a create/open loop to change permissions correctly using fchmod, since
         //with "O_CREAT" only we don't know if we've created or opened the shm.
         while(1){
            //Try to create shared memory
            m_handle = shm_open(m_filename.c_str(), oflag | (O_CREAT | O_EXCL), unix_perm);
            //If successful change real permissions
            if(m_handle >= 0){
               ::fchmod(m_handle, unix_perm);
            }
            //If already exists, try to open
            else if(errno == EEXIST){
               m_handle = shm_open(m_filename.c_str(), oflag, unix_perm);
               //If open fails and errno tells the file does not exist
               //(shm was removed between creation and opening tries), just retry
               if(m_handle < 0 && errno == ENOENT){
                  continue;
               }
            }
            //Exit retries
            break;
         }
      }
      break;
      default:
      {
         error_info err = other_error;
         throw interprocess_exception(err);
      }
   }

   //Check for error
   if(m_handle < 0){
      error_info err = errno;
      this->priv_close();
      throw interprocess_exception(err);
   }

   m_filename = filename;
   m_mode = mode;
   return true;
}

inline bool shared_memory_object::remove(const char *filename)
{
   try{
      std::string filepath;
      #if defined(BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
      const bool add_leading_slash = false;
      #elif defined(BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
      const bool add_leading_slash = !shared_memory_object_detail::use_filesystem_based_posix();
      #else
      const bool add_leading_slash = true;
      #endif
      if(add_leading_slash){
         ipcdetail::add_leading_slash(filename, filepath);
      }
      else{
         ipcdetail::shared_filepath(filename, filepath);
      }
      return 0 == shm_unlink(filepath.c_str());
   }
   catch(...){
      return false;
   }
}

inline void shared_memory_object::truncate(offset_t length)
{
#ifdef BOOST_FASTDDS_PATCHES

   if (0 != fallocate(m_handle, 0, 0, length))
   {
       error_info err(system_error_code());
       throw interprocess_exception(err);
   }

#else // Original BOOST code

   if(0 != ftruncate(m_handle, length)){
      error_info err(system_error_code());
      throw interprocess_exception(err);
   }

#endif
}

inline void shared_memory_object::priv_close()
{
   if(m_handle != -1){
      ::close(m_handle);
      m_handle = -1;
   }
}

#endif

//!A class that stores the name of a shared memory
//!and calls shared_memory_object::remove(name) in its destructor
//!Useful to remove temporary shared memory objects in the presence
//!of exceptions
class remove_shared_memory_on_destroy
{
   const char * m_name;
   public:
   remove_shared_memory_on_destroy(const char *name)
      :  m_name(name)
   {}

   ~remove_shared_memory_on_destroy()
   {  shared_memory_object::remove(m_name);  }
};

#endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED

}  //namespace interprocess {
}  //namespace boost {

#include <boost/interprocess/detail/config_end.hpp>

#endif   //BOOST_INTERPROCESS_SHARED_MEMORY_OBJECT_HPP
<commit_msg>Use posix_fallocate. (#1465)<commit_after>//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////

#ifndef BOOST_INTERPROCESS_SHARED_MEMORY_OBJECT_HPP
#define BOOST_INTERPROCESS_SHARED_MEMORY_OBJECT_HPP

#ifndef BOOST_CONFIG_HPP
#  include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
#  pragma once
#endif

#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/move/utility_core.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/detail/shared_dir_helpers.hpp>
#include <boost/interprocess/permissions.hpp>
#include <boost/move/adl_move_swap.hpp>
#include <cstddef>
#include <string>

#if defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS)
#  include <fcntl.h>        //O_CREAT, O_*...
#  include <sys/mman.h>     //shm_xxx
#  include <unistd.h>       //ftruncate, close
#  include <sys/stat.h>     //mode_t, S_IRWXG, S_IRWXO, S_IRWXU,
#  if defined(BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
#     if defined(__FreeBSD__)
#        include <sys/sysctl.h>
#     endif
#  endif
#else
//
#endif

//!\file
//!Describes a shared memory object management class.

namespace boost {
namespace interprocess {

//!A class that wraps a shared memory mapping that can be used to
//!create mapped regions from the mapped files
class shared_memory_object
{
   #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
   //Non-copyable and non-assignable
   BOOST_MOVABLE_BUT_NOT_COPYABLE(shared_memory_object)
   #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED

   public:
   //!Default constructor. Represents an empty shared_memory_object.
   shared_memory_object();

   //!Creates a shared memory object with name "name" and mode "mode", with the access mode "mode"
   //!If the file previously exists, throws an error.*/
   shared_memory_object(create_only_t, const char *name, mode_t mode, const permissions &perm = permissions())
   {  this->priv_open_or_create(ipcdetail::DoCreate, name, mode, perm);  }

   //!Tries to create a shared memory object with name "name" and mode "mode", with the
   //!access mode "mode". If the file previously exists, it tries to open it with mode "mode".
   //!Otherwise throws an error.
   shared_memory_object(open_or_create_t, const char *name, mode_t mode, const permissions &perm = permissions())
   {  this->priv_open_or_create(ipcdetail::DoOpenOrCreate, name, mode, perm);  }

   //!Tries to open a shared memory object with name "name", with the access mode "mode".
   //!If the file does not previously exist, it throws an error.
   shared_memory_object(open_only_t, const char *name, mode_t mode)
   {  this->priv_open_or_create(ipcdetail::DoOpen, name, mode, permissions());  }

   //!Moves the ownership of "moved"'s shared memory object to *this.
   //!After the call, "moved" does not represent any shared memory object.
   //!Does not throw
   shared_memory_object(BOOST_RV_REF(shared_memory_object) moved)
      :  m_handle(file_handle_t(ipcdetail::invalid_file()))
      ,  m_mode(read_only)
   {  this->swap(moved);   }

   //!Moves the ownership of "moved"'s shared memory to *this.
   //!After the call, "moved" does not represent any shared memory.
   //!Does not throw
   shared_memory_object &operator=(BOOST_RV_REF(shared_memory_object) moved)
   {
      shared_memory_object tmp(boost::move(moved));
      this->swap(tmp);
      return *this;
   }

   //!Swaps the shared_memory_objects. Does not throw
   void swap(shared_memory_object &moved);

   //!Erases a shared memory object from the system.
   //!Returns false on error. Never throws
   static bool remove(const char *name);

   //!Sets the size of the shared memory mapping
   void truncate(offset_t length);

   //!Destroys *this and indicates that the calling process is finished using
   //!the resource. All mapped regions are still
   //!valid after destruction. The destructor function will deallocate
   //!any system resources allocated by the system for use by this process for
   //!this resource. The resource can still be opened again calling
   //!the open constructor overload. To erase the resource from the system
   //!use remove().
   ~shared_memory_object();

   //!Returns the name of the shared memory object.
   const char *get_name() const;

   //!Returns true if the size of the shared memory object
   //!can be obtained and writes the size in the passed reference
   bool get_size(offset_t &size) const;

   //!Returns access mode
   mode_t get_mode() const;

   //!Returns mapping handle. Never throws.
   mapping_handle_t get_mapping_handle() const;

   #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
   private:

   //!Closes a previously opened file mapping. Never throws.
   void priv_close();

   //!Opens or creates a shared memory object.
   bool priv_open_or_create(ipcdetail::create_enum_t type, const char *filename, mode_t mode, const permissions &perm);

   file_handle_t  m_handle;
   mode_t         m_mode;
   std::string    m_filename;
   #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};

#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)

inline shared_memory_object::shared_memory_object()
   :  m_handle(file_handle_t(ipcdetail::invalid_file()))
   ,  m_mode(read_only)
{}

inline shared_memory_object::~shared_memory_object()
{  this->priv_close(); }

inline const char *shared_memory_object::get_name() const
{  return m_filename.c_str(); }

inline bool shared_memory_object::get_size(offset_t &size) const
{  return ipcdetail::get_file_size((file_handle_t)m_handle, size);  }

inline void shared_memory_object::swap(shared_memory_object &other)
{
   boost::adl_move_swap(m_handle, other.m_handle);
   boost::adl_move_swap(m_mode,   other.m_mode);
   m_filename.swap(other.m_filename);
}

inline mapping_handle_t shared_memory_object::get_mapping_handle() const
{
   return ipcdetail::mapping_handle_from_file_handle(m_handle);
}

inline mode_t shared_memory_object::get_mode() const
{  return m_mode; }

#if !defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS)

inline bool shared_memory_object::priv_open_or_create
   (ipcdetail::create_enum_t type, const char *filename, mode_t mode, const permissions &perm)
{
   m_filename = filename;
   std::string shmfile;
   ipcdetail::create_shared_dir_cleaning_old_and_get_filepath(filename, shmfile);

   //Set accesses
   if (mode != read_write && mode != read_only){
      error_info err = other_error;
      throw interprocess_exception(err);
   }

   switch(type){
      case ipcdetail::DoOpen:
         m_handle = ipcdetail::open_existing_file(shmfile.c_str(), mode, true);
      break;
      case ipcdetail::DoCreate:
         m_handle = ipcdetail::create_new_file(shmfile.c_str(), mode, perm, true);
      break;
      case ipcdetail::DoOpenOrCreate:
         m_handle = ipcdetail::create_or_open_file(shmfile.c_str(), mode, perm, true);
      break;
      default:
         {
            error_info err = other_error;
            throw interprocess_exception(err);
         }
   }

   //Check for error
   if(m_handle == ipcdetail::invalid_file()){
      error_info err = system_error_code();
      this->priv_close();
      throw interprocess_exception(err);
   }

   m_mode = mode;
   return true;
}

inline bool shared_memory_object::remove(const char *filename)
{
   try{
      //Make sure a temporary path is created for shared memory
      std::string shmfile;
      ipcdetail::shared_filepath(filename, shmfile);
      return ipcdetail::delete_file(shmfile.c_str());
   }
   catch(...){
      return false;
   }
}

inline void shared_memory_object::truncate(offset_t length)
{
   if(!ipcdetail::truncate_file(m_handle, length)){
      error_info err = system_error_code();
      throw interprocess_exception(err);
   }
}

inline void shared_memory_object::priv_close()
{
   if(m_handle != ipcdetail::invalid_file()){
      ipcdetail::close_file(m_handle);
      m_handle = ipcdetail::invalid_file();
   }
}

#else //!defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS)

namespace shared_memory_object_detail {

#ifdef BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY

#if defined(__FreeBSD__)

inline bool use_filesystem_based_posix()
{
   int jailed = 0;
   std::size_t len = sizeof(jailed);
   ::sysctlbyname("security.jail.jailed", &jailed, &len, NULL, 0);
   return jailed != 0;
}

#else
#error "Not supported platform for BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY"
#endif

#endif

}  //shared_memory_object_detail

inline bool shared_memory_object::priv_open_or_create
   (ipcdetail::create_enum_t type,
    const char *filename,
    mode_t mode, const permissions &perm)
{
   #if defined(BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
   const bool add_leading_slash = false;
   #elif defined(BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
   const bool add_leading_slash = !shared_memory_object_detail::use_filesystem_based_posix();
   #else
   const bool add_leading_slash = true;
   #endif
   if(add_leading_slash){
      ipcdetail::add_leading_slash(filename, m_filename);
   }
   else{
      ipcdetail::create_shared_dir_cleaning_old_and_get_filepath(filename, m_filename);
   }

   //Create new mapping
   int oflag = 0;
   if(mode == read_only){
      oflag |= O_RDONLY;
   }
   else if(mode == read_write){
      oflag |= O_RDWR;
   }
   else{
      error_info err(mode_error);
      throw interprocess_exception(err);
   }
   int unix_perm = perm.get_permissions();

   switch(type){
      case ipcdetail::DoOpen:
      {
         //No oflag addition
         m_handle = shm_open(m_filename.c_str(), oflag, unix_perm);
      }
      break;
      case ipcdetail::DoCreate:
      {
         oflag |= (O_CREAT | O_EXCL);
         m_handle = shm_open(m_filename.c_str(), oflag, unix_perm);
         if(m_handle >= 0){
            ::fchmod(m_handle, unix_perm);
         }
      }
      break;
      case ipcdetail::DoOpenOrCreate:
      {
         //We need a create/open loop to change permissions correctly using fchmod, since
         //with "O_CREAT" only we don't know if we've created or opened the shm.
         while(1){
            //Try to create shared memory
            m_handle = shm_open(m_filename.c_str(), oflag | (O_CREAT | O_EXCL), unix_perm);
            //If successful change real permissions
            if(m_handle >= 0){
               ::fchmod(m_handle, unix_perm);
            }
            //If already exists, try to open
            else if(errno == EEXIST){
               m_handle = shm_open(m_filename.c_str(), oflag, unix_perm);
               //If open fails and errno tells the file does not exist
               //(shm was removed between creation and opening tries), just retry
               if(m_handle < 0 && errno == ENOENT){
                  continue;
               }
            }
            //Exit retries
            break;
         }
      }
      break;
      default:
      {
         error_info err = other_error;
         throw interprocess_exception(err);
      }
   }

   //Check for error
   if(m_handle < 0){
      error_info err = errno;
      this->priv_close();
      throw interprocess_exception(err);
   }

   m_filename = filename;
   m_mode = mode;
   return true;
}

inline bool shared_memory_object::remove(const char *filename)
{
   try{
      std::string filepath;
      #if defined(BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
      const bool add_leading_slash = false;
      #elif defined(BOOST_INTERPROCESS_RUNTIME_FILESYSTEM_BASED_POSIX_SHARED_MEMORY)
      const bool add_leading_slash = !shared_memory_object_detail::use_filesystem_based_posix();
      #else
      const bool add_leading_slash = true;
      #endif
      if(add_leading_slash){
         ipcdetail::add_leading_slash(filename, filepath);
      }
      else{
         ipcdetail::shared_filepath(filename, filepath);
      }
      return 0 == shm_unlink(filepath.c_str());
   }
   catch(...){
      return false;
   }
}

inline void shared_memory_object::truncate(offset_t length)
{
#ifdef BOOST_FASTDDS_PATCHES

   if (0 != posix_fallocate(m_handle, 0, length))
   {
       error_info err(system_error_code());
       throw interprocess_exception(err);
   }

#else // Original BOOST code

   if(0 != ftruncate(m_handle, length)){
      error_info err(system_error_code());
      throw interprocess_exception(err);
   }

#endif
}

inline void shared_memory_object::priv_close()
{
   if(m_handle != -1){
      ::close(m_handle);
      m_handle = -1;
   }
}

#endif

//!A class that stores the name of a shared memory
//!and calls shared_memory_object::remove(name) in its destructor
//!Useful to remove temporary shared memory objects in the presence
//!of exceptions
class remove_shared_memory_on_destroy
{
   const char * m_name;
   public:
   remove_shared_memory_on_destroy(const char *name)
      :  m_name(name)
   {}

   ~remove_shared_memory_on_destroy()
   {  shared_memory_object::remove(m_name);  }
};

#endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED

}  //namespace interprocess {
}  //namespace boost {

#include <boost/interprocess/detail/config_end.hpp>

#endif   //BOOST_INTERPROCESS_SHARED_MEMORY_OBJECT_HPP
<|endoftext|>


<commit_before>//===-- sanitizer_stacktrace_libcdep.cc -----------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is shared between AddressSanitizer and ThreadSanitizer
// run-time libraries.
//===----------------------------------------------------------------------===//

#include "sanitizer_common.h"
#include "sanitizer_placement_new.h"
#include "sanitizer_stacktrace.h"
#include "sanitizer_stacktrace_printer.h"
#include "sanitizer_symbolizer.h"

namespace __sanitizer {

void StackTrace::Print() const {
  if (trace == nullptr || size == 0) {
    Printf("    <empty stack>\n\n");
    return;
  }
  InternalScopedString frame_desc(GetPageSizeCached() * 2);
  InternalScopedString dedup_token(GetPageSizeCached());
  int dedup_frames = common_flags()->dedup_token_length;
  uptr frame_num = 0;
  for (uptr i = 0; i < size && trace[i]; i++) {
    // PCs in stack traces are actually the return addresses, that is,
    // addresses of the next instructions after the call.
    uptr pc = GetPreviousInstructionPc(trace[i]);
    SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(pc);
    CHECK(frames);
    for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
      frame_desc.clear();
      RenderFrame(&frame_desc, common_flags()->stack_trace_format, frame_num++,
                  cur->info, common_flags()->symbolize_vs_style,
                  common_flags()->strip_path_prefix);
      Printf("%s\n", frame_desc.data());
      if (dedup_frames-- > 0) {
        if (dedup_token.length())
          dedup_token.append("--");
        dedup_token.append(cur->info.function);
      }
    }
    frames->ClearAll();
  }
  // Always print a trailing empty line after stack trace.
  Printf("\n");
  if (dedup_token.length())
    Printf("DEDUP_TOKEN: %s\n", dedup_token.data());
}

void BufferedStackTrace::Unwind(u32 max_depth, uptr pc, uptr bp, void *context,
                                uptr stack_top, uptr stack_bottom,
                                bool request_fast_unwind) {
  top_frame_bp = (max_depth > 0) ? bp : 0;
  // Avoid doing any work for small max_depth.
  if (max_depth == 0) {
    size = 0;
    return;
  }
  if (max_depth == 1) {
    size = 1;
    trace_buffer[0] = pc;
    return;
  }
  if (!WillUseFastUnwind(request_fast_unwind)) {
#if SANITIZER_CAN_SLOW_UNWIND
    if (context)
      SlowUnwindStackWithContext(pc, context, max_depth);
    else
      SlowUnwindStack(pc, max_depth);
#else
    UNREACHABLE("slow unwind requested but not available");
#endif
  } else {
    FastUnwindStack(pc, bp, stack_top, stack_bottom, max_depth);
  }
}

static int GetModuleAndOffsetForPc(uptr pc, char *module_name,
                                   uptr module_name_len, uptr *pc_offset) {
  const char *found_module_name = nullptr;
  bool ok = Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC(
      pc, &found_module_name, pc_offset);

  if (!ok) return false;

  if (module_name && module_name_len) {
    internal_strncpy(module_name, found_module_name, module_name_len);
    module_name[module_name_len - 1] = '\x00';
  }
  return true;
}

}  // namespace __sanitizer
using namespace __sanitizer;

extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf,
                              uptr out_buf_size) {
  if (!out_buf_size) return;
  pc = StackTrace::GetPreviousInstructionPc(pc);
  SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc);
  if (!frame) {
    internal_strncpy(out_buf, "<can't symbolize>", out_buf_size);
    out_buf[out_buf_size - 1] = 0;
    return;
  }
  InternalScopedString frame_desc(GetPageSizeCached());
  RenderFrame(&frame_desc, fmt, 0, frame->info,
              common_flags()->symbolize_vs_style,
              common_flags()->strip_path_prefix);
  internal_strncpy(out_buf, frame_desc.data(), out_buf_size);
  out_buf[out_buf_size - 1] = 0;
}

SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_symbolize_global(uptr data_addr, const char *fmt,
                                  char *out_buf, uptr out_buf_size) {
  if (!out_buf_size) return;
  out_buf[0] = 0;
  DataInfo DI;
  if (!Symbolizer::GetOrInit()->SymbolizeData(data_addr, &DI)) return;
  InternalScopedString data_desc(GetPageSizeCached());
  RenderData(&data_desc, fmt, &DI, common_flags()->strip_path_prefix);
  internal_strncpy(out_buf, data_desc.data(), out_buf_size);
  out_buf[out_buf_size - 1] = 0;
}

SANITIZER_INTERFACE_ATTRIBUTE
int __sanitizer_get_module_and_offset_for_pc( // NOLINT
    uptr pc, char *module_name, uptr module_name_len, uptr *pc_offset) {
  return __sanitizer::GetModuleAndOffsetForPc(pc, module_name, module_name_len,
                                              pc_offset);
}
}  // extern "C"
<commit_msg>Do not crash with missing symbolication when running in DEDUP mode<commit_after>//===-- sanitizer_stacktrace_libcdep.cc -----------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is shared between AddressSanitizer and ThreadSanitizer
// run-time libraries.
//===----------------------------------------------------------------------===//

#include "sanitizer_common.h"
#include "sanitizer_placement_new.h"
#include "sanitizer_stacktrace.h"
#include "sanitizer_stacktrace_printer.h"
#include "sanitizer_symbolizer.h"

namespace __sanitizer {

void StackTrace::Print() const {
  if (trace == nullptr || size == 0) {
    Printf("    <empty stack>\n\n");
    return;
  }
  InternalScopedString frame_desc(GetPageSizeCached() * 2);
  InternalScopedString dedup_token(GetPageSizeCached());
  int dedup_frames = common_flags()->dedup_token_length;
  uptr frame_num = 0;
  for (uptr i = 0; i < size && trace[i]; i++) {
    // PCs in stack traces are actually the return addresses, that is,
    // addresses of the next instructions after the call.
    uptr pc = GetPreviousInstructionPc(trace[i]);
    SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(pc);
    CHECK(frames);
    for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
      frame_desc.clear();
      RenderFrame(&frame_desc, common_flags()->stack_trace_format, frame_num++,
                  cur->info, common_flags()->symbolize_vs_style,
                  common_flags()->strip_path_prefix);
      Printf("%s\n", frame_desc.data());
      if (dedup_frames-- > 0) {
        if (dedup_token.length())
          dedup_token.append("--");
        if (cur->info.function != nullptr)
          dedup_token.append(cur->info.function);
      }
    }
    frames->ClearAll();
  }
  // Always print a trailing empty line after stack trace.
  Printf("\n");
  if (dedup_token.length())
    Printf("DEDUP_TOKEN: %s\n", dedup_token.data());
}

void BufferedStackTrace::Unwind(u32 max_depth, uptr pc, uptr bp, void *context,
                                uptr stack_top, uptr stack_bottom,
                                bool request_fast_unwind) {
  top_frame_bp = (max_depth > 0) ? bp : 0;
  // Avoid doing any work for small max_depth.
  if (max_depth == 0) {
    size = 0;
    return;
  }
  if (max_depth == 1) {
    size = 1;
    trace_buffer[0] = pc;
    return;
  }
  if (!WillUseFastUnwind(request_fast_unwind)) {
#if SANITIZER_CAN_SLOW_UNWIND
    if (context)
      SlowUnwindStackWithContext(pc, context, max_depth);
    else
      SlowUnwindStack(pc, max_depth);
#else
    UNREACHABLE("slow unwind requested but not available");
#endif
  } else {
    FastUnwindStack(pc, bp, stack_top, stack_bottom, max_depth);
  }
}

static int GetModuleAndOffsetForPc(uptr pc, char *module_name,
                                   uptr module_name_len, uptr *pc_offset) {
  const char *found_module_name = nullptr;
  bool ok = Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC(
      pc, &found_module_name, pc_offset);

  if (!ok) return false;

  if (module_name && module_name_len) {
    internal_strncpy(module_name, found_module_name, module_name_len);
    module_name[module_name_len - 1] = '\x00';
  }
  return true;
}

}  // namespace __sanitizer
using namespace __sanitizer;

extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf,
                              uptr out_buf_size) {
  if (!out_buf_size) return;
  pc = StackTrace::GetPreviousInstructionPc(pc);
  SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc);
  if (!frame) {
    internal_strncpy(out_buf, "<can't symbolize>", out_buf_size);
    out_buf[out_buf_size - 1] = 0;
    return;
  }
  InternalScopedString frame_desc(GetPageSizeCached());
  RenderFrame(&frame_desc, fmt, 0, frame->info,
              common_flags()->symbolize_vs_style,
              common_flags()->strip_path_prefix);
  internal_strncpy(out_buf, frame_desc.data(), out_buf_size);
  out_buf[out_buf_size - 1] = 0;
}

SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_symbolize_global(uptr data_addr, const char *fmt,
                                  char *out_buf, uptr out_buf_size) {
  if (!out_buf_size) return;
  out_buf[0] = 0;
  DataInfo DI;
  if (!Symbolizer::GetOrInit()->SymbolizeData(data_addr, &DI)) return;
  InternalScopedString data_desc(GetPageSizeCached());
  RenderData(&data_desc, fmt, &DI, common_flags()->strip_path_prefix);
  internal_strncpy(out_buf, data_desc.data(), out_buf_size);
  out_buf[out_buf_size - 1] = 0;
}

SANITIZER_INTERFACE_ATTRIBUTE
int __sanitizer_get_module_and_offset_for_pc( // NOLINT
    uptr pc, char *module_name, uptr module_name_len, uptr *pc_offset) {
  return __sanitizer::GetModuleAndOffsetForPc(pc, module_name, module_name_len,
                                              pc_offset);
}
}  // extern "C"
<|endoftext|>


<commit_before><commit_msg>BUG: Now handles any number of datasets.<commit_after><|endoftext|>


<commit_before>#include <array>
#include <string>
#include <iostream>
#include <vector>
#include <memory>
#include <map>
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <SDL/SDL_mixer.h>
#include <SDL/SDL_ttf.h>
#include "Vipper/Vipper.h"
#include "CSDLRenderer.h"

namespace RunTheWorld {

    Vipper::IRenderer::BitmapId CSDLRenderer::loadBitmap( std::string path ) {
      auto id = mSprites.size() + 1;
      mSprites[ id ] = IMG_Load( path.c_str() );
      return id;
    }

    Vipper::IRenderer::SoundId CSDLRenderer::loadSound( std::string path ) {
      auto id = mSounds.size() + 1;
      mSounds[ id ] = Mix_LoadWAV(path.c_str() );
      return id;
    }

    Vipper::IRenderer::FontId CSDLRenderer::loadFont( std::string path, int sizeInPt ) {
      auto id = mFonts.size() + 1;
      mFonts[ id ] = TTF_OpenFont(path.c_str(), sizeInPt );

      return id;
    }

    void CSDLRenderer::fill(float x0, float x1, float y0, float x2, float x3, float y1, int shade[3]) {
        float fromY = std::min( y0, y1 );
        float toY = std::max( y0, y1 );
        SDL_Rect rect;
        float deltaY = toY - fromY;

        float ratiox0x2 = 1.0f;
        float ratiox1x3 = 1.0f;

        if ( toY - fromY > 0.0f  ) {
            ratiox0x2 = ( x0 - x2 ) / deltaY;
            ratiox1x3 = ( x1 - x3 ) / deltaY;
        }

        float x = x0;
        float fx = x1;

        for ( int line = toY; line >= fromY; line--) {

            rect.x = x;
            rect.y = line;
            rect.w = ( fx - x);
            rect.h = 1;

            x -= ratiox0x2;
            fx -= ratiox1x3;

            SDL_FillRect(video, &rect, SDL_MapRGB(video->format, shade[0], shade[1],  shade[2] ));
        }
    }

    void CSDLRenderer::drawSquare( int x, int y, int x2, int y2, std::array<int,4> colour ) {
      SDL_Rect rect;
      rect.x = x;
      rect.y = y;
      rect.w = ( x2 - x );
      rect.h = ( y2 - y );
      int colourMerged = SDL_MapRGBA( video->format, colour[ 0 ], colour[ 1 ], colour[ 2 ], colour[ 3 ] );
      SDL_FillRect( video, &rect, colourMerged );
    };

    void CSDLRenderer::drawTextAt( int x, int y, std::string text, std::array<int, 4> colour, Vipper::IRenderer::FontId id ) {
      if ( id == 0 ) {
        return;
      }

      SDL_Color color = { (Uint8)colour[ 0 ], (Uint8)colour[ 1 ], (Uint8)colour[ 2 ], (Uint8)colour[ 3 ] };
      auto font = mFonts[ id ];
      auto result = TTF_RenderText_Solid( font, text.c_str(), color );
      SDL_Rect rect;
      rect.x = x;
      rect.y = y;
      rect.w = result->w;
      rect.h = result->h;
      SDL_BlitSurface( result, nullptr, video, &rect );
      SDL_FreeSurface( result );
    };

    void CSDLRenderer::drawBitmapAt( int x, int y, int w, int h, const IRenderer::BitmapId id ) {

      if ( id == 0 ) {
        return;
      }

      auto bitmap = mSprites[ id ];
      SDL_Rect rect;
      rect.x = x;
      rect.y = y;
      rect.w = w;
      rect.h = h;
      SDL_BlitSurface( bitmap, nullptr, video, &rect );
    };

    void CSDLRenderer::playSound( const IRenderer::SoundId& id ) {
      if ( id == 0 ) {
        return;
      }

      auto sound = mSounds[ id ];

      Mix_PlayChannel( -1, sound, 0 );
    };

  CSDLRenderer::CSDLRenderer() {

    //REFACTOR!
    SDL_Init(  SDL_INIT_EVERYTHING );
    TTF_Init();
    video = SDL_SetVideoMode( 640, 480, 32, 0 );

    if ( Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024) == -1 ) {
      std::cout << "coudlnt init mixer" << std::endl;
    }
  }

  void CSDLRenderer::shutdown() {
    SDL_Quit();
  }

  void CSDLRenderer::update() {
    SDL_Event event;

    if ( SDL_PollEvent( &event ) ) {

      if( event.type == SDL_QUIT ) {
        exit(0);
      }

      if ( event.type == SDL_MOUSEBUTTONDOWN ) {
        dispatchClickToListeners( std::pair<int, int>( event.button.x, event.button.y ) );
      }

        if (event.type == SDL_KEYUP) {
            switch (event.key.keysym.sym) {
                case SDLK_q:
#ifndef __EMSCRIPTEN__
                    exit(0);
#endif
                case SDLK_LEFT:
                    dispatchKeyUpToListeners(Vipper::ECommand::kLeft);
                    break;

                case SDLK_RIGHT:
                    dispatchKeyUpToListeners(Vipper::ECommand::kRight);
                    break;

                case SDLK_UP:
                    dispatchKeyUpToListeners(Vipper::ECommand::kUp);
                    break;

                case SDLK_DOWN:
                    dispatchKeyUpToListeners(Vipper::ECommand::kDown);
                    break;
                case SDLK_SPACE:
                    dispatchKeyUpToListeners(Vipper::ECommand::kFire1);
                    break;
                default:
                    break;
            }
        }

        if (event.type == SDL_KEYDOWN) {
            switch (event.key.keysym.sym) {
                case SDLK_LEFT:
                    dispatchKeyDownToListeners(Vipper::ECommand::kLeft);
                    break;
                case SDLK_RIGHT:
                    dispatchKeyDownToListeners(Vipper::ECommand::kRight);
                    break;

                case SDLK_UP:
                    dispatchKeyDownToListeners(Vipper::ECommand::kUp);
                    break;

                case SDLK_DOWN:
                    dispatchKeyDownToListeners(Vipper::ECommand::kDown);
                    break;
                case SDLK_SPACE:
                    dispatchKeyDownToListeners(Vipper::ECommand::kFire1);
                    break;
                default:
                    break;
            }
        }
    }
  }

  void CSDLRenderer::render() {
    SDL_Flip(video);
  }
}
<commit_msg>Free up the video surface before quitting<commit_after>#include <array>
#include <string>
#include <iostream>
#include <vector>
#include <memory>
#include <map>
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <SDL/SDL_mixer.h>
#include <SDL/SDL_ttf.h>
#include "Vipper/Vipper.h"
#include "CSDLRenderer.h"

namespace RunTheWorld {

    Vipper::IRenderer::BitmapId CSDLRenderer::loadBitmap( std::string path ) {
      auto id = mSprites.size() + 1;
      mSprites[ id ] = IMG_Load( path.c_str() );
      return id;
    }

    Vipper::IRenderer::SoundId CSDLRenderer::loadSound( std::string path ) {
      auto id = mSounds.size() + 1;
      mSounds[ id ] = Mix_LoadWAV(path.c_str() );
      return id;
    }

    Vipper::IRenderer::FontId CSDLRenderer::loadFont( std::string path, int sizeInPt ) {
      auto id = mFonts.size() + 1;
      mFonts[ id ] = TTF_OpenFont(path.c_str(), sizeInPt );

      return id;
    }

    void CSDLRenderer::fill(float x0, float x1, float y0, float x2, float x3, float y1, int shade[3]) {
        float fromY = std::min( y0, y1 );
        float toY = std::max( y0, y1 );
        SDL_Rect rect;
        float deltaY = toY - fromY;

        float ratiox0x2 = 1.0f;
        float ratiox1x3 = 1.0f;

        if ( toY - fromY > 0.0f  ) {
            ratiox0x2 = ( x0 - x2 ) / deltaY;
            ratiox1x3 = ( x1 - x3 ) / deltaY;
        }

        float x = x0;
        float fx = x1;

        for ( int line = toY; line >= fromY; line--) {

            rect.x = x;
            rect.y = line;
            rect.w = ( fx - x);
            rect.h = 1;

            x -= ratiox0x2;
            fx -= ratiox1x3;

            SDL_FillRect(video, &rect, SDL_MapRGB(video->format, shade[0], shade[1],  shade[2] ));
        }
    }

    void CSDLRenderer::drawSquare( int x, int y, int x2, int y2, std::array<int,4> colour ) {
      SDL_Rect rect;
      rect.x = x;
      rect.y = y;
      rect.w = ( x2 - x );
      rect.h = ( y2 - y );
      int colourMerged = SDL_MapRGBA( video->format, colour[ 0 ], colour[ 1 ], colour[ 2 ], colour[ 3 ] );
      SDL_FillRect( video, &rect, colourMerged );
    };

    void CSDLRenderer::drawTextAt( int x, int y, std::string text, std::array<int, 4> colour, Vipper::IRenderer::FontId id ) {
      if ( id == 0 ) {
        return;
      }

      SDL_Color color = { (Uint8)colour[ 0 ], (Uint8)colour[ 1 ], (Uint8)colour[ 2 ], (Uint8)colour[ 3 ] };
      auto font = mFonts[ id ];
      auto result = TTF_RenderText_Solid( font, text.c_str(), color );
      SDL_Rect rect;
      rect.x = x;
      rect.y = y;
      rect.w = result->w;
      rect.h = result->h;
      SDL_BlitSurface( result, nullptr, video, &rect );
      SDL_FreeSurface( result );
    };

    void CSDLRenderer::drawBitmapAt( int x, int y, int w, int h, const IRenderer::BitmapId id ) {

      if ( id == 0 ) {
        return;
      }

      auto bitmap = mSprites[ id ];
      SDL_Rect rect;
      rect.x = x;
      rect.y = y;
      rect.w = w;
      rect.h = h;
      SDL_BlitSurface( bitmap, nullptr, video, &rect );
    };

    void CSDLRenderer::playSound( const IRenderer::SoundId& id ) {
      if ( id == 0 ) {
        return;
      }

      auto sound = mSounds[ id ];

      Mix_PlayChannel( -1, sound, 0 );
    };

  CSDLRenderer::CSDLRenderer() {

    //REFACTOR!
    SDL_Init(  SDL_INIT_EVERYTHING );
    TTF_Init();
    video = SDL_SetVideoMode( 640, 480, 32, 0 );

    if ( Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024) == -1 ) {
      std::cout << "coudlnt init mixer" << std::endl;
    }
  }

  void CSDLRenderer::shutdown() {
      SDL_FreeSurface(video);
      SDL_Quit();
  }

  void CSDLRenderer::update() {
    SDL_Event event;

    if ( SDL_PollEvent( &event ) ) {

      if( event.type == SDL_QUIT ) {
        exit(0);
      }

      if ( event.type == SDL_MOUSEBUTTONDOWN ) {
        dispatchClickToListeners( std::pair<int, int>( event.button.x, event.button.y ) );
      }

        if (event.type == SDL_KEYUP) {
            switch (event.key.keysym.sym) {
                case SDLK_q:
#ifndef __EMSCRIPTEN__
                    exit(0);
#endif
                case SDLK_LEFT:
                    dispatchKeyUpToListeners(Vipper::ECommand::kLeft);
                    break;

                case SDLK_RIGHT:
                    dispatchKeyUpToListeners(Vipper::ECommand::kRight);
                    break;

                case SDLK_UP:
                    dispatchKeyUpToListeners(Vipper::ECommand::kUp);
                    break;

                case SDLK_DOWN:
                    dispatchKeyUpToListeners(Vipper::ECommand::kDown);
                    break;
                case SDLK_SPACE:
                    dispatchKeyUpToListeners(Vipper::ECommand::kFire1);
                    break;
                default:
                    break;
            }
        }

        if (event.type == SDL_KEYDOWN) {
            switch (event.key.keysym.sym) {
                case SDLK_LEFT:
                    dispatchKeyDownToListeners(Vipper::ECommand::kLeft);
                    break;
                case SDLK_RIGHT:
                    dispatchKeyDownToListeners(Vipper::ECommand::kRight);
                    break;

                case SDLK_UP:
                    dispatchKeyDownToListeners(Vipper::ECommand::kUp);
                    break;

                case SDLK_DOWN:
                    dispatchKeyDownToListeners(Vipper::ECommand::kDown);
                    break;
                case SDLK_SPACE:
                    dispatchKeyDownToListeners(Vipper::ECommand::kFire1);
                    break;
                default:
                    break;
            }
        }
    }
  }

  void CSDLRenderer::render() {
    SDL_Flip(video);
  }
}
<|endoftext|>


<commit_before>/*  ************************************************************************************
 *
 *  ftFluidFlow
 *
 *  Created by Matthias Oostrik on 03/16.14.
 *  Copyright 2014 http://www.MatthiasOostrik.com All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the author nor the names of its contributors
 *       may be used to endorse or promote products derived from this software
 *       without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 *  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 *  OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 *  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 *  OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *	The Fluid shaders are adapted from various sources. Unfortunately I can't remember all, but the most important ones:
 *		* Mark J Harris: Various online sources
 *		* Patricio Gonzalez Vivo (http://www.patriciogonzalezvivo.com): ofxFluid
 *
 *  ************************************************************************************ */

#include "ftFluidFlow.h"

namespace flowTools {

	ftFluidFlow::ftFluidFlow(){
		parameters.setName("fluid");
		parameters.add(speed.set("speed", .5, 0, 1));
		parameters.add(numJacobiIterations.set("iterations", 40, 1, 100));
		parameters.add(viscosity.set("viscosity", 0.0, 0, 1));
		parameters.add(vorticity.set("vorticity", 0.0, 0.0, 1));
		dissipationParameters.setName("dissipation");
		dissipationParameters.add(dissipationVel.set("velocity",0.0015, 0, 0.01));
		dissipationParameters.add(dissipationDen.set("density", 0.0015, 0, 0.01));
		dissipationParameters.add(dissipationPrs.set("pressure",0.025, 0, 0.1));
		parameters.add(dissipationParameters);
		smokeBuoyancyParameters.setName("smoke buoyancy");
		smokeBuoyancyParameters.add(smokeSigma.set("buoyancy", 0.5, 0.0, 1.0));
		smokeBuoyancyParameters.add(smokeWeight.set("weight", 0.05, 0.0, 1.0));
		smokeBuoyancyParameters.add(ambientTemperature.set("ambient temperature", 0.75, 0.0, 1.0));
		smokeBuoyancyParameters.add(gravity.set("gravity", ofDefaultVec2(0., -0.980665), ofDefaultVec2(-1, -1), ofDefaultVec2(1, 1)));
		parameters.add(smokeBuoyancyParameters);
//		parameters.add(wrap.set("wrap", false));
//		wrap.addListener(this, &ftFluidFlow::wrapListener);

	}

	//--------------------------------------------------------------
	void ftFluidFlow::setup(int _simulationWidth, int _simulationHeight, int _densityWidth, int _densityHeight) {
		allocate(_simulationWidth, _simulationHeight, GL_RG32F, _densityWidth, _densityHeight, GL_RGBA32F);
//		if(wrap.get()) { advectShader = &advectWrapShader; } else { advectShader = &advectNoWrapShader; }
		advectShader = &advectNoWrapShader;
	}

	void ftFluidFlow::allocate(int _simulationWidth, int _simulationHeight, GLint _simulationInternalFormat, int _densityWidth, int _densityHeight, GLint _densityInternalFormat) {
		simulationWidth = _simulationWidth;
		simulationHeight = _simulationHeight;
		densityWidth = _densityWidth;
		densityHeight = _densityHeight;

		ftFlow::allocate(simulationWidth, simulationHeight, _simulationInternalFormat, densityWidth, densityHeight, _densityInternalFormat);

		visualizationField.setup(simulationWidth, simulationHeight);

		temperatureFbo.allocate(simulationWidth,simulationHeight,GL_R32F);
		ftUtil::zero(temperatureFbo);
		pressureFbo.allocate(simulationWidth,simulationHeight,GL_R32F);
		ftUtil::zero(pressureFbo);
		obstacleFbo.allocate(simulationWidth, simulationHeight, GL_R8);
		ftUtil::zero(obstacleFbo);
		obstacleOffsetFbo.allocate(simulationWidth, simulationHeight, GL_RGBA32F);
		ftUtil::zero(obstacleOffsetFbo);
		obstacleOffsetShader.update(obstacleOffsetFbo, obstacleFbo.getTexture());
		divergenceFbo.allocate(simulationWidth, simulationHeight, GL_R32F);
		ftUtil::zero(divergenceFbo);
		smokeBuoyancyFbo.allocate(simulationWidth, simulationHeight, GL_RG32F);
		ftUtil::zero(smokeBuoyancyFbo);
		vorticityVelocityFbo.allocate(simulationWidth, simulationHeight, GL_RG32F);
		ftUtil::zero(pressureFbo);
		vorticityConfinementFbo.allocate(simulationWidth, simulationHeight, GL_RG32F);
		ftUtil::zero(pressureFbo);

		initObstacle();

	}

	//--------------------------------------------------------------
	void ftFluidFlow::update(float _deltaTime){
		float timeStep = _deltaTime * speed.get() * simulationWidth;

		ofPushStyle();
		ofEnableBlendMode(OF_BLENDMODE_DISABLED);

		ftPingPongFbo& velocityFbo = inputFbo;
		ftPingPongFbo& densityFbo = outputFbo;

		// ADVECT
		velocityFbo.swap();
		advectShader->update(velocityFbo.get(), velocityFbo.getBackTexture(), velocityFbo.getBackTexture(), timeStep, 1.0 - dissipationVel.get());
		velocityFbo.swap();
		applyObstacleNegShader.update(velocityFbo.get(), velocityFbo.getBackTexture(), obstacleOffsetFbo.getTexture());

		// ADD FORCES: DIFFUSE
		if (viscosity.get() > 0.0) {
			for (int i = 0; i < numJacobiIterations.get(); i++) {
				velocityFbo.swap();
				diffuseShader.update(velocityFbo.get(), velocityFbo.getBackTexture(), viscosity.get());
			}
			velocityFbo.swap();
			applyObstacleNegShader.update(velocityFbo.get(), velocityFbo.getBackTexture(), obstacleOffsetFbo.getTexture());
		}

		// ADD FORCES: VORTEX CONFINEMENT
		if (vorticity.get() > 0.0) {
			vorticityVelocityShader.update(vorticityVelocityFbo.get(), velocityFbo.getTexture());
			vorticityVelocityFbo.swap();
			applyObstacleZeroShader.update(vorticityVelocityFbo.get(), vorticityVelocityFbo.getBackTexture(), obstacleOffsetFbo.getTexture());
			vorticityConfinementShader.update(vorticityConfinementFbo, vorticityVelocityFbo.getTexture(), timeStep, vorticity.get());
			addVelocity(vorticityConfinementFbo.getTexture());
			velocityFbo.swap();
			applyObstacleNegShader.update(velocityFbo.get(), velocityFbo.getBackTexture(), obstacleOffsetFbo.getTexture());
		}

		// ADD FORCES:  SMOKE BUOYANCY
		if (smokeSigma.get() > 0.0 && smokeWeight.get() > 0.0 ) {
			temperatureFbo.swap();
			advectShader->update(temperatureFbo.get(), temperatureFbo.getBackTexture(), velocityFbo.getTexture(),  timeStep, 1.0 - dissipationDen.get());
//			temperatureFbo.swap();
//			clampLengthShader.update(temperatureFbo.get(), temperatureFbo.getBackTexture(), 2.0, 1.0);
			temperatureFbo.swap();
			applyObstacleNegShader.update(temperatureFbo.get(), temperatureFbo.getBackTexture(), obstacleOffsetFbo.getTexture());
			ftUtil::zero(smokeBuoyancyFbo);
			smokeBuoyancyShader.update(smokeBuoyancyFbo, temperatureFbo.getTexture(), densityFbo.getTexture(), ambientTemperature.get(), timeStep, smokeSigma.get(), smokeWeight.get(), gravity.get());
			addVelocity(smokeBuoyancyFbo.getTexture());
			velocityFbo.swap();
			applyObstacleNegShader.update(velocityFbo.get(), velocityFbo.getBackTexture(), obstacleOffsetFbo.getTexture());
		}
		else {
			ftUtil::zero(temperatureFbo);
		}

		// PRESSURE: DIVERGENCE
//		ftUtil::zero(divergenceFbo);
		divergenceShader.update(divergenceFbo, velocityFbo.getTexture());

		// PRESSURE: JACOBI
//		ftUtil::zero(pressureFbo);
		pressureFbo.swap();
		multiplyForceShader.update(pressureFbo.get(), pressureFbo.getBackTexture(), 1.0 - dissipationPrs.get());
		for (int i = 0; i < numJacobiIterations.get(); i++) {
			pressureFbo.swap();
			jacobiObstacleShader.update(pressureFbo.get(), pressureFbo.getBackTexture(), divergenceFbo.getTexture(), obstacleOffsetFbo.getTexture());
		}
		pressureFbo.swap();
		applyObstaclePosShader.update(pressureFbo.get(), pressureFbo.getBackTexture(), obstacleOffsetFbo.getTexture());

		// PRESSURE: SUBSTRACT GRADIENT
		velocityFbo.swap();
		substractGradientShader.update(velocityFbo.get(), velocityFbo.getBackTexture(), pressureFbo.getTexture());
		velocityFbo.swap();
		applyObstacleNegShader.update(velocityFbo.get(), velocityFbo.getBackTexture(), obstacleOffsetFbo.getTexture());

		// DENSITY:
		densityFbo.swap();
		advectShader->update(densityFbo.get(), densityFbo.getBackTexture(), velocityFbo.getTexture(), timeStep, 1.0 - dissipationDen.get());
//		densityFbo.swap();
//		clampLengthShader.update(densityFbo.get(), densityFbo.getBackTexture(), sqrt(3), 1.0);
		densityFbo.swap();
		applyObstacleDensityShader.update(densityFbo.get(), densityFbo.getBackTexture(), obstacleFbo.getTexture());

		ofPopStyle();
	}

	//--------------------------------------------------------------
	void ftFluidFlow::setFlow(flowTools::ftFlowForceType _type, ofTexture &_tex) {
		switch (_type) {
			case FT_VELOCITY:		setVelocity(_tex);		break;
			case FT_DENSITY:		setDensity(_tex);		break;
			case FT_TEMPERATURE:	setTemperature(_tex);	break;
			case FT_PRESSURE:		setPressure(_tex);		break;
			case FT_OBSTACLE:		setObstacle(_tex);		break;
			default:
				ofLogWarning("ftFluidFlow: addFlow") << "no method to add flow of type " << _type;
				break;
		}
	}

	//--------------------------------------------------------------
	void ftFluidFlow::addFlow(flowTools::ftFlowForceType _type, ofTexture &_tex, float _strength) {
		switch (_type) {
			case FT_VELOCITY:		addVelocity(_tex, _strength);		break;
			case FT_DENSITY:		addDensity(_tex, _strength);		break;
			case FT_TEMPERATURE:	addTemperature(_tex, _strength);	break;
			case FT_PRESSURE:		addPressure(_tex, _strength);		break;
			case FT_OBSTACLE:		addObstacle(_tex);					break;
			default:
				ofLogWarning("ftFluidFlow: addFlow") << "no method to add flow of type " << _type;
				break;
		}
	}

	//--------------------------------------------------------------
	void ftFluidFlow::initObstacle(){
//		if (wrap.get()) {
//			ftUtil::zero(obstacleFbo);
//		}
//		else { // create edge
			ofPushStyle();
			ofEnableBlendMode(OF_BLENDMODE_DISABLED);
			ftUtil::one(obstacleFbo);
			obstacleFbo.begin();
			ofSetColor(0,0,0,255);
			int borderSize = 1;
			ofDrawRectangle(borderSize, borderSize, obstacleFbo.getWidth()-borderSize*2, obstacleFbo.getHeight()-borderSize*2);
			obstacleFbo.end();
			ofPopStyle();
//		}

		obstacleOffsetShader.update(obstacleOffsetFbo, obstacleFbo.getTexture());
	}

	//--------------------------------------------------------------
	void ftFluidFlow::setObstacle(ofTexture & _tex){
		ofPushStyle();
		ofEnableBlendMode(OF_BLENDMODE_DISABLED);
		initObstacle();
		addBooleanShader.update(obstacleFbo.get(), obstacleFbo.getBackTexture(), _tex);
		ftUtil::zero(obstacleOffsetFbo);
		obstacleOffsetShader.update(obstacleOffsetFbo, obstacleFbo.getTexture());
		ofPopStyle();
	}

	//--------------------------------------------------------------
	void ftFluidFlow::addObstacle(ofTexture & _tex){
		ofPushStyle();
		ofEnableBlendMode(OF_BLENDMODE_DISABLED);
		obstacleFbo.swap();
		addBooleanShader.update(obstacleFbo.get(), obstacleFbo.getBackTexture(), _tex);
		obstacleOffsetShader.update(obstacleOffsetFbo, obstacleFbo.getTexture());
		ofPopStyle();
	}

	//--------------------------------------------------------------
	void ftFluidFlow::reset() {

		ftFlow::reset();
		ftUtil::zero(pressureFbo);
		ftUtil::zero(temperatureFbo);
		ftUtil::zero(divergenceFbo);
		ftUtil::zero(vorticityVelocityFbo);
		ftUtil::zero(vorticityConfinementFbo);
		ftUtil::zero(smokeBuoyancyFbo);

		initObstacle();

		jacobiObstacleShader = ftJacobiObstacleShader();
	}
}
<commit_msg>optimized obstacle<commit_after>/*  ************************************************************************************
 *
 *  ftFluidFlow
 *
 *  Created by Matthias Oostrik on 03/16.14.
 *  Copyright 2014 http://www.MatthiasOostrik.com All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the author nor the names of its contributors
 *       may be used to endorse or promote products derived from this software
 *       without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 *  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 *  OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 *  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 *  OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *	The Fluid shaders are adapted from various sources. Unfortunately I can't remember all, but the most important ones:
 *		* Mark J Harris: Various online sources
 *		* Patricio Gonzalez Vivo (http://www.patriciogonzalezvivo.com): ofxFluid
 *
 *  ************************************************************************************ */

#include "ftFluidFlow.h"

namespace flowTools {

	ftFluidFlow::ftFluidFlow(){
		parameters.setName("fluid");
		parameters.add(speed.set("speed", .5, 0, 1));
		parameters.add(numJacobiIterations.set("iterations", 40, 1, 100));
		parameters.add(viscosity.set("viscosity", 0.0, 0, 1));
		parameters.add(vorticity.set("vorticity", 0.0, 0.0, 1));
		dissipationParameters.setName("dissipation");
		dissipationParameters.add(dissipationVel.set("velocity",0.0015, 0, 0.01));
		dissipationParameters.add(dissipationDen.set("density", 0.0015, 0, 0.01));
		dissipationParameters.add(dissipationPrs.set("pressure",0.025, 0, 0.1));
		parameters.add(dissipationParameters);
		smokeBuoyancyParameters.setName("smoke buoyancy");
		smokeBuoyancyParameters.add(smokeSigma.set("buoyancy", 0.5, 0.0, 1.0));
		smokeBuoyancyParameters.add(smokeWeight.set("weight", 0.05, 0.0, 1.0));
		smokeBuoyancyParameters.add(ambientTemperature.set("ambient temperature", 0.75, 0.0, 1.0));
		smokeBuoyancyParameters.add(gravity.set("gravity", ofDefaultVec2(0., -0.980665), ofDefaultVec2(-1, -1), ofDefaultVec2(1, 1)));
		parameters.add(smokeBuoyancyParameters);
//		parameters.add(wrap.set("wrap", false));
//		wrap.addListener(this, &ftFluidFlow::wrapListener);

	}

	//--------------------------------------------------------------
	void ftFluidFlow::setup(int _simulationWidth, int _simulationHeight, int _densityWidth, int _densityHeight) {
		allocate(_simulationWidth, _simulationHeight, GL_RG32F, _densityWidth, _densityHeight, GL_RGBA32F);
//		if(wrap.get()) { advectShader = &advectWrapShader; } else { advectShader = &advectNoWrapShader; }
		advectShader = &advectNoWrapShader;
	}

	void ftFluidFlow::allocate(int _simulationWidth, int _simulationHeight, GLint _simulationInternalFormat, int _densityWidth, int _densityHeight, GLint _densityInternalFormat) {
		simulationWidth = _simulationWidth;
		simulationHeight = _simulationHeight;
		densityWidth = _densityWidth;
		densityHeight = _densityHeight;

		ftFlow::allocate(simulationWidth, simulationHeight, _simulationInternalFormat, densityWidth, densityHeight, _densityInternalFormat);

		visualizationField.setup(simulationWidth, simulationHeight);

		temperatureFbo.allocate(simulationWidth,simulationHeight,GL_R32F);
		ftUtil::zero(temperatureFbo);
		pressureFbo.allocate(simulationWidth,simulationHeight,GL_R32F);
		ftUtil::zero(pressureFbo);
		obstacleFbo.allocate(simulationWidth, simulationHeight, GL_R8);
		ftUtil::zero(obstacleFbo);
		obstacleOffsetFbo.allocate(simulationWidth, simulationHeight, GL_RGB32F);
		ftUtil::zero(obstacleOffsetFbo);
		obstacleOffsetShader.update(obstacleOffsetFbo, obstacleFbo.getTexture());
		divergenceFbo.allocate(simulationWidth, simulationHeight, GL_R32F);
		ftUtil::zero(divergenceFbo);
		smokeBuoyancyFbo.allocate(simulationWidth, simulationHeight, GL_RG32F);
		ftUtil::zero(smokeBuoyancyFbo);
		vorticityVelocityFbo.allocate(simulationWidth, simulationHeight, GL_RG32F);
		ftUtil::zero(pressureFbo);
		vorticityConfinementFbo.allocate(simulationWidth, simulationHeight, GL_RG32F);
		ftUtil::zero(pressureFbo);

		initObstacle();

	}

	//--------------------------------------------------------------
	void ftFluidFlow::update(float _deltaTime){
		float timeStep = _deltaTime * speed.get() * simulationWidth;

		ofPushStyle();
		ofEnableBlendMode(OF_BLENDMODE_DISABLED);

		ftPingPongFbo& velocityFbo = inputFbo;
		ftPingPongFbo& densityFbo = outputFbo;

		// ADVECT
		velocityFbo.swap();
		advectShader->update(velocityFbo.get(), velocityFbo.getBackTexture(), velocityFbo.getBackTexture(), timeStep, 1.0 - dissipationVel.get());
		velocityFbo.swap();
		applyObstacleNegShader.update(velocityFbo.get(), velocityFbo.getBackTexture(), obstacleOffsetFbo.getTexture());

		// ADD FORCES: DIFFUSE
		if (viscosity.get() > 0.0) {
			for (int i = 0; i < numJacobiIterations.get(); i++) {
				velocityFbo.swap();
				diffuseShader.update(velocityFbo.get(), velocityFbo.getBackTexture(), viscosity.get());
			}
			velocityFbo.swap();
			applyObstacleNegShader.update(velocityFbo.get(), velocityFbo.getBackTexture(), obstacleOffsetFbo.getTexture());
		}

		// ADD FORCES: VORTEX CONFINEMENT
		if (vorticity.get() > 0.0) {
			vorticityVelocityShader.update(vorticityVelocityFbo.get(), velocityFbo.getTexture());
			vorticityVelocityFbo.swap();
			applyObstacleZeroShader.update(vorticityVelocityFbo.get(), vorticityVelocityFbo.getBackTexture(), obstacleOffsetFbo.getTexture());
			vorticityConfinementShader.update(vorticityConfinementFbo, vorticityVelocityFbo.getTexture(), timeStep, vorticity.get());
			addVelocity(vorticityConfinementFbo.getTexture());
			velocityFbo.swap();
			applyObstacleNegShader.update(velocityFbo.get(), velocityFbo.getBackTexture(), obstacleOffsetFbo.getTexture());
		}

		// ADD FORCES:  SMOKE BUOYANCY
		if (smokeSigma.get() > 0.0 && smokeWeight.get() > 0.0 ) {
			temperatureFbo.swap();
			advectShader->update(temperatureFbo.get(), temperatureFbo.getBackTexture(), velocityFbo.getTexture(),  timeStep, 1.0 - dissipationDen.get());
//			temperatureFbo.swap();
//			clampLengthShader.update(temperatureFbo.get(), temperatureFbo.getBackTexture(), 2.0, 1.0);
			temperatureFbo.swap();
			applyObstacleNegShader.update(temperatureFbo.get(), temperatureFbo.getBackTexture(), obstacleOffsetFbo.getTexture());
			ftUtil::zero(smokeBuoyancyFbo);
			smokeBuoyancyShader.update(smokeBuoyancyFbo, temperatureFbo.getTexture(), densityFbo.getTexture(), ambientTemperature.get(), timeStep, smokeSigma.get(), smokeWeight.get(), gravity.get());
			addVelocity(smokeBuoyancyFbo.getTexture());
			velocityFbo.swap();
			applyObstacleNegShader.update(velocityFbo.get(), velocityFbo.getBackTexture(), obstacleOffsetFbo.getTexture());
		}
		else {
			ftUtil::zero(temperatureFbo);
		}

		// PRESSURE: DIVERGENCE
//		ftUtil::zero(divergenceFbo);
		divergenceShader.update(divergenceFbo, velocityFbo.getTexture());

		// PRESSURE: JACOBI
//		ftUtil::zero(pressureFbo);
		pressureFbo.swap();
		multiplyForceShader.update(pressureFbo.get(), pressureFbo.getBackTexture(), 1.0 - dissipationPrs.get());
		for (int i = 0; i < numJacobiIterations.get(); i++) {
			pressureFbo.swap();
			jacobiObstacleShader.update(pressureFbo.get(), pressureFbo.getBackTexture(), divergenceFbo.getTexture(), obstacleOffsetFbo.getTexture());
		}
		pressureFbo.swap();
		applyObstaclePosShader.update(pressureFbo.get(), pressureFbo.getBackTexture(), obstacleOffsetFbo.getTexture());

		// PRESSURE: SUBSTRACT GRADIENT
		velocityFbo.swap();
		substractGradientShader.update(velocityFbo.get(), velocityFbo.getBackTexture(), pressureFbo.getTexture());
		velocityFbo.swap();
		applyObstacleNegShader.update(velocityFbo.get(), velocityFbo.getBackTexture(), obstacleOffsetFbo.getTexture());

		// DENSITY:
		densityFbo.swap();
		advectShader->update(densityFbo.get(), densityFbo.getBackTexture(), velocityFbo.getTexture(), timeStep, 1.0 - dissipationDen.get());
//		densityFbo.swap();
//		clampLengthShader.update(densityFbo.get(), densityFbo.getBackTexture(), sqrt(3), 1.0);
		densityFbo.swap();
		applyObstacleDensityShader.update(densityFbo.get(), densityFbo.getBackTexture(), obstacleFbo.getTexture());

		ofPopStyle();
	}

	//--------------------------------------------------------------
	void ftFluidFlow::setFlow(flowTools::ftFlowForceType _type, ofTexture &_tex) {
		switch (_type) {
			case FT_VELOCITY:		setVelocity(_tex);		break;
			case FT_DENSITY:		setDensity(_tex);		break;
			case FT_TEMPERATURE:	setTemperature(_tex);	break;
			case FT_PRESSURE:		setPressure(_tex);		break;
			case FT_OBSTACLE:		setObstacle(_tex);		break;
			default:
				ofLogWarning("ftFluidFlow: addFlow") << "no method to add flow of type " << _type;
				break;
		}
	}

	//--------------------------------------------------------------
	void ftFluidFlow::addFlow(flowTools::ftFlowForceType _type, ofTexture &_tex, float _strength) {
		switch (_type) {
			case FT_VELOCITY:		addVelocity(_tex, _strength);		break;
			case FT_DENSITY:		addDensity(_tex, _strength);		break;
			case FT_TEMPERATURE:	addTemperature(_tex, _strength);	break;
			case FT_PRESSURE:		addPressure(_tex, _strength);		break;
			case FT_OBSTACLE:		addObstacle(_tex);					break;
			default:
				ofLogWarning("ftFluidFlow: addFlow") << "no method to add flow of type " << _type;
				break;
		}
	}

	//--------------------------------------------------------------
	void ftFluidFlow::initObstacle(){
//		if (wrap.get()) {
//			ftUtil::zero(obstacleFbo);
//		}
//		else { // create edge
			ofPushStyle();
			ofEnableBlendMode(OF_BLENDMODE_DISABLED);
			ftUtil::one(obstacleFbo);
			obstacleFbo.begin();
			ofSetColor(0,0,0,255);
			int borderSize = 1;
			ofDrawRectangle(borderSize, borderSize, obstacleFbo.getWidth()-borderSize*2, obstacleFbo.getHeight()-borderSize*2);
			obstacleFbo.end();
			ofPopStyle();
//		}

		obstacleOffsetShader.update(obstacleOffsetFbo, obstacleFbo.getTexture());
	}

	//--------------------------------------------------------------
	void ftFluidFlow::setObstacle(ofTexture & _tex){
		ofPushStyle();
		ofEnableBlendMode(OF_BLENDMODE_DISABLED);
		initObstacle();
		addBooleanShader.update(obstacleFbo.get(), obstacleFbo.getBackTexture(), _tex);
		ftUtil::zero(obstacleOffsetFbo);
		obstacleOffsetShader.update(obstacleOffsetFbo, obstacleFbo.getTexture());
		ofPopStyle();
	}

	//--------------------------------------------------------------
	void ftFluidFlow::addObstacle(ofTexture & _tex){
		ofPushStyle();
		ofEnableBlendMode(OF_BLENDMODE_DISABLED);
		obstacleFbo.swap();
		addBooleanShader.update(obstacleFbo.get(), obstacleFbo.getBackTexture(), _tex);
		obstacleOffsetShader.update(obstacleOffsetFbo, obstacleFbo.getTexture());
		ofPopStyle();
	}

	//--------------------------------------------------------------
	void ftFluidFlow::reset() {

		ftFlow::reset();
		ftUtil::zero(pressureFbo);
		ftUtil::zero(temperatureFbo);
		ftUtil::zero(divergenceFbo);
		ftUtil::zero(vorticityVelocityFbo);
		ftUtil::zero(vorticityConfinementFbo);
		ftUtil::zero(smokeBuoyancyFbo);

		initObstacle();

		jacobiObstacleShader = ftJacobiObstacleShader();
	}
}
<|endoftext|>


<commit_before>/*

    ofxTableGestures (formerly OF-TangibleFramework)
    Developed for Taller de Sistemes Interactius I
    Universitat Pompeu Fabra

    Copyright (c) 2011 Carles F. Julià <carles.fernandez@upf.edu>

    Permission is hereby granted, free of charge, to any person
    obtaining a copy of this software and associated documentation
    files (the "Software"), to deal in the Software without
    restriction, including without limitation the rights to use,
    copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following
    conditions:

    The above copyright notice and this permission notice shall be
    included in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    OTHER DEALINGS IN THE SOFTWARE.

*/

#ifndef FIGUREGRAPHIC_HPP_INCLUDED
#define FIGUREGRAPHIC_HPP_INCLUDED

#include "ofVectorMath.h"
#include "Graphic.hpp"
#include "Figure.h"

inline void ofMultMatrix(ofMatrix4x4 &m) {
    float a[] = {m(0,0),m(0,1),m(0,2),m(0,3),
                 m(1,0),m(1,1),m(1,2),m(1,3),
                 m(2,0),m(2,1),m(2,2),m(2,3),
                 m(3,0),m(3,1),m(3,2),m(3,3)};
    glMultMatrixf(a);
}

class FigureGraphic: public Graphic
{
    Figures::Figure * figure;
    bool testCollide;
    bool hasalpha;
    bool fill;
    bool hidden;
    public:
    ofColor color;
    ofMatrix4x4 transformation;
    FigureGraphic(Figures::Figure * f):figure(f),testCollide(true),hasalpha(false),fill(true),hidden(false){}
    ~FigureGraphic(){}
    inline bool Collide(ofPoint const & point)
    {
        return testCollide && figure->Collide(point);
    }
    void draw()
    {
        if(hidden)
        {
            ofPushMatrix();
            ofMultMatrix(transformation);
            glGetDoublev(GL_MODELVIEW_MATRIX,figure->getMatrix().data);
            ofPopMatrix();
        }
        else
        {
            ofPushStyle();
            ofPushMatrix();
            ofMultMatrix(transformation);
            if(hasalpha)
            {
                ofEnableAlphaBlending();
                ofSetColor(color.r,color.g,color.b,color.a);
            }
            else
            {
                ofSetColor(color.r,color.g,color.b);
            }
            if(fill)
            {figure->Draw();}
            else
            {figure->DrawStroke();}
            if(hasalpha)
            {
                ofDisableAlphaBlending();
            }
            ofPopMatrix();
            ofPopStyle();
        }
    }
    void canCollide(bool can){testCollide = can;}
    bool canCollide(){return testCollide;}
    void hasAlpha(bool has){hasalpha = has;}
    bool hasAlpha(){return hasalpha;}
    bool getFill(){return fill;}
    void setFill(bool Fill){fill = Fill;}
    Figures::Figure * getFigure(){return figure;}
    void setFigure(Figures::Figure * f){figure = f;}
    bool isHidden() {return hidden;}
    void isHidden(bool is){hidden = is;}
};

#endif // FIGUREGRAPHIC_HPP_INCLUDED
<commit_msg>adding layer specification on figuregraphic<commit_after>/*

    ofxTableGestures (formerly OF-TangibleFramework)
    Developed for Taller de Sistemes Interactius I
    Universitat Pompeu Fabra

    Copyright (c) 2011 Carles F. Julià <carles.fernandez@upf.edu>

    Permission is hereby granted, free of charge, to any person
    obtaining a copy of this software and associated documentation
    files (the "Software"), to deal in the Software without
    restriction, including without limitation the rights to use,
    copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following
    conditions:

    The above copyright notice and this permission notice shall be
    included in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    OTHER DEALINGS IN THE SOFTWARE.

*/

#ifndef FIGUREGRAPHIC_HPP_INCLUDED
#define FIGUREGRAPHIC_HPP_INCLUDED

#include "ofVectorMath.h"
#include "Graphic.hpp"
#include "Figure.h"

inline void ofMultMatrix(ofMatrix4x4 &m) {
    float a[] = {m(0,0),m(0,1),m(0,2),m(0,3),
                 m(1,0),m(1,1),m(1,2),m(1,3),
                 m(2,0),m(2,1),m(2,2),m(2,3),
                 m(3,0),m(3,1),m(3,2),m(3,3)};
    glMultMatrixf(a);
}

class FigureGraphic: public Graphic
{
    Figures::Figure * figure;
    bool testCollide;
    bool hasalpha;
    bool fill;
    bool hidden;
    public:
    ofColor color;
    ofMatrix4x4 transformation;
    FigureGraphic(Figures::Figure * f, int layer=APP_LAYER):Graphic(layer),figure(f),testCollide(true),hasalpha(false),fill(true),hidden(false){}
    ~FigureGraphic(){}
    inline bool Collide(ofPoint const & point)
    {
        return testCollide && figure->Collide(point);
    }
    void draw()
    {
        if(hidden)
        {
            ofPushMatrix();
            ofMultMatrix(transformation);
            glGetDoublev(GL_MODELVIEW_MATRIX,figure->getMatrix().data);
            ofPopMatrix();
        }
        else
        {
            ofPushStyle();
            ofPushMatrix();
            ofMultMatrix(transformation);
            if(hasalpha)
            {
                ofEnableAlphaBlending();
                ofSetColor(color.r,color.g,color.b,color.a);
            }
            else
            {
                ofSetColor(color.r,color.g,color.b);
            }
            if(fill)
            {figure->Draw();}
            else
            {figure->DrawStroke();}
            if(hasalpha)
            {
                ofDisableAlphaBlending();
            }
            ofPopMatrix();
            ofPopStyle();
        }
    }
    void canCollide(bool can){testCollide = can;}
    bool canCollide(){return testCollide;}
    void hasAlpha(bool has){hasalpha = has;}
    bool hasAlpha(){return hasalpha;}
    bool getFill(){return fill;}
    void setFill(bool Fill){fill = Fill;}
    Figures::Figure * getFigure(){return figure;}
    void setFigure(Figures::Figure * f){figure = f;}
    bool isHidden() {return hidden;}
    void isHidden(bool is){hidden = is;}
};

#endif // FIGUREGRAPHIC_HPP_INCLUDED
<|endoftext|>