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