1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 #pragma once
18 
19 /** \file
20  * \ingroup freestyle
21  * \brief Base class to define a cell grid surrounding the bounding box of the scene
22  */
23 
24 #include <cstring>  // for memset
25 #include <float.h>
26 #include <stdint.h>  // For POINTER_FROM_UINT, i.e. uintptr_t.
27 #include <vector>
28 
29 #include "Geom.h"
30 #include "GeomUtils.h"
31 #include "Polygon.h"
32 
33 #include "../system/FreestyleConfig.h"
34 
35 #include "BLI_utildefines.h"
36 
37 #ifdef WITH_CXX_GUARDEDALLOC
38 #  include "MEM_guardedalloc.h"
39 #endif
40 
41 using namespace std;
42 
43 namespace Freestyle {
44 
45 using namespace Geometry;
46 
47 typedef vector<Polygon3r *> OccludersSet;
48 
49 //
50 // Class to define cells used by the regular grid
51 //
52 ///////////////////////////////////////////////////////////////////////////////
53 
54 class Cell {
55  public:
Cell(Vec3r & orig)56   Cell(Vec3r &orig)
57   {
58     _orig = orig;
59   }
60 
~Cell()61   virtual ~Cell()
62   {
63   }
64 
addOccluder(Polygon3r * o)65   inline void addOccluder(Polygon3r *o)
66   {
67     if (o) {
68       _occluders.push_back(o);
69     }
70   }
71 
getOrigin()72   inline const Vec3r &getOrigin()
73   {
74     return _orig;
75   }
76 
getOccluders()77   inline OccludersSet &getOccluders()
78   {
79     return _occluders;
80   }
81 
82  private:
83   Vec3r _orig;
84   OccludersSet _occluders;
85 
86 #ifdef WITH_CXX_GUARDEDALLOC
87   MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:Cell")
88 #endif
89 };
90 
91 class GridVisitor {
92  public:
~GridVisitor()93   virtual ~GridVisitor(){};  // soc
94 
discoverCell(Cell *)95   virtual void discoverCell(Cell * /*cell*/)
96   {
97   }
98 
examineOccluder(Polygon3r *)99   virtual void examineOccluder(Polygon3r * /*occ*/)
100   {
101   }
102 
finishCell(Cell *)103   virtual void finishCell(Cell * /*cell*/)
104   {
105   }
106 
stop()107   virtual bool stop()
108   {
109     return false;
110   }
111 
112 #ifdef WITH_CXX_GUARDEDALLOC
113   MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:GridVisitor")
114 #endif
115 };
116 
117 /*! Gathers all the occluders belonging to the cells traversed by the ray */
118 class allOccludersGridVisitor : public GridVisitor {
119  public:
allOccludersGridVisitor(OccludersSet & occluders)120   allOccludersGridVisitor(OccludersSet &occluders) : GridVisitor(), occluders_(occluders)
121   {
122   }
123 
124   virtual void examineOccluder(Polygon3r *occ);
125 
occluders()126   OccludersSet &occluders()
127   {
128     return occluders_;
129   }
130 
clear()131   void clear()
132   {
133     occluders_.clear();
134   }
135 
136  private:
137   OccludersSet &occluders_;
138 };
139 
140 /*! Finds the first intersection and breaks.
141  *  The occluder and the intersection information are stored and accessible.
142  */
143 class firstIntersectionGridVisitor : public GridVisitor {
144   // soc - changed order to remove warnings
145  public:
146   double u_, v_, t_;
147 
148  private:
149   Polygon3r *occluder_;
150   Vec3r ray_org_, ray_dir_, cell_size_;
151   Cell *current_cell_;
152 
153  public:
firstIntersectionGridVisitor(const Vec3r & ray_org,const Vec3r & ray_dir,const Vec3r & cell_size)154   firstIntersectionGridVisitor(const Vec3r &ray_org, const Vec3r &ray_dir, const Vec3r &cell_size)
155       : GridVisitor(),
156         u_(0),
157         v_(0),
158         t_(DBL_MAX),
159         occluder_(0),
160         ray_org_(ray_org),
161         ray_dir_(ray_dir),
162         cell_size_(cell_size),
163         current_cell_(0)
164   {
165   }
166 
~firstIntersectionGridVisitor()167   virtual ~firstIntersectionGridVisitor()
168   {
169   }
170 
discoverCell(Cell * cell)171   virtual void discoverCell(Cell *cell)
172   {
173     current_cell_ = cell;
174   }
175 
176   virtual void examineOccluder(Polygon3r *occ);
177 
178   virtual bool stop();
179 
occluder()180   Polygon3r *occluder()
181   {
182     return occluder_;
183   }
184 };
185 
186 //
187 // Class to define a regular grid used for ray casting computations
188 //
189 ///////////////////////////////////////////////////////////////////////////////
190 
191 class Grid {
192  public:
193   /*! Builds a Grid. Must be followed by a call to configure() */
Grid()194   Grid()
195   {
196   }
197 
~Grid()198   virtual ~Grid()
199   {
200     clear();
201   }
202 
203   /*! clears the grid
204    *  Deletes all the cells, clears the hashtable, resets size, size of cell, number of cells.
205    */
206   virtual void clear();
207 
208   /*! Sets the different parameters of the grid
209    *    orig
210    *      The grid origin
211    *    size
212    *      The grid's dimensions
213    *    nb
214    *      The number of cells of the grid
215    */
216   virtual void configure(const Vec3r &orig, const Vec3r &size, unsigned nb);
217 
218   /*! returns a vector of integer containing the coordinates of the cell containing the point
219    * passed as argument
220    *    p
221    *      The point for which we're looking the cell
222    */
getCellCoordinates(const Vec3r & p,Vec3u & res)223   inline void getCellCoordinates(const Vec3r &p, Vec3u &res)
224   {
225     int tmp;
226     for (int i = 0; i < 3; i++) {
227       tmp = (int)((p[i] - _orig[i]) / _cell_size[i]);
228       if (tmp < 0) {
229         res[i] = 0;
230       }
231       else if ((unsigned int)tmp >= _cells_nb[i]) {
232         res[i] = _cells_nb[i] - 1;
233       }
234       else {
235         res[i] = tmp;
236       }
237     }
238   }
239 
240   /*! Fills the case corresponding to coord with the cell */
241   virtual void fillCell(const Vec3u &coord, Cell &cell) = 0;
242 
243   /*! returns the cell whose coordinates are passed as argument */
244   virtual Cell *getCell(const Vec3u &coord) = 0;
245 
246   /*! returns the cell containing the point passed as argument.
247    *  If the cell is empty (contains no occluder),  NULL is returned:
248    *    p
249    *      The point for which we're looking the cell
250    */
getCell(const Vec3r & p)251   inline Cell *getCell(const Vec3r &p)
252   {
253     Vec3u coord;
254     getCellCoordinates(p, coord);
255     return getCell(coord);
256   }
257 
258   /*! Retrieves the x,y,z coordinates of the origin of the cell whose coordinates (i,j,k)
259    *  is passed as argument:
260    *    cell_coord
261    *      i,j,k integer coordinates for the cell
262    *    orig
263    *      x,y,x vector to be filled in with the cell origin's coordinates
264    */
getCellOrigin(const Vec3u & cell_coord,Vec3r & orig)265   inline void getCellOrigin(const Vec3u &cell_coord, Vec3r &orig)
266   {
267     for (unsigned int i = 0; i < 3; i++) {
268       orig[i] = _orig[i] + cell_coord[i] * _cell_size[i];
269     }
270   }
271 
272   /*! Retrieves the box corresponding to the cell whose coordinates are passed as argument:
273    *    cell_coord
274    *      i,j,k integer coordinates for the cell
275    *    min_out
276    *      The min x,y,x vector of the box. Filled in by the method.
277    *    max_out
278    *      The max x,y,z coordinates of the box. Filled in by the method.
279    */
getCellBox(const Vec3u & cell_coord,Vec3r & min_out,Vec3r & max_out)280   inline void getCellBox(const Vec3u &cell_coord, Vec3r &min_out, Vec3r &max_out)
281   {
282     getCellOrigin(cell_coord, min_out);
283     max_out = min_out + _cell_size;
284   }
285 
286   /*! inserts a convex polygon occluder
287    *  This method is quite coarse insofar as it adds all cells intersecting the polygon bounding
288    * box convex_poly The list of 3D points constituting a convex polygon
289    */
290   void insertOccluder(Polygon3r *occluder);
291 
292   /*! Adds an occluder to the list of occluders */
addOccluder(Polygon3r * occluder)293   void addOccluder(Polygon3r *occluder)
294   {
295     _occluders.push_back(occluder);
296   }
297 
298   /*! Casts a ray between a starting point and an ending point
299    *  Returns the list of occluders contained in the cells intersected by this ray
300    *  Starts with a call to InitRay.
301    */
302   void castRay(const Vec3r &orig, const Vec3r &end, OccludersSet &occluders, unsigned timestamp);
303 
304   // Prepares to cast ray without generating OccludersSet
305   void initAcceleratedRay(const Vec3r &orig, const Vec3r &end, unsigned timestamp);
306 
307   /*! Casts an infinite ray (still finishing at the end of the grid) from a starting point and in a
308    * given direction. Returns the list of occluders contained in the cells intersected by this ray
309    *  Starts with a call to InitRay.
310    */
311   void castInfiniteRay(const Vec3r &orig,
312                        const Vec3r &dir,
313                        OccludersSet &occluders,
314                        unsigned timestamp);
315 
316   // Prepares to cast ray without generating OccludersSet.
317   bool initAcceleratedInfiniteRay(const Vec3r &orig, const Vec3r &dir, unsigned timestamp);
318 
319   /*! Casts an infinite ray (still finishing at the end of the grid) from a starting point and in a
320    * given direction. Returns the first intersection (occluder,t,u,v) or null. Starts with a call
321    * to InitRay.
322    */
323   Polygon3r *castRayToFindFirstIntersection(
324       const Vec3r &orig, const Vec3r &dir, double &t, double &u, double &v, unsigned timestamp);
325 
326   /*! Init all structures and values for computing the cells intersected by this new ray */
327   void initRay(const Vec3r &orig, const Vec3r &end, unsigned timestamp);
328 
329   /*! Init all structures and values for computing the cells intersected by this infinite ray.
330    * Returns false if the ray doesn't intersect the grid.
331    */
332   bool initInfiniteRay(const Vec3r &orig, const Vec3r &dir, unsigned timestamp);
333 
334   /*! Accessors */
getOrigin()335   inline const Vec3r &getOrigin() const
336   {
337     return _orig;
338   }
339 
gridSize()340   inline Vec3r gridSize() const
341   {
342     return _size;
343   }
344 
getCellSize()345   inline Vec3r getCellSize() const
346   {
347     return _cell_size;
348   }
349 
350   // ARB profiling only:
getOccluders()351   inline OccludersSet *getOccluders()
352   {
353     return &_occluders;
354   }
355 
displayDebug()356   void displayDebug()
357   {
358     cerr << "Cells nb     : " << _cells_nb << endl;
359     cerr << "Cell size    : " << _cell_size << endl;
360     cerr << "Origin       : " << _orig << endl;
361     cerr << "Occluders nb : " << _occluders.size() << endl;
362   }
363 
364  protected:
365   /*! Core of castRay and castInfiniteRay, find occluders along the given ray */
castRayInternal(GridVisitor & visitor)366   inline void castRayInternal(GridVisitor &visitor)
367   {
368     Cell *current_cell = NULL;
369     do {
370       current_cell = getCell(_current_cell);
371       if (current_cell) {
372         visitor.discoverCell(current_cell);
373         OccludersSet &occluders =
374             current_cell->getOccluders();  // FIXME: I had forgotten the ref &
375         for (OccludersSet::iterator it = occluders.begin(); it != occluders.end(); it++) {
376           if (POINTER_AS_UINT((*it)->userdata2) != _timestamp) {
377             (*it)->userdata2 = POINTER_FROM_UINT(_timestamp);
378             visitor.examineOccluder(*it);
379           }
380         }
381         visitor.finishCell(current_cell);
382       }
383     } while ((!visitor.stop()) && (nextRayCell(_current_cell, _current_cell)));
384   }
385 
386   /*! returns the  cell next to the cell passed as argument. */
387   bool nextRayCell(Vec3u &current_cell, Vec3u &next_cell);
388 
389   unsigned int _timestamp;
390 
391   Vec3u _cells_nb;   // number of cells for x,y,z axis
392   Vec3r _cell_size;  // cell x,y,z dimensions
393   Vec3r _size;       // grid x,y,x dimensions
394   Vec3r _orig;       // grid origin
395 
396   Vec3r _ray_dir;       // direction vector for the ray
397   Vec3u _current_cell;  // The current cell being processed (designated by its 3 coordinates)
398   Vec3r _pt;    // Points corresponding to the incoming and outgoing intersections of one cell with
399                 // the ray
400   real _t_end;  // To know when we are at the end of the ray
401   real _t;
402 
403   // OccludersSet _ray_occluders; // Set storing the occluders contained in the cells traversed by
404   // a ray
405   OccludersSet _occluders;  // List of all occluders inserted in the grid
406 
407 #ifdef WITH_CXX_GUARDEDALLOC
408   MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:Grid")
409 #endif
410 };
411 
412 //
413 // Class to walk through occluders in grid without building intermediate data structures
414 //
415 ///////////////////////////////////////////////////////////////////////////////
416 
417 class VirtualOccludersSet {
418  public:
VirtualOccludersSet(Grid & _grid)419   VirtualOccludersSet(Grid &_grid) : grid(_grid){};
420   Polygon3r *begin();
421   Polygon3r *next();
422   Polygon3r *next(bool stopOnNewCell);
423 
424  private:
425   Polygon3r *firstOccluderFromNextCell();
426   Grid &grid;
427   OccludersSet::iterator it, end;
428 
429 #ifdef WITH_CXX_GUARDEDALLOC
430   MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:VirtualOccludersSet")
431 #endif
432 };
433 
434 } /* namespace Freestyle */
435