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 ¤t_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