/* * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * ***** END GPL LICENSE BLOCK ***** */ #ifndef __GRID_H__ #define __GRID_H__ /** \file blender/freestyle/intern/geometry/Grid.h * \ingroup freestyle * \brief Base class to define a cell grid surrounding the bounding box of the scene * \author Stephane Grabli * \date 30/07/2002 */ #include // for memset #include #include // For SET_UINT_IN_POINTER, i.e. uintptr_t. #include #include "Geom.h" #include "GeomUtils.h" #include "Polygon.h" #include "../system/FreestyleConfig.h" extern "C" { #include "BLI_utildefines.h" } #ifdef WITH_CXX_GUARDEDALLOC #include "MEM_guardedalloc.h" #endif using namespace std; namespace Freestyle { using namespace Geometry; typedef vector OccludersSet; // // Class to define cells used by the regular grid // /////////////////////////////////////////////////////////////////////////////// class Cell { public: Cell(Vec3r& orig) { _orig = orig; } virtual ~Cell() {} inline void addOccluder(Polygon3r *o) { if (o) _occluders.push_back(o); } inline const Vec3r& getOrigin() { return _orig; } inline OccludersSet& getOccluders() { return _occluders; } private: Vec3r _orig; OccludersSet _occluders; #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:Cell") #endif }; class GridVisitor { public: virtual ~GridVisitor() {}; //soc virtual void discoverCell(Cell *cell) {} virtual void examineOccluder(Polygon3r *occ) {} virtual void finishCell(Cell *cell) {} virtual bool stop() { return false; } #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:GridVisitor") #endif }; /*! Gathers all the occluders belonging to the cells traversed by the ray */ class allOccludersGridVisitor : public GridVisitor { public: allOccludersGridVisitor(OccludersSet& occluders) : GridVisitor(), occluders_(occluders) {} virtual void examineOccluder(Polygon3r *occ); OccludersSet& occluders() { return occluders_; } void clear() { occluders_.clear(); } private: OccludersSet& occluders_; }; /*! Finds the first intersection and breaks. * The occluder and the intersection information are stored and accessible. */ class firstIntersectionGridVisitor : public GridVisitor { //soc - changed order to remove warnings public: double u_, v_, t_; private: Polygon3r *occluder_; Vec3r ray_org_, ray_dir_, cell_size_; Cell *current_cell_; public: firstIntersectionGridVisitor(const Vec3r& ray_org, const Vec3r& ray_dir, const Vec3r& cell_size) : GridVisitor(), u_(0), v_(0), t_(DBL_MAX), occluder_(0), ray_org_(ray_org), ray_dir_(ray_dir), cell_size_(cell_size), current_cell_(0) { } virtual ~firstIntersectionGridVisitor() {} virtual void discoverCell(Cell *cell) { current_cell_ = cell; } virtual void examineOccluder(Polygon3r *occ); virtual bool stop(); Polygon3r *occluder() { return occluder_; } }; // // Class to define a regular grid used for ray casting computations // /////////////////////////////////////////////////////////////////////////////// class Grid { public: /*! Builds a Grid. Must be followed by a call to configure() */ Grid() {} virtual ~Grid() { clear(); } /*! clears the grid * Deletes all the cells, clears the hashtable, resets size, size of cell, number of cells. */ virtual void clear(); /*! Sets the different parameters of the grid * orig * The grid origin * size * The grid's dimensions * nb * The number of cells of the grid */ virtual void configure(const Vec3r& orig, const Vec3r& size, unsigned nb); /*! returns a vector of integer containing the coordinates of the cell containing the point passed as argument * p * The point for which we're looking the cell */ inline void getCellCoordinates(const Vec3r& p, Vec3u& res) { int tmp; for (int i = 0; i < 3; i++) { tmp = (int)((p[i] - _orig[i]) / _cell_size[i]); if (tmp < 0) res[i] = 0; else if ((unsigned int)tmp >= _cells_nb[i]) res[i] = _cells_nb[i] - 1; else res[i] = tmp; } } /*! Fills the case corresponding to coord with the cell */ virtual void fillCell(const Vec3u& coord, Cell& cell) = 0; /*! returns the cell whose coordinates are pased as argument */ virtual Cell *getCell(const Vec3u& coord) = 0; /*! returns the cell containing the point passed as argument. If the cell is empty (contains no occluder), * NULL is returned * p * The point for which we're looking the cell */ inline Cell *getCell(const Vec3r& p) { Vec3u coord; getCellCoordinates(p, coord); return getCell(coord); } /*! Retrieves the x,y,z coordinates of the origin of the cell whose coordinates (i,j,k) is passed as argument * cell_coord * i,j,k integer coordinates for the cell * orig * x,y,x vector to be filled in with the cell origin's coordinates */ inline void getCellOrigin(const Vec3u& cell_coord, Vec3r& orig) { for (unsigned int i = 0; i < 3; i++) orig[i] = _orig[i] + cell_coord[i] * _cell_size[i]; } /*! Retrieves the box corresponding to the cell whose coordinates are passed as argument. * cell_coord * i,j,k integer coordinates for the cell * min_out * The min x,y,x vector of the box. Filled in by the method. * max_out * The max x,y,z coordinates of the box. Filled in by the method. */ inline void getCellBox(const Vec3u& cell_coord, Vec3r& min_out, Vec3r& max_out) { getCellOrigin(cell_coord, min_out); max_out = min_out + _cell_size; } /*! inserts a convex polygon occluder * This method is quite coarse insofar as it adds all cells intersecting the polygon bounding box * convex_poly * The list of 3D points constituting a convex polygon */ void insertOccluder(Polygon3r *convex_poly); /*! Adds an occluder to the list of occluders */ void addOccluder(Polygon3r *occluder) { _occluders.push_back(occluder); } /*! Casts a ray between a starting point and an ending point * Returns the list of occluders contained in the cells intersected by this ray * Starts with a call to InitRay. */ void castRay(const Vec3r& orig, const Vec3r& end, OccludersSet& occluders, unsigned timestamp); // Prepares to cast ray without generating OccludersSet void initAcceleratedRay(const Vec3r& orig, const Vec3r& end, unsigned timestamp); /*! Casts an infinite ray (still finishing at the end of the grid) from a starting point and in a given direction. * Returns the list of occluders contained in the cells intersected by this ray * Starts with a call to InitRay. */ void castInfiniteRay(const Vec3r& orig, const Vec3r& dir, OccludersSet& occluders, unsigned timestamp); // Prepares to cast ray without generating OccludersSet. bool initAcceleratedInfiniteRay(const Vec3r& orig, const Vec3r& dir, unsigned timestamp); /*! Casts an infinite ray (still finishing at the end of the grid) from a starting point and in a given direction. * Returns the first intersection (occluder,t,u,v) or null. * Starts with a call to InitRay. */ Polygon3r * castRayToFindFirstIntersection(const Vec3r& orig, const Vec3r& dir, double& t, double& u, double& v, unsigned timestamp); /*! Init all structures and values for computing the cells intersected by this new ray */ void initRay(const Vec3r &orig, const Vec3r& end, unsigned timestamp); /*! Init all structures and values for computing the cells intersected by this infinite ray. * Returns false if the ray doesn't intersect the grid. */ bool initInfiniteRay(const Vec3r &orig, const Vec3r& dir, unsigned timestamp); /*! Accessors */ inline const Vec3r& getOrigin() const { return _orig; } inline Vec3r gridSize() const { return _size; } inline Vec3r getCellSize() const { return _cell_size; } //ARB profiling only: inline OccludersSet *getOccluders() { return &_occluders; } void displayDebug() { cerr << "Cells nb : " << _cells_nb << endl; cerr << "Cell size : " << _cell_size << endl; cerr << "Origin : " << _orig << endl; cerr << "Occluders nb : " << _occluders.size() << endl; } protected: /*! Core of castRay and castInfiniteRay, find occluders along the given ray */ inline void castRayInternal(GridVisitor& visitor) { Cell *current_cell = NULL; do { current_cell = getCell(_current_cell); if (current_cell) { visitor.discoverCell(current_cell); OccludersSet& occluders = current_cell->getOccluders(); // FIXME: I had forgotten the ref & for (OccludersSet::iterator it = occluders.begin(); it != occluders.end(); it++) { if (GET_UINT_FROM_POINTER((*it)->userdata2) != _timestamp) { (*it)->userdata2 = SET_UINT_IN_POINTER(_timestamp); visitor.examineOccluder(*it); } } visitor.finishCell(current_cell); } } while ((!visitor.stop()) && (nextRayCell(_current_cell, _current_cell))); } /*! returns the cell next to the cell passed as argument. */ bool nextRayCell(Vec3u& current_cell, Vec3u& next_cell); unsigned int _timestamp; Vec3u _cells_nb; // number of cells for x,y,z axis Vec3r _cell_size; // cell x,y,z dimensions Vec3r _size; // grid x,y,x dimensions Vec3r _orig; // grid origin Vec3r _ray_dir; // direction vector for the ray Vec3u _current_cell; // The current cell being processed (designated by its 3 coordinates) Vec3r _pt; // Points corresponding to the incoming and outgoing intersections of one cell with the ray real _t_end; // To know when we are at the end of the ray real _t; //OccludersSet _ray_occluders; // Set storing the occluders contained in the cells traversed by a ray OccludersSet _occluders; // List of all occluders inserted in the grid #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:Grid") #endif }; // // Class to walk through occluders in grid without building intermediate data structures // /////////////////////////////////////////////////////////////////////////////// class VirtualOccludersSet { public: VirtualOccludersSet(Grid& _grid) : grid (_grid) {}; Polygon3r *begin(); Polygon3r *next(); Polygon3r *next(bool stopOnNewCell); private: Polygon3r *firstOccluderFromNextCell(); Grid& grid; OccludersSet::iterator it, end; #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:VirtualOccludersSet") #endif }; } /* namespace Freestyle */ #endif // __GRID_H__