Blender  V3.3
Canvas.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
8 #include <sstream>
9 #include <vector>
10 
11 #include "Canvas.h"
12 #include "StrokeRenderer.h"
13 #include "StyleModule.h"
14 
15 #include "../image/GaussianFilter.h"
16 #include "../image/Image.h"
17 #include "../image/ImagePyramid.h"
18 
19 #include "../system/FreestyleConfig.h"
20 #include "../system/PseudoNoise.h"
21 #include "../system/TimeStamp.h"
22 
23 #include "../view_map/SteerableViewMap.h"
24 
25 #include "BKE_global.h"
26 
27 // soc #include <qimage.h>
28 // soc #include <QString>
29 
30 #include "IMB_imbuf.h"
31 #include "IMB_imbuf_types.h"
32 
33 using namespace std;
34 
35 namespace Freestyle {
36 
37 Canvas *Canvas::_pInstance = nullptr;
38 
39 const char *Canvas::_MapsPath = nullptr;
40 
41 Canvas::Canvas()
42 {
43  _SelectedFEdge = nullptr;
44  _pInstance = this;
46  _Renderer = nullptr;
47  _current_sm = nullptr;
48  _steerableViewMap = new SteerableViewMap(NB_STEERABLE_VIEWMAP - 1);
49  _basic = false;
50 }
51 
52 Canvas::Canvas(const Canvas &iBrother)
53 {
54  _SelectedFEdge = iBrother._SelectedFEdge;
55  _pInstance = this;
57  _Renderer = iBrother._Renderer;
58  _current_sm = iBrother._current_sm;
59  _steerableViewMap = new SteerableViewMap(*(iBrother._steerableViewMap));
60  _basic = iBrother._basic;
61 }
62 
63 Canvas::~Canvas()
64 {
65  _pInstance = nullptr;
66 
67  Clear();
68  if (_Renderer) {
69  delete _Renderer;
70  _Renderer = nullptr;
71  }
72  // FIXME: think about an easy control for the maps memory management...
73  if (!_maps.empty()) {
74  for (mapsMap::iterator m = _maps.begin(), mend = _maps.end(); m != mend; ++m) {
75  delete ((*m).second);
76  }
77  _maps.clear();
78  }
79  delete _steerableViewMap;
80 }
81 
82 void Canvas::preDraw()
83 {
84 }
85 
86 void Canvas::Draw()
87 {
88  if (_StyleModules.empty()) {
89  return;
90  }
91  preDraw();
92  TimeStamp *timestamp = TimeStamp::instance();
93 
94  for (unsigned int i = 0; i < _StyleModules.size(); ++i) {
95  _current_sm = _StyleModules[i];
96 
97  if (i < _Layers.size() && _Layers[i]) {
98  delete _Layers[i];
99  }
100 
101  _Layers[i] = _StyleModules[i]->execute();
102  if (!_Layers[i]) {
103  continue;
104  }
105 
106  stroke_count += _Layers[i]->strokes_size();
107 
108  timestamp->increment();
109  }
110  postDraw();
111 }
112 
113 void Canvas::postDraw()
114 {
115  update();
116 }
117 
118 void Canvas::Clear()
119 {
120  if (!_Layers.empty()) {
121  for (deque<StrokeLayer *>::iterator sl = _Layers.begin(), slend = _Layers.end(); sl != slend;
122  ++sl) {
123  if (*sl) {
124  delete (*sl);
125  }
126  }
127  _Layers.clear();
128  }
129 
130  if (!_StyleModules.empty()) {
131  for (deque<StyleModule *>::iterator s = _StyleModules.begin(), send = _StyleModules.end();
132  s != send;
133  ++s) {
134  if (*s) {
135  delete (*s);
136  }
137  }
138  _StyleModules.clear();
139  }
140  if (_steerableViewMap) {
141  _steerableViewMap->Reset();
142  }
143 
144  stroke_count = 0;
145 }
146 
147 void Canvas::Erase()
148 {
149  if (!_Layers.empty()) {
150  for (deque<StrokeLayer *>::iterator sl = _Layers.begin(), slend = _Layers.end(); sl != slend;
151  ++sl) {
152  if (*sl) {
153  (*sl)->clear();
154  }
155  }
156  }
157  if (_steerableViewMap) {
158  _steerableViewMap->Reset();
159  }
160  update();
161 
162  stroke_count = 0;
163 }
164 
165 void Canvas::PushBackStyleModule(StyleModule *iStyleModule)
166 {
167  StrokeLayer *layer = new StrokeLayer();
168  _StyleModules.push_back(iStyleModule);
169  _Layers.push_back(layer);
170 }
171 
172 void Canvas::InsertStyleModule(unsigned index, StyleModule *iStyleModule)
173 {
174  unsigned size = _StyleModules.size();
175  StrokeLayer *layer = new StrokeLayer();
176  if ((_StyleModules.empty()) || (index == size)) {
177  _StyleModules.push_back(iStyleModule);
178  _Layers.push_back(layer);
179  return;
180  }
181  _StyleModules.insert(_StyleModules.begin() + index, iStyleModule);
182  _Layers.insert(_Layers.begin() + index, layer);
183 }
184 
185 void Canvas::RemoveStyleModule(unsigned index)
186 {
187  unsigned int i = 0;
188  if (!_StyleModules.empty()) {
189  for (deque<StyleModule *>::iterator s = _StyleModules.begin(), send = _StyleModules.end();
190  s != send;
191  ++s, ++i) {
192  if (i == index) {
193  // remove shader
194  if (*s) {
195  delete *s;
196  }
197  _StyleModules.erase(s);
198  break;
199  }
200  }
201  }
202 
203  if (!_Layers.empty()) {
204  i = 0;
205  for (deque<StrokeLayer *>::iterator sl = _Layers.begin(), slend = _Layers.end(); sl != slend;
206  ++sl, ++i) {
207  if (i == index) {
208  // remove layer
209  if (*sl) {
210  delete *sl;
211  }
212  _Layers.erase(sl);
213  break;
214  }
215  }
216  }
217 }
218 
219 void Canvas::SwapStyleModules(unsigned i1, unsigned i2)
220 {
221  StyleModule *tmp;
222  tmp = _StyleModules[i1];
223  _StyleModules[i1] = _StyleModules[i2];
224  _StyleModules[i2] = tmp;
225 
226  StrokeLayer *tmp2;
227  tmp2 = _Layers[i1];
228  _Layers[i1] = _Layers[i2];
229  _Layers[i2] = tmp2;
230 }
231 
232 void Canvas::ReplaceStyleModule(unsigned index, StyleModule *iStyleModule)
233 {
234  unsigned i = 0;
235  for (deque<StyleModule *>::iterator s = _StyleModules.begin(), send = _StyleModules.end();
236  s != send;
237  ++s, ++i) {
238  if (i == index) {
239  if (*s) {
240  delete *s;
241  }
242  *s = iStyleModule;
243  break;
244  }
245  }
246 }
247 
248 void Canvas::setVisible(unsigned index, bool iVisible)
249 {
250  _StyleModules[index]->setDisplayed(iVisible);
251 }
252 
253 void Canvas::setModified(unsigned index, bool iMod)
254 {
255  _StyleModules[index]->setModified(iMod);
256 }
257 
258 void Canvas::resetModified(bool iMod /* = false */)
259 {
260  unsigned int size = _StyleModules.size();
261  for (unsigned int i = 0; i < size; ++i) {
262  setModified(i, iMod);
263  }
264 }
265 
266 void Canvas::causalStyleModules(vector<unsigned> &vec, unsigned index)
267 {
268  unsigned int size = _StyleModules.size();
269 
270  for (unsigned int i = index; i < size; ++i) {
271  if (_StyleModules[i]->getCausal()) {
272  vec.push_back(i);
273  }
274  }
275 }
276 
277 void Canvas::Render(const StrokeRenderer *iRenderer)
278 {
279  for (unsigned int i = 0; i < _StyleModules.size(); ++i) {
280  if (!_StyleModules[i]->getDisplayed() || !_Layers[i]) {
281  continue;
282  }
283  _Layers[i]->Render(iRenderer);
284  }
285 }
286 
287 void Canvas::RenderBasic(const StrokeRenderer *iRenderer)
288 {
289  for (unsigned int i = 0; i < _StyleModules.size(); ++i) {
290  if (!_StyleModules[i]->getDisplayed() || !_Layers[i]) {
291  continue;
292  }
293  _Layers[i]->RenderBasic(iRenderer);
294  }
295 }
296 
297 void Canvas::loadMap(const char *iFileName,
298  const char *iMapName,
299  unsigned int iNbLevels,
300  float iSigma)
301 {
302  // check whether this map was already loaded:
303  if (!_maps.empty()) {
304  mapsMap::iterator m = _maps.find(iMapName);
305  if (m != _maps.end()) {
306  // lazy check for size changes
307  ImagePyramid *pyramid = (*m).second;
308  if ((pyramid->width() != width()) || (pyramid->height() != height())) {
309  delete pyramid;
310  }
311  else {
312  return;
313  }
314  }
315  }
316 
317  string filePath;
318  if (_MapsPath) {
319  filePath = _MapsPath;
320  filePath += iFileName;
321  }
322  else {
323  filePath = iFileName;
324  }
325 
326 #if 0 // soc
327  QImage *qimg;
328  QImage newMap(filePath.c_str());
329  if (newMap.isNull()) {
330  cerr << "Could not load image file " << filePath << endl;
331  return;
332  }
333  qimg = &newMap;
334 #endif
335  /* OCIO_TODO: support different input color space */
336  ImBuf *qimg = IMB_loadiffname(filePath.c_str(), 0, nullptr);
337  if (qimg == nullptr) {
338  cerr << "Could not load image file " << filePath << endl;
339  return;
340  }
341 
342 #if 0 // soc
343  // resize
344  QImage scaledImg;
345  if ((newMap.width() != width()) || (newMap.height() != height())) {
346  scaledImg = newMap.scaled(width(), height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
347  qimg = &scaledImg;
348  }
349 #endif
350  ImBuf *scaledImg;
351  if ((qimg->x != width()) || (qimg->y != height())) {
352  scaledImg = IMB_dupImBuf(qimg);
353  IMB_scaleImBuf(scaledImg, width(), height());
354  }
355 
356  // deal with color image
357 #if 0
358  if (newMap->depth() != 8) {
359  int w = newMap->width();
360  int h = newMap->height();
361  QImage *tmp = new QImage(w, h, 8);
362  for (unsigned int y = 0; y < h; ++y) {
363  for (unsigned int x = 0; x < w; ++x) {
364  int c = qGray(newMap->pixel(x, y));
365  tmp->setPixel(x, y, c);
366  }
367  }
368  delete newMap;
369  newMap = tmp;
370  }
371 #endif
372 
373  int x, y;
374  int w = qimg->x;
375  int h = qimg->y;
376  int rowbytes = w * 4;
377  GrayImage tmp(w, h);
378  char *pix;
379 
380  for (y = 0; y < h; ++y) {
381  for (x = 0; x < w; ++x) {
382  pix = (char *)qimg->rect + y * rowbytes + x * 4;
383  float c = (pix[0] * 11 + pix[1] * 16 + pix[2] * 5) / 32;
384  tmp.setPixel(x, y, c);
385  }
386  }
387 
388 #if 0
389  GrayImage blur(w, h);
390  GaussianFilter gf(4.0f);
391  //int bound = gf.getBound();
392  for (y = 0; y < h; ++y) {
393  for (x = 0; x < w; ++x) {
394  int c = gf.getSmoothedPixel<GrayImage>(&tmp, x, y);
395  blur.setPixel(x, y, c);
396  }
397  }
398 #endif
399 
400  GaussianPyramid *pyramid = new GaussianPyramid(tmp, iNbLevels, iSigma);
401  int ow = pyramid->width(0);
402  int oh = pyramid->height(0);
403  string base(iMapName); // soc
404  for (int i = 0; i < pyramid->getNumberOfLevels(); ++i) {
405  // save each image:
406 #if 0
407  w = pyramid.width(i);
408  h = pyramid.height(i);
409 #endif
410 
411  // soc QImage qtmp(ow, oh, QImage::Format_RGB32);
412  ImBuf *qtmp = IMB_allocImBuf(ow, oh, 32, IB_rect);
413 
414  // int k = (1 << i);
415  for (y = 0; y < oh; ++y) {
416  for (x = 0; x < ow; ++x) {
417  int c = pyramid->pixel(x, y, i); // 255 * pyramid->pixel(x, y, i);
418  // soc qtmp.setPixel(x, y, qRgb(c, c, c));
419  pix = (char *)qtmp->rect + y * rowbytes + x * 4;
420  pix[0] = pix[1] = pix[2] = c;
421  }
422  }
423  // soc qtmp.save(base + QString::number(i) + ".bmp", "BMP");
424  stringstream filename;
425  filename << base;
426  filename << i << ".bmp";
427  qtmp->ftype = IMB_FTYPE_BMP;
428  IMB_saveiff(qtmp, const_cast<char *>(filename.str().c_str()), 0);
429  }
430 
431 #if 0
432  QImage *qtmp = new QImage(w, h, 32);
433  for (y = 0; y < h; ++y) {
434  for (x = 0; x < w; ++x) {
435  int c = (int)blur.pixel(x, y);
436  qtmp->setPixel(x, y, qRgb(c, c, c));
437  }
438  }
439  delete newMap;
440  newMap = qtmp;
441 #endif
442 
443  _maps[iMapName] = pyramid;
444  // newMap->save("toto.bmp", "BMP");
445 }
446 
447 float Canvas::readMapPixel(const char *iMapName, int level, int x, int y)
448 {
449  if (_maps.empty()) {
450  if (G.debug & G_DEBUG_FREESTYLE) {
451  cout << "readMapPixel warning: no map was loaded " << endl;
452  }
453  return -1;
454  }
455  mapsMap::iterator m = _maps.find(iMapName);
456  if (m == _maps.end()) {
457  if (G.debug & G_DEBUG_FREESTYLE) {
458  cout << "readMapPixel warning: no map was loaded with the name " << iMapName << endl;
459  }
460  return -1;
461  }
462  ImagePyramid *pyramid = (*m).second;
463  if ((x < 0) || (x >= pyramid->width()) || (y < 0) || (y >= pyramid->height())) {
464  return 0;
465  }
466 
467  return pyramid->pixel(x, height() - 1 - y, level);
468 }
469 
470 } /* namespace Freestyle */
@ G_DEBUG_FREESTYLE
Definition: BKE_global.h:181
Class to define a canvas designed to draw style modules.
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint i1
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
bool IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy)
Definition: scaling.c:1644
struct ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
Definition: allocimbuf.c:500
struct ImBuf * IMB_dupImBuf(const struct ImBuf *ibuf1)
struct ImBuf * IMB_loadiffname(const char *filepath, int flags, char colorspace[IM_MAX_SPACE])
Definition: readimage.c:209
bool IMB_saveiff(struct ImBuf *ibuf, const char *filepath, int flags)
Definition: writeimage.c:22
Contains defines and structs used throughout the imbuf module.
@ IB_rect
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object instance
struct Render Render
Definition: RE_pipeline.h:39
Classes to render a stroke with OpenGL.
Class representing a style module.
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
FEdge * _SelectedFEdge
Definition: Canvas.h:67
SteerableViewMap * _steerableViewMap
Definition: Canvas.h:73
StyleModule * _current_sm
Definition: Canvas.h:70
StrokeRenderer * _Renderer
Definition: Canvas.h:69
float getSmoothedPixel(Map *map, int x, int y)
float pixel(unsigned x, unsigned y) const
void setPixel(unsigned x, unsigned y, float v)
virtual float pixel(int x, int y, int level=0)
int getNumberOfLevels() const
Definition: ImagePyramid.h:61
virtual int height(int level=0)
virtual int width(int level=0)
void setDisplayed(bool b=true)
Definition: StyleModule.h:148
@ IMB_FTYPE_BMP
#define G(x, y, z)
inherits from class Rep
Definition: AppCanvas.cpp:18
static unsigned c
Definition: RandGen.cpp:83
static void update(bNodeTree *ntree)
enum eImbFileType ftype
unsigned int * rect