Nori  23
block.cpp
1 /*
2  This file is part of Nori, a simple educational ray tracer
3 
4  Copyright (c) 2015 by Wenzel Jakob, Romain Prévost
5 
6  Nori is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License Version 3
8  as published by the Free Software Foundation.
9 
10  Nori is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #include <nori/block.h>
20 #include <nori/bitmap.h>
21 #include <nori/rfilter.h>
22 #include <nori/bbox.h>
23 #include <tbb/tbb.h>
24 
25 NORI_NAMESPACE_BEGIN
26 
28  init(size,filter);
29 }
30 
32  delete[] m_filter;
33  delete[] m_weightsX;
34  delete[] m_weightsY;
35 }
36 
37 
38 void ImageBlock::init(const Vector2i &size, const ReconstructionFilter *filter) {
39  m_offset = Point2i(0, 0);
40  m_size = size;
41  m_borderSize = 0;
42  m_filterRadius = 0;
43  m_lookupFactor = 0;
44  m_blockId = 0;
45 
46  if(m_filter) {
47  delete[] m_filter;
48  delete[] m_weightsX;
49  delete[] m_weightsY;
50  m_filter = nullptr;
51  m_weightsX = nullptr;
52  m_weightsY = nullptr;
53  }
54  if (filter) {
55  /* Tabulate the image reconstruction filter for performance reasons */
56  m_filterRadius = filter->getRadius();
57  m_borderSize = (int) std::ceil(m_filterRadius - 0.5f);
58  m_filter = new float[NORI_FILTER_RESOLUTION + 1];
59  for (int i=0; i<NORI_FILTER_RESOLUTION; ++i) {
60  float pos = (m_filterRadius * i) / NORI_FILTER_RESOLUTION;
61  m_filter[i] = filter->eval(pos);
62  }
63  m_filter[NORI_FILTER_RESOLUTION] = 0.0f;
64  m_lookupFactor = NORI_FILTER_RESOLUTION / m_filterRadius;
65  int weightSize = (int) std::ceil(2*m_filterRadius) + 1;
66  m_weightsX = new float[weightSize];
67  m_weightsY = new float[weightSize];
68  memset(m_weightsX, 0, sizeof(float) * weightSize);
69  memset(m_weightsY, 0, sizeof(float) * weightSize);
70  }
71 
72  /* Allocate space for pixels and border regions */
73  resize(size.y() + 2*m_borderSize, size.x() + 2*m_borderSize);
74 }
75 
77  Bitmap *result = new Bitmap(m_size);
78  for (int y=0; y<m_size.y(); ++y)
79  for (int x=0; x<m_size.x(); ++x)
80  result->coeffRef(y, x) = coeff(y + m_borderSize, x + m_borderSize).divideByFilterWeight();
81  return result;
82 }
83 
84 void ImageBlock::fromBitmap(const Bitmap &bitmap) {
85  if (bitmap.cols() != cols() || bitmap.rows() != rows())
86  throw NoriException("Invalid bitmap dimensions!");
87 
88  for (int y=0; y<m_size.y(); ++y)
89  for (int x=0; x<m_size.x(); ++x)
90  coeffRef(y, x) << bitmap.coeff(y, x), 1;
91 }
92 
93 void ImageBlock::put(const Point2f &_pos, const Color3f &value) {
94  if (!value.isValid()) {
95  /* If this happens, go fix your code instead of removing this warning ;) */
96  cerr << "Integrator: computed an invalid radiance value: " << value.toString() << endl;
97  return;
98  }
99 
100  /* Convert to pixel coordinates within the image block */
101  Point2f pos(
102  _pos.x() - 0.5f - (m_offset.x() - m_borderSize),
103  _pos.y() - 0.5f - (m_offset.y() - m_borderSize)
104  );
105 
106  /* Compute the rectangle of pixels that will need to be updated */
107  BoundingBox2i bbox(
108  Point2i((int) std::ceil(pos.x() - m_filterRadius), (int) std::ceil(pos.y() - m_filterRadius)),
109  Point2i((int) std::floor(pos.x() + m_filterRadius), (int) std::floor(pos.y() + m_filterRadius))
110  );
111  bbox.clip(BoundingBox2i(Point2i(0, 0), Point2i((int) cols() - 1, (int) rows() - 1)));
112 
113  /* Lookup values from the pre-rasterized filter */
114  for (int x=bbox.min.x(), idx = 0; x<=bbox.max.x(); ++x)
115  m_weightsX[idx++] = m_filter[(int) (std::abs(x-pos.x()) * m_lookupFactor)];
116  for (int y=bbox.min.y(), idx = 0; y<=bbox.max.y(); ++y)
117  m_weightsY[idx++] = m_filter[(int) (std::abs(y-pos.y()) * m_lookupFactor)];
118 
119  for (int y=bbox.min.y(), yr=0; y<=bbox.max.y(); ++y, ++yr)
120  for (int x=bbox.min.x(), xr=0; x<=bbox.max.x(); ++x, ++xr)
121  coeffRef(y, x) += Color4f(value) * m_weightsX[xr] * m_weightsY[yr];
122 }
123 
125  Vector2i offset = b.getOffset() - m_offset +
126  Vector2i::Constant(m_borderSize - b.getBorderSize());
127  Vector2i size = b.getSize() + Vector2i(2*b.getBorderSize());
128 
129  tbb::mutex::scoped_lock lock(m_mutex);
130 
131  block(offset.y(), offset.x(), size.y(), size.x())
132  += b.topLeftCorner(size.y(), size.x());
133 }
134 
135 std::string ImageBlock::toString() const {
136  return tfm::format("ImageBlock[offset=%s, size=%s]]",
137  m_offset.toString(), m_size.toString());
138 }
139 
140 BlockGenerator::BlockGenerator(const Vector2i &size, int blockSize)
141  : m_size(size), m_blockSize(blockSize) {
142  m_numBlocks = Vector2i(
143  (int) std::ceil(size.x() / (float) blockSize),
144  (int) std::ceil(size.y() / (float) blockSize));
145  reset();
146 }
147 
149  m_blocksLeft = m_numBlocks.x() * m_numBlocks.y();
150  m_direction = ERight;
151  m_block = Point2i(m_numBlocks / 2);
152  m_stepsLeft = 1;
153  m_numSteps = 1;
154 }
155 
157  tbb::mutex::scoped_lock lock(m_mutex);
158 
159  if (m_blocksLeft == 0)
160  return false;
161 
162  Point2i pos = m_block * m_blockSize;
163  block.setOffset(pos);
164  block.setSize((m_size - pos).cwiseMin(Vector2i::Constant(m_blockSize)));
165  block.setBlockId(m_block.y() * m_numBlocks.x() + m_block.x());
166 
167  if (--m_blocksLeft == 0)
168  return true;
169 
170  do {
171  switch (m_direction) {
172  case ERight: ++m_block.x(); break;
173  case EDown: ++m_block.y(); break;
174  case ELeft: --m_block.x(); break;
175  case EUp: --m_block.y(); break;
176  }
177 
178  if (--m_stepsLeft == 0) {
179  m_direction = (m_direction + 1) % 4;
180  if (m_direction == ELeft || m_direction == ERight)
181  ++m_numSteps;
182  m_stepsLeft = m_numSteps;
183  }
184  } while ((m_block.array() < 0).any() ||
185  (m_block.array() >= m_numBlocks.array()).any());
186 
187  return true;
188 }
189 
190 NORI_NAMESPACE_END
Stores a RGB high dynamic-range bitmap.
Definition: bitmap.h:32
BlockGenerator(const Vector2i &size, int blockSize)
Create a block generator with.
Definition: block.cpp:140
void reset()
Reset to the first block.
Definition: block.cpp:148
bool next(ImageBlock &block)
Return the next block to be rendered.
Definition: block.cpp:156
Weighted pixel storage for a rectangular subregion of an image.
Definition: block.h:48
void put(const Point2f &pos, const Color3f &value)
Record a sample with the given position and radiance value.
Definition: block.cpp:93
ImageBlock(const Vector2i &size, const ReconstructionFilter *filter)
Definition: block.cpp:27
const Vector2i & getSize() const
Return the size of the block within the main image.
Definition: block.h:75
void fromBitmap(const Bitmap &bitmap)
Convert a bitmap into an image block.
Definition: block.cpp:84
int getBorderSize() const
Return the border size in pixels.
Definition: block.h:78
~ImageBlock()
Release all memory.
Definition: block.cpp:31
void lock() const
Lock the image block (using an internal mutex)
Definition: block.h:109
std::string toString() const
Return a human-readable string summary.
Definition: block.cpp:135
void setSize(const Point2i &size)
Configure the size of the block within the main image.
Definition: block.h:72
Bitmap * toBitmap() const
Turn the block into a proper bitmap.
Definition: block.cpp:76
void setOffset(const Point2i &offset)
Configure the offset of the block within the main image.
Definition: block.h:66
const Point2i & getOffset() const
Return the offset of the block within the main image.
Definition: block.h:69
Simple exception class, which stores a human-readable error description.
Definition: common.h:148
Generic radially symmetric image reconstruction filter.
Definition: rfilter.h:41
virtual float eval(float x) const =0
Evaluate the filter function.
float getRadius() const
Return the filter radius in fractional pixels.
Definition: rfilter.h:44
Represents a linear RGB color value.
Definition: color.h:29
bool isValid() const
Check if the color vector contains a NaN/Inf/negative value.
Definition: common.cpp:224
std::string toString() const
Return a human-readable string summary.
Definition: color.h:79
Represents a linear RGB color and a weight.
Definition: color.h:89
Generic n-dimensional bounding box data structure.
Definition: bbox.h:42
void clip(const TBoundingBox &bbox)
Clip to another bounding box.
Definition: bbox.h:270
PointType max
Component-wise maximum.
Definition: bbox.h:396
PointType min
Component-wise minimum.
Definition: bbox.h:395
std::string toString() const
Return a human-readable string summary.
Definition: vector.h:119
std::string toString() const
Return a human-readable string summary.
Definition: vector.h:71