Files
test/source/blender/freestyle/intern/geometry/Grid.h
Campbell Barton e955c94ed3 License Headers: Set copyright to "Blender Authors", add AUTHORS
Listing the "Blender Foundation" as copyright holder implied the Blender
Foundation holds copyright to files which may include work from many
developers.

While keeping copyright on headers makes sense for isolated libraries,
Blender's own code may be refactored or moved between files in a way
that makes the per file copyright holders less meaningful.

Copyright references to the "Blender Foundation" have been replaced with
"Blender Authors", with the exception of `./extern/` since these this
contains libraries which are more isolated, any changed to license
headers there can be handled on a case-by-case basis.

Some directories in `./intern/` have also been excluded:

- `./intern/cycles/` it's own `AUTHORS` file is planned.
- `./intern/opensubdiv/`.

An "AUTHORS" file has been added, using the chromium projects authors
file as a template.

Design task: #110784

Ref !110783.
2023-08-16 00:20:26 +10:00

409 lines
11 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
/** \file
* \ingroup freestyle
* \brief Base class to define a cell grid surrounding the bounding box of the scene
*/
#include <cstring> // for memset
#include <float.h>
#include <stdint.h> // For POINTER_FROM_UINT, i.e. uintptr_t.
#include <vector>
#include "Geom.h"
#include "GeomUtils.h"
#include "Polygon.h"
#include "../system/FreestyleConfig.h"
#include "BLI_utildefines.h"
#ifdef WITH_CXX_GUARDEDALLOC
# include "MEM_guardedalloc.h"
#endif
using namespace std;
namespace Freestyle {
using namespace Geometry;
typedef vector<Polygon3r *> 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 hash-table, 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, uint 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 ((uint)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 passed 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), nullptr 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 (uint 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 *occluder);
/** 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, uint timestamp);
// Prepares to cast ray without generating OccludersSet
void initAcceleratedRay(const Vec3r &orig, const Vec3r &end, uint 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,
uint timestamp);
// Prepares to cast ray without generating OccludersSet.
bool initAcceleratedInfiniteRay(const Vec3r &orig, const Vec3r &dir, uint 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, uint timestamp);
/** Init all structures and values for computing the cells intersected by this new ray */
void initRay(const Vec3r &orig, const Vec3r &end, uint 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, uint 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 = nullptr;
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 (POINTER_AS_UINT((*it)->userdata2) != _timestamp) {
(*it)->userdata2 = POINTER_FROM_UINT(_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);
uint _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 */