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