1
2
3 // System-core includes
4 #include "tsystem.h" //Processors count
5 #include "timagecache.h"
6 #include "tw/stringtable.h"
7
8 // Toonz scene-stage structures
9 #include "toonz/toonzscene.h"
10 #include "toonz/tscenehandle.h"
11 #include "toonz/sceneproperties.h"
12 #include "toonz/tframehandle.h"
13 #include "toonz/tfxhandle.h"
14 #include "toonz/tpalettehandle.h"
15 #include "toonz/txshlevel.h"
16 #include "toonz/txshlevelhandle.h"
17 #include "toonz/txsheethandle.h"
18 #include "toonz/tobjecthandle.h"
19 #include "toonz/tstageobjecttree.h"
20 #include "toonz/tcamera.h"
21 #include "toonz/palettecontroller.h"
22 #include "tapp.h" //Toonz current objects
23
24 // Images stuff
25 #include "trasterimage.h"
26 #include "trop.h"
27
28 // Fxs stuff
29 #include "toutputproperties.h"
30 #include "trasterfx.h"
31 #include "toonz/scenefx.h" //Fxs tree build-up
32 #include "toonz/tcolumnfx.h"
33
34 // Cache management
35 #include "tpassivecachemanager.h"
36
37 // Flipbook
38 #include "flipbook.h"
39 #include "toonzqt/flipconsole.h"
40
41 // Qt stuff
42 #include <QMetaType>
43 #include <QRegion>
44 #include "toonzqt/gutil.h" //For converions between TRects and QRects
45
46 // Preferences
47 #include "toonz/preferences.h"
48
49 #include "previewfxmanager.h"
50
51 //=======================================================================================================
52
53 // Resume: The 'Preview Fx' command shows a flipbook associated with given fx,
54 // containing the appearance
55 // of the fx under current rendering status (including current camera,
56 // preview settings, schematic tree).
57 //
58 // There are some considerations to be aware of:
59 // 1. A Preview Fx flipbook must hold the render of the whole Preview settings
60 // range. Plus, many Preview Fx
61 // could live altogether. It could be that more than one Preview Fx window
62 // is active for the same fx.
63 // 2. The flipbook associated with a 'Preview Fx' command should react to
64 // updates of the rendering status.
65 // This should happen as long as the fx actually has a meaning in the
66 // rendering context - that is, if
67 // the user enters sub- or super-xsheets, the flipbook should continue
68 // rendering with
69 // the old data. Possibly, if modifying a sub-xsheet, an 'upper' Preview Fx
70 // should react accordingly.
71 // 3. Fx Subtree aliases retrieved through TRasterFx::getAlias() may be used
72 // to decide if some frame has to
73 // be rebuilt.
74
75 //=======================================================================================================
76
77 // Forward declarations
78 class PreviewFxInstance;
79
80 //=======================================================================================================
81
82 //==============================
83 // Preliminary functions
84 //------------------------------
85
86 namespace {
87 bool suspendedRendering = false;
88 PreviewFxManager *previewerInstance = 0;
89
90 // Timer used to deliver scene changes notifications in an 'overridden' fashion.
91 // In practice, only the last (up to a fixed time granularity) of these
92 // notifications
93 // is actually received by the manager's associated slots.
94 QTimer levelChangedTimer, fxChangedTimer, xsheetChangedTimer,
95 objectChangedTimer;
96 const int notificationDelay = 300;
97
98 //----------------------------------------------------------------------------
99
getCacheId(const TFxP & fx,int frame)100 inline std::string getCacheId(const TFxP &fx, int frame) {
101 return std::to_string(fx->getIdentifier()) + ".noext" + std::to_string(frame);
102 }
103
104 //----------------------------------------------------------------------------
105
106 // NOTE: This method will not currently trespass xsheet level boundaries. It
107 // will not
108 // recognize descendants in sub-xsheets....
areAncestorAndDescendant(const TFxP & ancestor,const TFxP & descendant)109 bool areAncestorAndDescendant(const TFxP &ancestor, const TFxP &descendant) {
110 if (ancestor.getPointer() == descendant.getPointer()) return true;
111
112 int i;
113 for (i = 0; i < ancestor->getInputPortCount(); ++i)
114 if (areAncestorAndDescendant(ancestor->getInputPort(i)->getFx(),
115 descendant))
116 return true;
117
118 return false;
119 }
120
121 //----------------------------------------------------------------------------
122
123 // Qt's contains actually returns QRegion::intersected... I wonder why...
contains(const QRegion & region,const TRect & rect)124 inline bool contains(const QRegion ®ion, const TRect &rect) {
125 return QRegion(toQRect(rect)).subtracted(region).isEmpty();
126 }
127
128 //----------------------------------------------------------------------------
129
adaptView(FlipBook * flipbook,TDimension cameraSize)130 inline void adaptView(FlipBook *flipbook, TDimension cameraSize) {
131 TRect imgRect(cameraSize);
132 flipbook->getImageViewer()->adaptView(imgRect, imgRect);
133 }
134 }; // namespace
135
136 //=======================================================================================================
137
138 //==================================
139 // PreviewFxRenderPort class
140 //----------------------------------
141
142 //! This class receives and handles notifications from a TRenderer executing the
143 //! preview fx
144 //! rendering job.
145 class PreviewFxRenderPort final : public QObject, public TRenderPort {
146 PreviewFxInstance *m_owner;
147
148 public:
149 PreviewFxRenderPort(PreviewFxInstance *owner);
150 ~PreviewFxRenderPort();
151
152 void onRenderRasterStarted(
153 const TRenderPort::RenderData &renderData) override;
154 void onRenderRasterCompleted(const RenderData &renderData) override;
155 void onRenderFailure(const RenderData &renderData, TException &e) override;
156 void onRenderFinished(bool inCanceled = false) override;
157 };
158
159 //----------------------------------------------------------------------------------------
160
PreviewFxRenderPort(PreviewFxInstance * owner)161 PreviewFxRenderPort::PreviewFxRenderPort(PreviewFxInstance *owner)
162 : m_owner(owner) {}
163
164 //----------------------------------------------------------------------------------------
165
~PreviewFxRenderPort()166 PreviewFxRenderPort::~PreviewFxRenderPort() {}
167
168 //=======================================================================================================
169
170 //==========================
171 // PreviewFxInstance
172 //--------------------------
173
174 class PreviewFxInstance {
175 public:
176 struct FrameInfo {
177 std::string m_alias;
178 QRegion m_renderedRegion;
179
FrameInfoPreviewFxInstance::FrameInfo180 FrameInfo(const std::string &alias) : m_alias(alias) {}
181 };
182
183 public:
184 TXsheetP m_xsheet;
185 TRasterFxP m_fx;
186 TRenderer m_renderer;
187 PreviewFxRenderPort m_renderPort;
188
189 std::set<FlipBook *> m_flipbooks;
190 std::set<FlipBook *> m_frozenFlips; // Used externally by PreviewFxManager
191
192 int m_start, m_end, m_step, m_initFrame;
193 std::map<int, FrameInfo> m_frameInfos; // Used to resume fx tree structures
194 std::vector<UCHAR> m_pbStatus;
195
196 TRenderSettings m_renderSettings;
197 TDimension m_cameraRes;
198 TRectD m_renderArea;
199 TPointD m_cameraPos;
200 TPointD m_subcameraDisplacement;
201 bool m_subcamera;
202
203 QRegion m_overallRenderedRegion;
204 TRect m_rectUnderRender;
205 bool m_renderFailed;
206
207 TLevelP m_level;
208 TSoundTrackP m_snd;
209
210 public:
211 PreviewFxInstance(TFxP fx, TXsheet *xsh);
212 ~PreviewFxInstance();
213
214 void addFlipbook(FlipBook *&flipbook);
215 void detachFlipbook(FlipBook *flipbook);
216 void updateFlipbooks();
217
218 void refreshViewRects(bool rebuild = false);
219
220 void reset();
221 void reset(int frame);
222
223 // Updater methods. These refresh the manager's status, but do not launch new
224 // renders
225 // on their own. The refreshViewRects method must be invoked to trigger it.
226 // Observe that there may exist dependencies among them - invoking in the
227 // following
228 // declaration order is safe.
229 void updateFrameRange();
230 void updateInitialFrame();
231 void updateRenderSettings();
232 void updateCamera();
233 void updateFlipbookTitles();
234 void updatePreviewRect();
235
236 void updateAliases();
237 void updateAliasKeyword(const std::string &keyword);
238
239 void updateProgressBarStatus();
240
241 void onRenderRasterStarted(const TRenderPort::RenderData &renderData);
242 void onRenderRasterCompleted(const TRenderPort::RenderData &renderData);
243 void onRenderFailure(const TRenderPort::RenderData &renderData,
244 TException &e);
245 void onRenderFinished(bool isCanceled = false);
246
247 void doOnRenderRasterCompleted(const TRenderPort::RenderData &renderData);
248 void doOnRenderRasterStarted(const TRenderPort::RenderData &renderData);
249
isSubCameraActive()250 bool isSubCameraActive() { return m_subcamera; }
251
252 private:
253 void cropAndStep(int &frame);
254
255 bool isFullPreview();
256 TFxP buildSceneFx(int frame);
257
258 void addRenderData(std::vector<TRenderer::RenderData> &datas,
259 ToonzScene *scene, int frame, bool rebuild);
260 void startRender(bool rebuild = false);
261 };
262
263 //------------------------------------------------------------------
264
isFullPreview()265 inline bool PreviewFxInstance::isFullPreview() {
266 return dynamic_cast<TOutputFx *>((TFx *)m_fx.getPointer());
267 }
268
269 //------------------------------------------------------------------
270
cropAndStep(int & frame)271 inline void PreviewFxInstance::cropAndStep(int &frame) {
272 frame = frame < m_start ? m_start : frame;
273 frame = (frame > m_end && m_end > -1) ? m_end : frame;
274
275 // If a step was specified, ensure that frame is on step multiples.
276 int framePos = (frame - m_start) / m_step;
277 frame = m_start + (framePos * m_step);
278 }
279
280 //------------------------------------------------------------------
281
buildSceneFx(int frame)282 inline TFxP PreviewFxInstance::buildSceneFx(int frame) {
283 TApp *app = TApp::instance();
284 ToonzScene *scene = app->getCurrentScene()->getScene();
285
286 if (isFullPreview())
287 return ::buildSceneFx(scene, m_xsheet.getPointer(), frame,
288 m_renderSettings.m_shrinkX, true);
289 else
290 return ::buildPartialSceneFx(scene, m_xsheet.getPointer(), frame, m_fx,
291 m_renderSettings.m_shrinkX, true);
292 }
293
294 //------------------------------------------------------------------
295
addRenderData(std::vector<TRenderer::RenderData> & datas,ToonzScene * scene,int frame,bool rebuild)296 void PreviewFxInstance::addRenderData(std::vector<TRenderer::RenderData> &datas,
297 ToonzScene *scene, int frame,
298 bool rebuild) {
299 // Seek the image associated to the render data in the cache.
300 std::map<int, FrameInfo>::iterator it;
301 it = m_frameInfos.find(frame);
302
303 TRasterFxP builtFx =
304 buildSceneFx(frame); // when stereoscopic, i use this only for the alias
305 TRasterFxP builtFxA, builtFxB;
306
307 if (m_renderSettings.m_stereoscopic) {
308 ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
309 scene->shiftCameraX(-m_renderSettings.m_stereoscopicShift / 2);
310 builtFxA = buildSceneFx(frame);
311 scene->shiftCameraX(m_renderSettings.m_stereoscopicShift);
312 builtFxB = buildSceneFx(frame);
313 scene->shiftCameraX(-m_renderSettings.m_stereoscopicShift / 2);
314 } else
315 builtFxA = builtFx;
316
317 if (it == m_frameInfos.end()) {
318 // Should not be - however, in this case build an associated Frame info
319 it = m_frameInfos.insert(std::make_pair(frame, FrameInfo(std::string())))
320 .first;
321 it->second.m_alias =
322 builtFx ? builtFx->getAlias(frame, m_renderSettings) : "";
323 }
324
325 bool isCalculated =
326 (!builtFx) || ((!rebuild) && ::contains(it->second.m_renderedRegion,
327 m_rectUnderRender));
328
329 m_pbStatus[(frame - m_start) / m_step] = isCalculated
330 ? FlipSlider::PBFrameFinished
331 : FlipSlider::PBFrameNotStarted;
332
333 // If it is already present, return
334 if (isCalculated) return;
335
336 datas.push_back(TRenderer::RenderData(frame, m_renderSettings,
337 TFxPair(builtFxA, builtFxB)));
338 }
339
340 //-----------------------------------------------------------------------------------------
341
PreviewFxInstance(TFxP fx,TXsheet * xsh)342 PreviewFxInstance::PreviewFxInstance(TFxP fx, TXsheet *xsh)
343 : m_renderer(TSystem::getProcessorCount())
344 , m_renderPort(this)
345 , m_fx(fx)
346 , m_cameraRes(0, 0)
347 , m_start(0)
348 , m_end(-1)
349 , m_initFrame(0)
350 , m_xsheet(xsh) {
351 // Install the render port on the instance renderer
352 m_renderer.addPort(&m_renderPort);
353
354 updateRenderSettings();
355 updateCamera();
356 updateFrameRange();
357 updateAliases();
358 }
359
360 //----------------------------------------------------------------------------------------
361
~PreviewFxInstance()362 PreviewFxInstance::~PreviewFxInstance() {
363 // Stop the render - there is no need to wait for a complete (and blocking)
364 // render stop.
365 m_renderer.removePort(
366 &m_renderPort); // No more images to be stored in the cache!
367 m_renderer.stopRendering();
368
369 // Release the user cache about this instance
370 std::string contextName("PFX");
371 contextName += std::to_string(m_fx->getIdentifier());
372 TPassiveCacheManager::instance()->releaseContextNamesWithPrefix(contextName);
373
374 // Clear the cached images
375 int i;
376 for (i = m_start; i <= m_end; i += m_step)
377 TImageCache::instance()->remove(getCacheId(m_fx, i));
378 }
379
380 //-----------------------------------------------------------------------------------------
381
382 //! Clears the preview instance informations about passed frame, including any
383 //! cached image.
384 //! Informations needed to preview again are NOT rebuilt.
reset(int frame)385 void PreviewFxInstance::reset(int frame) {
386 TImageCache::instance()->remove(getCacheId(m_fx, frame));
387 std::map<int, FrameInfo>::iterator it = m_frameInfos.find(frame);
388 if (it != m_frameInfos.end()) {
389 TRasterFxP builtFx = buildSceneFx(frame);
390 it->second.m_alias =
391 builtFx ? builtFx->getAlias(frame, m_renderSettings) : "";
392 it->second.m_renderedRegion = QRegion();
393 m_overallRenderedRegion = QRegion();
394 }
395 }
396
397 //-----------------------------------------------------------------------------------------
398
399 //! Clears the preview instance informations, including cached images.
400 //! Informations needed
401 //! to preview again are rebuilt.
reset()402 void PreviewFxInstance::reset() {
403 int i;
404 for (i = m_start; i <= m_end; i += m_step)
405 TImageCache::instance()->remove(getCacheId(m_fx, i));
406
407 m_frameInfos.clear();
408
409 updateFrameRange();
410 updateRenderSettings();
411 updateCamera();
412 updateFlipbookTitles();
413 updateAliases();
414 }
415
416 //-----------------------------------------------------------------------------------------
417
addFlipbook(FlipBook * & flipbook)418 void PreviewFxInstance::addFlipbook(FlipBook *&flipbook) {
419 TApp *app = TApp::instance();
420 ToonzScene *scene = app->getCurrentScene()->getScene();
421 TOutputProperties *properties =
422 scene->getProperties()->getPreviewProperties();
423
424 int currFrame = flipbook ? flipbook->getCurrentFrame() - 1
425 : app->getCurrentFrame()->getFrame();
426 cropAndStep(currFrame);
427
428 if (!flipbook) {
429 /*-- 使用可能なFlipbookを取り出す。Poolに無い場合は新たに作る --*/
430 flipbook = FlipBookPool::instance()->pop();
431
432 // In case this is a subcamera preview, fit the flipbook's view. This is
433 // done *before* associating
434 // m_fx to the flipbook (using Flipbook::setLevel) - so there is no
435 // duplicate view refresh.
436 /*-- Preview Settingsで"Use Sub Camera"
437 * がONのとき、サブカメラ枠の外は計算しないようになる --*/
438 if (m_subcamera) {
439 // result->adaptGeometry(TRect(previewInstance->m_cameraRes)); //This
440 // one fits the panel, too.
441 adaptView(flipbook, m_cameraRes); // This one adapts the view. If has
442 // associated fx, calls refresh...
443 } else {
444 // Retrieve the eventual sub-camera
445 TCamera *currCamera = TApp::instance()
446 ->getCurrentScene()
447 ->getScene()
448 ->getCurrentPreviewCamera();
449 TRect subcameraRect(currCamera->getInterestRect());
450 /*-- Viewer上でサブカメラが指定されている状態でFxPreviewをした場合 --*/
451 if (subcameraRect.getLx() > 0 && subcameraRect.getLy() > 0) {
452 /*-- サブカメラ枠のShrink --*/
453 if (m_renderSettings.m_shrinkX > 1 || m_renderSettings.m_shrinkY > 1) {
454 subcameraRect.x0 /= m_renderSettings.m_shrinkX;
455 subcameraRect.y0 /= m_renderSettings.m_shrinkY;
456 subcameraRect.x1 =
457 (subcameraRect.x1 + 1) / m_renderSettings.m_shrinkX - 1;
458 subcameraRect.y1 =
459 (subcameraRect.y1 + 1) / m_renderSettings.m_shrinkY - 1;
460 }
461
462 // Fit & pan the panel to cover the sub-camera
463 flipbook->adaptGeometry(subcameraRect, TRect(TPoint(), m_cameraRes));
464 }
465 }
466
467 /*-- フリーズボタンの表示 --*/
468 flipbook->addFreezeButtonToTitleBar();
469 }
470
471 m_flipbooks.insert(flipbook);
472
473 /*-- タイトルの設定。Previewコマンドから呼ばれた場合はisFullPreviewがON --*/
474
475 // Build the fx string description - Should really be moved in a better
476 // function...
477 std::wstring fxId;
478 TLevelColumnFx *columnFx = dynamic_cast<TLevelColumnFx *>(m_fx.getPointer());
479 TZeraryColumnFx *sfx = dynamic_cast<TZeraryColumnFx *>(m_fx.getPointer());
480 if (columnFx)
481 fxId =
482 L"Col" + QString::number(columnFx->getColumnIndex() + 1).toStdWString();
483 else if (sfx)
484 fxId = sfx->getZeraryFx()->getFxId();
485 else {
486 fxId = m_fx->getFxId();
487 if (fxId.empty()) fxId = m_fx->getName();
488 }
489
490 // Adjust the flipbook appropriately
491
492 // Decorate the description for the flipbook
493 if (isFullPreview()) {
494 flipbook->setTitle(
495 /*"Rendered Frames :: From " + QString::number(m_start+1) +
496 " To " + QString::number(m_end+1) +
497 " :: Step " + QString::number(m_step)*/
498 QObject::tr("Rendered Frames :: From %1 To %2 :: Step %3")
499 .arg(QString::number(m_start + 1))
500 .arg(QString::number(m_end + 1))
501 .arg(QString::number(m_step)));
502 TXsheet::SoundProperties *prop = new TXsheet::SoundProperties();
503 prop->m_frameRate = properties->getFrameRate();
504 m_snd = m_xsheet->makeSound(prop);
505 if (Preferences::instance()->fitToFlipbookEnabled())
506 flipbook->getImageViewer()->adaptView(TRect(m_cameraRes),
507 TRect(m_cameraRes));
508
509 } else
510 flipbook->setTitle(
511 QObject::tr("Preview FX :: %1 ").arg(QString::fromStdWString(fxId)));
512
513 // In case the render is a full preview, add the soundtrack
514
515 // Associate the rendered level to flipbook
516 flipbook->setLevel(m_fx.getPointer(), m_xsheet.getPointer(),
517 m_level.getPointer(), 0, m_start + 1, m_end + 1, m_step,
518 currFrame + 1, m_snd.getPointer());
519
520 // Add the progress bar status pointer
521 flipbook->setProgressBarStatus(&m_pbStatus);
522 }
523
524 //----------------------------------------------------------------------------------------
525
detachFlipbook(FlipBook * flipbook)526 void PreviewFxInstance::detachFlipbook(FlipBook *flipbook) {
527 // Just remove the flipbook from the flipbooks container
528 std::set<FlipBook *>::iterator it = m_flipbooks.find(flipbook);
529 if (it == m_flipbooks.end()) return;
530
531 m_flipbooks.erase(it);
532
533 // If the flipbook set associated with the render is now empty, stop the
534 // render
535 if (m_flipbooks.empty()) m_renderer.stopRendering();
536 }
537
538 //----------------------------------------------------------------------------------------
539
updateFlipbooks()540 void PreviewFxInstance::updateFlipbooks() {
541 std::set<FlipBook *>::iterator it;
542 for (it = m_flipbooks.begin(); it != m_flipbooks.end(); ++it) (*it)->update();
543 }
544
545 //----------------------------------------------------------------------------------------
546
updateFrameRange()547 void PreviewFxInstance::updateFrameRange() {
548 TApp *app = TApp::instance();
549 ToonzScene *scene = app->getCurrentScene()->getScene();
550 TOutputProperties *properties =
551 scene->getProperties()->getPreviewProperties();
552
553 int frameCount = m_xsheet->getFrameCount();
554
555 // Initialize the render starting from current frame. If not in the preview
556 // range,
557 // start from the closest range extreme.
558 properties->getRange(m_start, m_end, m_step);
559 if (m_end < 0) m_end = frameCount - 1;
560
561 // Intersect with the fx active frame range
562 TRasterFxP rasterFx(m_fx);
563 TFxTimeRegion timeRegion(rasterFx->getTimeRegion());
564 m_start = std::max(timeRegion.getFirstFrame(), m_start);
565 m_end = std::min(timeRegion.getLastFrame(), m_end);
566
567 // Release all images not in the new frame range
568 std::map<int, FrameInfo>::iterator it, jt;
569 for (it = m_frameInfos.begin(); it != m_frameInfos.end();) {
570 if (it->first < m_start || it->first > m_end ||
571 ((it->first - m_start) % m_step)) {
572 TImageCache::instance()->remove(getCacheId(m_fx, it->first));
573 jt = it++;
574 m_frameInfos.erase(jt);
575 } else
576 ++it;
577 }
578
579 // Build a level to associate the flipbook with the rendered output
580 m_level->setName(std::to_string(m_fx->getIdentifier()) + ".noext");
581 int i;
582 for (i = 0; i < frameCount; i++) m_level->setFrame(TFrameId(i), 0);
583
584 // Resize and update internal containers
585 if (m_start > m_end) {
586 m_frameInfos.clear();
587 m_pbStatus.clear();
588 } else {
589 // Build the new frame-alias range
590 for (i = m_start; i <= m_end; i += m_step)
591 if (m_frameInfos.find(i) == m_frameInfos.end()) {
592 // Clear the overall rendered region and build the frame info
593 m_overallRenderedRegion = QRegion();
594 m_frameInfos.insert(std::make_pair(i, std::string()));
595 }
596
597 // Resize the progress bar
598 m_pbStatus.resize((m_end - m_start) / m_step + 1);
599 }
600
601 // Reset the flipbooks' frame range
602 std::set<FlipBook *>::iterator kt;
603 int currFrame;
604 bool fullPreview = isFullPreview();
605 for (kt = m_flipbooks.begin(); kt != m_flipbooks.end(); ++kt) {
606 currFrame = (*kt)->getCurrentFrame() - 1;
607 cropAndStep(currFrame);
608 (*kt)->setLevel(m_fx.getPointer(), m_xsheet.getPointer(),
609 m_level.getPointer(), 0, m_start + 1, m_end + 1, m_step,
610 currFrame + 1, m_snd.getPointer());
611 }
612 }
613
614 //----------------------------------------------------------------------------------------
615
updateInitialFrame()616 void PreviewFxInstance::updateInitialFrame() {
617 // Search all flipbooks and take the minimum of each's current
618 std::set<FlipBook *>::iterator kt;
619 m_initFrame = (std::numeric_limits<int>::max)();
620 for (kt = m_flipbooks.begin(); kt != m_flipbooks.end(); ++kt)
621 m_initFrame = std::min(m_initFrame, (*kt)->getCurrentFrame() - 1);
622
623 cropAndStep(m_initFrame);
624 }
625
626 //----------------------------------------------------------------------------------------
627
updateFlipbookTitles()628 void PreviewFxInstance::updateFlipbookTitles() {
629 if (isFullPreview() && m_start <= m_end) {
630 int start = m_start + 1;
631 int end = m_end + 1;
632
633 std::set<FlipBook *>::iterator kt;
634 for (kt = m_flipbooks.begin(); kt != m_flipbooks.end(); ++kt) {
635 // In the full preview case, the title must display the frame range
636 // informations
637 (*kt)->setTitle(
638 /*"Rendered Frames :: From " + QString::number(start) +
639 " To " + QString::number(end) +
640 " :: Step " + QString::number(m_step)*/
641 QObject::tr("Rendered Frames :: From %1 To %2 :: Step %3")
642 .arg(QString::number(start))
643 .arg(QString::number(end))
644 .arg(QString::number(m_step)));
645 }
646 }
647 }
648
649 //----------------------------------------------------------------------------------------
650
updateAliases()651 void PreviewFxInstance::updateAliases() {
652 if (m_start > m_end) return;
653
654 std::string newAlias;
655
656 // Build and compare the new aliases with the stored ones
657 std::map<int, FrameInfo>::iterator it;
658 for (it = m_frameInfos.begin(); it != m_frameInfos.end(); ++it) {
659 TRasterFxP builtFx = buildSceneFx(it->first);
660 newAlias = builtFx ? builtFx->getAlias(it->first, m_renderSettings) : "";
661 if (newAlias != it->second.m_alias) {
662 // Clear the overall and frame-specific rendered regions
663 m_overallRenderedRegion = QRegion();
664 it->second.m_renderedRegion = QRegion();
665
666 it->second.m_alias = newAlias;
667 }
668 }
669 }
670
671 //----------------------------------------------------------------------------------------
672
updateAliasKeyword(const std::string & keyword)673 void PreviewFxInstance::updateAliasKeyword(const std::string &keyword) {
674 if (m_start > m_end) return;
675
676 // Remove the rendered image whose alias contains keyword
677 std::map<int, FrameInfo>::iterator it;
678 for (it = m_frameInfos.begin(); it != m_frameInfos.end(); ++it) {
679 if (it->second.m_alias.find(keyword) != std::string::npos) {
680 // Clear the overall and frame-specific rendered regions
681 m_overallRenderedRegion = QRegion();
682 it->second.m_renderedRegion = QRegion();
683
684 // Clear the cached image
685 TRasterImageP ri =
686 TImageCache::instance()->get(getCacheId(m_fx, it->first), true);
687 if (ri) ri->getRaster()->clear();
688 }
689 }
690 }
691
692 //----------------------------------------------------------------------------------------
693
updateProgressBarStatus()694 void PreviewFxInstance::updateProgressBarStatus() {
695 int i;
696 unsigned int j;
697 std::map<int, FrameInfo>::iterator it;
698 for (i = m_start, j = 0; i <= m_end; i += m_step, ++j) {
699 it = m_frameInfos.find(i);
700 m_pbStatus[j] = ::contains(it->second.m_renderedRegion, m_rectUnderRender)
701 ? FlipSlider::PBFrameFinished
702 : FlipSlider::PBFrameNotStarted;
703 }
704 }
705
706 //----------------------------------------------------------------------------------------
707
updateRenderSettings()708 void PreviewFxInstance::updateRenderSettings() {
709 TApp *app = TApp::instance();
710 ToonzScene *scene = app->getCurrentScene()->getScene();
711 TOutputProperties *properties =
712 scene->getProperties()->getPreviewProperties();
713
714 m_subcamera = properties->isSubcameraPreview();
715
716 const TRenderSettings &renderSettings = properties->getRenderSettings();
717
718 if (m_renderSettings != renderSettings) {
719 m_renderSettings = renderSettings;
720
721 // Erase all previuosly previewed images
722 int i;
723 for (i = m_start; i <= m_end; i += m_step)
724 TImageCache::instance()->remove(getCacheId(m_fx, i));
725
726 // Clear all frame-specific rendered regions
727 std::map<int, FrameInfo>::iterator it;
728 for (it = m_frameInfos.begin(); it != m_frameInfos.end(); ++it)
729 it->second.m_renderedRegion = QRegion();
730 }
731 }
732
733 //----------------------------------------------------------------------------------------
734
updateCamera()735 void PreviewFxInstance::updateCamera() {
736 // Clear the overall rendered region
737 m_overallRenderedRegion = QRegion();
738
739 // Retrieve the preview camera
740 TCamera *currCamera = TApp::instance()
741 ->getCurrentScene()
742 ->getScene()
743 ->getCurrentPreviewCamera();
744 TRect subCameraRect = currCamera->getInterestRect();
745 TPointD cameraPos(-0.5 * currCamera->getRes().lx,
746 -0.5 * currCamera->getRes().ly);
747
748 // Update the camera region and camera stage area
749 TDimension cameraRes(0, 0);
750 TRectD renderArea;
751 if (m_subcamera && subCameraRect.getLx() > 0 && subCameraRect.getLy() > 0) {
752 cameraRes = TDimension(subCameraRect.getLx(), subCameraRect.getLy());
753 renderArea = TRectD(subCameraRect.x0, subCameraRect.y0,
754 subCameraRect.x1 + 1, subCameraRect.y1 + 1) +
755 cameraPos;
756 } else {
757 cameraRes = currCamera->getRes();
758 renderArea = TRectD(cameraPos, TDimensionD(cameraRes.lx, cameraRes.ly));
759 }
760
761 cameraRes.lx /= m_renderSettings.m_shrinkX;
762 cameraRes.ly /= m_renderSettings.m_shrinkY;
763
764 if (m_cameraRes != cameraRes || m_renderArea != renderArea) {
765 m_cameraRes = cameraRes;
766 m_renderArea = renderArea;
767 m_cameraPos = cameraPos;
768
769 // Build the displacement needed when extracting the flipbooks' views
770 m_subcameraDisplacement =
771 TPointD(0.5 * (m_renderArea.x0 + m_renderArea.x1),
772 0.5 * (m_renderArea.y0 + m_renderArea.y1));
773
774 // Erase all previuosly previewed images
775 int i;
776 for (i = m_start; i <= m_end; i += m_step)
777 TImageCache::instance()->remove(getCacheId(m_fx, i));
778
779 // Clear all frame-specific rendered regions
780 std::map<int, FrameInfo>::iterator it;
781 for (it = m_frameInfos.begin(); it != m_frameInfos.end(); ++it)
782 it->second.m_renderedRegion = QRegion();
783 }
784 }
785
786 //----------------------------------------------------------------------------------------
787
updatePreviewRect()788 void PreviewFxInstance::updatePreviewRect() {
789 bool isFullRender = false;
790 if (!m_subcamera) {
791 // Retrieve the eventual sub-camera
792 TCamera *currCamera = TApp::instance()
793 ->getCurrentScene()
794 ->getScene()
795 ->getCurrentPreviewCamera();
796 TRect subcameraRect(currCamera->getInterestRect());
797
798 /*-- Viewer上でサブカメラが指定されていない状態でFxPreviewをした場合 --*/
799 if (subcameraRect.getLx() == 0 || subcameraRect.getLy() == 0)
800 isFullRender = true;
801 }
802
803 // Build all the viewRects to be calculated. They will be computed on
804 // consecutive
805 // render operations.
806 // NOTE: For now, we'll perform a simplicistic solution - coalesce all the
807 // flipbooks'
808 // viewrects and launch just one render.
809 TRectD previewRectD;
810 m_rectUnderRender = TRect();
811
812 int shrinkX = m_renderSettings.m_shrinkX;
813 int shrinkY = m_renderSettings.m_shrinkY;
814
815 if (!isFullRender) {
816 // For each opened flipbook
817 /*-- 開いているFlipbookの表示範囲を足しこんでいく --*/
818 std::set<FlipBook *>::iterator it;
819 for (it = m_flipbooks.begin(); it != m_flipbooks.end(); ++it) {
820 // Only visible flipbooks are considered
821 if ((*it)->isVisible())
822 // Retrieve the flipbook's viewRect. Observe that this image geometry
823 // is intended in shrinked image reference, and assumes that the camera
824 // center
825 // lies at coords (0.0, 0.0).
826 previewRectD += (*it)->getPreviewedImageGeometry();
827 }
828
829 // Pass from shrinked to standard image geometry
830 /*-- いったんShrinkを元に戻す --*/
831 previewRectD.x0 *= shrinkX;
832 previewRectD.y0 *= shrinkY;
833 previewRectD.x1 *= shrinkX;
834 previewRectD.y1 *= shrinkY;
835
836 // Now, the viewer will center the subcamera's raster instead than camera's.
837 // So, we have
838 // to correct the previewRectD by the stored displacement.
839 previewRectD += m_subcameraDisplacement;
840
841 /*-- 表示範囲と計算範囲の共通部分を得る --*/
842 previewRectD *= m_renderArea;
843 } else
844 previewRectD = m_renderArea;
845
846 // Ensure that rect has the same pixel geometry as the preview camera
847 /*-- 再度Shrink --*/
848 previewRectD -= m_cameraPos;
849 previewRectD.x0 = previewRectD.x0 / shrinkX;
850 previewRectD.y0 = previewRectD.y0 / shrinkY;
851 previewRectD.x1 = previewRectD.x1 / shrinkX;
852 previewRectD.y1 = previewRectD.y1 / shrinkY;
853
854 // Now, pass to m_cameraRes-relative coordinates
855 /*-- 計算エリア基準の座標 → カメラ基準の座標 --*/
856 TPointD shrinkedRelPos((m_renderArea.x0 - m_cameraPos.x) / shrinkX,
857 (m_renderArea.y0 - m_cameraPos.y) / shrinkY);
858 previewRectD -= shrinkedRelPos;
859
860 previewRectD.x0 = tfloor(previewRectD.x0);
861 previewRectD.y0 = tfloor(previewRectD.y0);
862 previewRectD.x1 = tceil(previewRectD.x1);
863 previewRectD.y1 = tceil(previewRectD.y1);
864
865 /*-- 表示しなくてはいけないRect --*/
866 QRect qViewRect(previewRectD.x0, previewRectD.y0, previewRectD.getLx(),
867 previewRectD.getLy());
868 /*-- 表示しなくてはいけないRectから、既に計算済みの範囲を引く =
869 * 新たに計算が必要な領域 --*/
870 QRegion viewRectRegionToRender(
871 QRegion(qViewRect).subtracted(m_overallRenderedRegion));
872
873 // If the rect to render has already been calculated, continue.
874 /*-- 新たに計算が必要な領域が無ければReturn --*/
875 if (viewRectRegionToRender.isEmpty()) return;
876
877 // Retrieve the minimal box containing the region yet to be rendered
878 /*-- 新たに計算が必要な領域を含む最小のRectを得る --*/
879 QRect boxRectToRender(viewRectRegionToRender.boundingRect());
880
881 /*-- 計算中のRectに登録する --*/
882 m_rectUnderRender = toTRect(boxRectToRender);
883 /*-- カメラ基準の座標 → 計算エリア基準の座標 --*/
884 previewRectD = toTRectD(boxRectToRender) + m_cameraPos + shrinkedRelPos;
885 /*-- RenderAreaをセット --*/
886 m_renderPort.setRenderArea(previewRectD);
887 }
888
889 //----------------------------------------------------------------------------------------
890
refreshViewRects(bool rebuild)891 void PreviewFxInstance::refreshViewRects(bool rebuild) {
892 if (suspendedRendering) return;
893
894 if (m_flipbooks.empty()) return;
895
896 // Stop any currently running render process. It *should not* be necessary to
897 // wait for complete stop.
898 // WARNING: This requires that different rendering instances are
899 // simultaneously
900 // supported in a single TRenderer...!! We're not currently supporting this...
901 {
902 // NOTE: stopRendering(true) LOOPS and may trigger events which delete this
903 // very
904 // render instance. So we have to watch inside the manager to see if this is
905 // still
906 // alive... The following should be removed using stopRendering(false)...
907 // NOTE: The same problem imposes that refreshViewRects() is not invoked
908 // directly
909 // when iterating the previewInstances map - we've used a signal-slot
910 // connection for this.
911 unsigned long fxId = m_fx->getIdentifier();
912
913 m_renderer.stopRendering(true); // Wait until we've finished
914
915 QMap<unsigned long, PreviewFxInstance *> &previewInstances =
916 PreviewFxManager::instance()->m_previewInstances;
917 if (previewInstances.find(fxId) == previewInstances.end()) return;
918 }
919
920 if (suspendedRendering) return;
921
922 updatePreviewRect();
923 updateProgressBarStatus();
924 updateFlipbooks();
925
926 startRender(rebuild);
927 }
928
929 //----------------------------------------------------------------------------------------
930
startRender(bool rebuild)931 void PreviewFxInstance::startRender(bool rebuild) {
932 if (m_start > m_end) return;
933
934 // Build the rendering initial frame
935 /*-- m_initialFrameに最初に計算するフレーム番号を格納 --*/
936 updateInitialFrame();
937
938 m_renderFailed = false;
939
940 ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
941
942 // Fill the production-specific infos (threads count and tile size)
943 TOutputProperties *properties =
944 scene->getProperties()->getPreviewProperties();
945
946 // Update the threads number
947 const int procCount = TSystem::getProcessorCount();
948 const int threadCounts[3] = {1, procCount / 2, procCount};
949
950 int index = properties->getThreadIndex();
951 m_renderer.setThreadsCount(threadCounts[index]);
952
953 // Build raster granularity size
954 index = properties->getMaxTileSizeIndex();
955
956 const int maxTileSizes[4] = {
957 (std::numeric_limits<int>::max)(), TOutputProperties::LargeVal,
958 TOutputProperties::MediumVal, TOutputProperties::SmallVal};
959
960 int oldMaxTileSize = m_renderSettings.m_maxTileSize;
961 m_renderSettings.m_maxTileSize = maxTileSizes[index];
962
963 // Initialize the vector of TRenderer::RenderData to be rendered. The 'frame'
964 // data
965 // should be inserted first.
966 RenderDataVector *renderDatas = new RenderDataVector;
967 int i;
968 for (i = m_initFrame; i <= m_end; i += m_step)
969 addRenderData(*renderDatas, scene, i, rebuild);
970 for (i = m_start; i < m_initFrame; i += m_step)
971 addRenderData(*renderDatas, scene, i, rebuild);
972
973 // Restore the original max tile size
974 m_renderSettings.m_maxTileSize = oldMaxTileSize;
975
976 // Retrieve the renderId
977 unsigned long renderId = m_renderer.nextRenderId();
978 std::string contextName("PFX");
979 contextName += std::to_string(m_fx->getIdentifier());
980 TPassiveCacheManager::instance()->setContextName(renderId, contextName);
981
982 // Finally, start rendering all frames which were not found in cache
983 m_renderer.startRendering(renderDatas);
984 }
985
986 //----------------------------------------------------------------------------------------
987
onRenderRasterStarted(const TRenderPort::RenderData & renderData)988 void PreviewFxRenderPort::onRenderRasterStarted(
989 const TRenderPort::RenderData &renderData) {
990 m_owner->onRenderRasterStarted(renderData);
991 }
992
993 //----------------------------------------------------------------------------------------
994
onRenderRasterCompleted(const RenderData & renderData)995 void PreviewFxRenderPort::onRenderRasterCompleted(
996 const RenderData &renderData) {
997 /*-- Do not show the result if canceled while rendering --*/
998 if (renderData.m_info.m_isCanceled && *renderData.m_info.m_isCanceled) {
999 // set m_renderFailed to true in order to prevent updating
1000 // m_overallRenderedRegion at PreviewFxInstance::onRenderFinished().
1001 m_owner->m_renderFailed = true;
1002 return;
1003 }
1004
1005 m_owner->onRenderRasterCompleted(renderData);
1006 }
1007
1008 //----------------------------------------------------------------------------------------
1009
onRenderFailure(const RenderData & renderData,TException & e)1010 void PreviewFxRenderPort::onRenderFailure(const RenderData &renderData,
1011 TException &e) {
1012 m_owner->onRenderFailure(renderData, e);
1013 }
1014
1015 //----------------------------------------------------------------------------------------
1016
onRenderFinished(bool isCanceled)1017 void PreviewFxRenderPort::onRenderFinished(bool isCanceled) {
1018 m_owner->onRenderFinished(isCanceled);
1019 }
1020
1021 //----------------------------------------------------------------------------------------
1022
onRenderRasterStarted(const TRenderPort::RenderData & renderData)1023 void PreviewFxInstance::onRenderRasterStarted(
1024 const TRenderPort::RenderData &renderData) {
1025 PreviewFxManager::instance()->emitStartedFrame(m_fx->getIdentifier(),
1026 renderData);
1027 }
1028
1029 //----------------------------------------------------------------------------------------
1030
onRenderRasterCompleted(const TRenderPort::RenderData & renderData)1031 void PreviewFxInstance::onRenderRasterCompleted(
1032 const TRenderPort::RenderData &renderData) {
1033 PreviewFxManager::instance()->emitRenderedFrame(m_fx->getIdentifier(),
1034 renderData);
1035 }
1036
1037 //----------------------------------------------------------------------------------------
1038
1039 // Update the progress bar status to show the frame has started
doOnRenderRasterStarted(const TRenderPort::RenderData & renderData)1040 void PreviewFxInstance::doOnRenderRasterStarted(
1041 const TRenderPort::RenderData &renderData) {
1042 unsigned int i, size = renderData.m_frames.size();
1043 for (i = 0; i < size; ++i)
1044 // Update the pb status for each cluster's frame
1045 m_pbStatus[(renderData.m_frames[i] - m_start) / m_step] =
1046 FlipSlider::PBFrameStarted;
1047
1048 /*-- 計算中の赤枠を表示する --*/
1049 std::set<FlipBook *>::iterator it;
1050 for (it = m_flipbooks.begin(); it != m_flipbooks.end(); ++it)
1051 (*it)->setIsRemakingPreviewFx(true);
1052
1053 updateFlipbooks();
1054 }
1055
1056 //----------------------------------------------------------------------------------------
1057
1058 // Show the rendered frame if it is some flipbook's current
doOnRenderRasterCompleted(const TRenderPort::RenderData & renderData)1059 void PreviewFxInstance::doOnRenderRasterCompleted(
1060 const TRenderPort::RenderData &renderData) {
1061 std::string cacheId(getCacheId(m_fx, renderData.m_frames[0]));
1062
1063 TRasterImageP ri(TImageCache::instance()->get(cacheId, true));
1064 TRasterP ras;
1065 if (ri)
1066 ras = ri->getRaster();
1067 else
1068 ras = 0;
1069
1070 /*-- 16bpcで計算された場合、結果をDitheringする --*/
1071 TRasterP rasA = renderData.m_rasA;
1072 TRasterP rasB = renderData.m_rasB;
1073 if (rasA->getPixelSize() == 8) // render in 64 bits
1074 {
1075 TRaster32P auxA(rasA->getLx(), rasA->getLy());
1076 TRop::convert(auxA, rasA); // dithering
1077 rasA = auxA;
1078 if (m_renderSettings.m_stereoscopic) {
1079 assert(rasB);
1080 TRaster32P auxB(rasB->getLx(), rasB->getLy());
1081 TRop::convert(auxB, rasB); // dithering
1082 rasB = auxB;
1083 }
1084 }
1085
1086 if (!ras || (ras->getSize() != m_cameraRes)) {
1087 TImageCache::instance()->remove(cacheId);
1088
1089 // Create the raster at camera resolution
1090 ras = rasA->create(m_cameraRes.lx, m_cameraRes.ly);
1091 ras->clear();
1092 ri = TRasterImageP(ras);
1093 }
1094
1095 // Finally, copy the rendered raster over the cached one
1096 TRect rectUnderRender(
1097 m_rectUnderRender); // Extract may MODIFY IT! E.g. with shrinks..!
1098 ras = ras->extract(rectUnderRender);
1099 if (ras) {
1100 if (m_renderSettings.m_stereoscopic) {
1101 assert(rasB);
1102 TRop::makeStereoRaster(rasA, rasB);
1103 }
1104 ras->copy(rasA);
1105 }
1106 // Submit the image to the cache, for all cluster's frames
1107 unsigned int i, size = renderData.m_frames.size();
1108 for (i = 0; i < size; ++i) {
1109 int frame = renderData.m_frames[i];
1110 TImageCache::instance()->add(getCacheId(m_fx, frame), ri);
1111
1112 // Update the pb status
1113 int pbIndex = (frame - m_start) / m_step;
1114 if (pbIndex >= 0 && pbIndex < (int)m_pbStatus.size())
1115 m_pbStatus[pbIndex] = FlipSlider::PBFrameFinished;
1116
1117 // Update the frame-specific rendered region
1118 std::map<int, FrameInfo>::iterator jt = m_frameInfos.find(frame);
1119 assert(jt != m_frameInfos.end());
1120 jt->second.m_renderedRegion += toQRect(m_rectUnderRender);
1121
1122 std::set<FlipBook *>::iterator it;
1123 int renderedFrame = frame + 1;
1124 for (it = m_flipbooks.begin(); it != m_flipbooks.end(); ++it)
1125 if ((*it)->getCurrentFrame() == renderedFrame)
1126 (*it)->showFrame(renderedFrame);
1127 }
1128
1129 updateFlipbooks();
1130 }
1131
1132 //----------------------------------------------------------------------------------------
1133
onRenderFailure(const TRenderPort::RenderData & renderData,TException & e)1134 void PreviewFxInstance::onRenderFailure(
1135 const TRenderPort::RenderData &renderData, TException &e) {
1136 m_renderFailed = true;
1137
1138 // Update each frame status
1139 unsigned int i, size = renderData.m_frames.size();
1140 for (i = 0; i < size; ++i) {
1141 int frame = renderData.m_frames[i];
1142
1143 // Update the pb status
1144 int pbIndex = (frame - m_start) / m_step;
1145 if (pbIndex >= 0 && pbIndex < (int)m_pbStatus.size())
1146 m_pbStatus[pbIndex] = FlipSlider::PBFrameNotStarted;
1147 }
1148 }
1149
1150 //----------------------------------------------------------------------------------------
1151
onRenderFinished(bool isCanceled)1152 void PreviewFxInstance::onRenderFinished(bool isCanceled) {
1153 // Update the rendered region
1154 if (!m_renderFailed && !isCanceled)
1155 m_overallRenderedRegion += toQRect(m_rectUnderRender);
1156
1157 /*-- 計算中の赤枠の表示を消す --*/
1158 std::set<FlipBook *>::iterator it;
1159 for (it = m_flipbooks.begin(); it != m_flipbooks.end(); ++it)
1160 (*it)->setIsRemakingPreviewFx(false);
1161 }
1162
1163 //=======================================================================================================
1164
1165 //=========================
1166 // PreviewFxManager
1167 //-------------------------
1168
PreviewFxManager()1169 PreviewFxManager::PreviewFxManager() : QObject() {
1170 TApp *app = TApp::instance();
1171 qRegisterMetaType<unsigned long>("unsigned long");
1172 qRegisterMetaType<TRenderPort::RenderData>("TRenderPort::RenderData");
1173
1174 /*-- Rendering終了時、各RenderPortからEmit → Flipbookの更新を行う --*/
1175 connect(this, SIGNAL(renderedFrame(unsigned long, TRenderPort::RenderData)),
1176 this, SLOT(onRenderedFrame(unsigned long, TRenderPort::RenderData)));
1177 /*-- Rendering開始時、各RenderPortからEmit →
1178 * Flipbookのプログレスバーのステータスを「計算中」にする --*/
1179 connect(this, SIGNAL(startedFrame(unsigned long, TRenderPort::RenderData)),
1180 this, SLOT(onStartedFrame(unsigned long, TRenderPort::RenderData)));
1181
1182 // connect(app->getPaletteController()->getCurrentPalette(),
1183 // SIGNAL(colorStyleChangedOnMouseRelease()),SLOT(onLevelChanged()));
1184 // connect(app->getPaletteController()->getCurrentPalette(),
1185 // SIGNAL(paletteChanged()), SLOT(onLevelChanged()));
1186 connect(app->getPaletteController()->getCurrentLevelPalette(),
1187 SIGNAL(colorStyleChangedOnMouseRelease()), SLOT(onLevelChanged()));
1188 connect(app->getPaletteController()->getCurrentLevelPalette(),
1189 SIGNAL(paletteChanged()), SLOT(onLevelChanged()));
1190
1191 connect(app->getCurrentLevel(), SIGNAL(xshLevelChanged()), this,
1192 SLOT(onLevelChanged()));
1193 connect(app->getCurrentFx(), SIGNAL(fxChanged()), this, SLOT(onFxChanged()));
1194 connect(app->getCurrentXsheet(), SIGNAL(xsheetChanged()), this,
1195 SLOT(onXsheetChanged()));
1196 connect(app->getCurrentObject(), SIGNAL(objectChanged(bool)), this,
1197 SLOT(onObjectChanged(bool)));
1198
1199 /*-- 上記の on○○Changed() は、全て refreshViewRects をEmitしている。
1200 → これまでの計算を止め、新たにstartRenderをする。
1201 (Qt::QueuedConnection
1202 は、イベントループの手が空いた時に初めてSLOTを呼ぶ、ということ)
1203 --*/
1204 // Due to current implementation of PreviewFxInstance::refreshViewRects().
1205 connect(this, SIGNAL(refreshViewRects(unsigned long)), this,
1206 SLOT(onRefreshViewRects(unsigned long)), Qt::QueuedConnection);
1207
1208 previewerInstance = this;
1209 }
1210
1211 //-----------------------------------------------------------------------------
1212
~PreviewFxManager()1213 PreviewFxManager::~PreviewFxManager() {}
1214
1215 //-----------------------------------------------------------------------------
1216
instance()1217 PreviewFxManager *PreviewFxManager::instance() {
1218 static PreviewFxManager _instance;
1219 return &_instance;
1220 }
1221
1222 //-----------------------------------------------------------------------------
1223
showNewPreview(TFxP fx,bool forceFlipbook)1224 FlipBook *PreviewFxManager::showNewPreview(TFxP fx, bool forceFlipbook) {
1225 if (!fx) return 0;
1226
1227 /*-- fxIdは、Fxの作成ごとに1つずつインクリメントして割り振られる数字 --*/
1228 unsigned long fxId = fx->getIdentifier();
1229 PreviewFxInstance *previewInstance = 0;
1230
1231 /*-- PreviewFxInstanceをFxごとに作成する --*/
1232 QMap<unsigned long, PreviewFxInstance *>::iterator it =
1233 m_previewInstances.find(fxId);
1234 if (it == m_previewInstances.end()) {
1235 TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
1236 previewInstance = new PreviewFxInstance(fx, xsh);
1237 m_previewInstances.insert(fxId, previewInstance);
1238 } else {
1239 previewInstance = it.value();
1240 /*-- 以前PreviewしたことのあるFxを、再度Previewしたとき --*/
1241 if (!forceFlipbook &&
1242 !Preferences::instance()->previewAlwaysOpenNewFlipEnabled()) {
1243 // Search the first visible flipbook to be raised. If not found, add a new
1244 // one.
1245 /*--
1246 * そのFxに関連付けられたFlipbookがあり、かつVisibleな場合は、reset()で再計算
1247 * --*/
1248 std::set<FlipBook *> &flipbooks = previewInstance->m_flipbooks;
1249 std::set<FlipBook *>::iterator jt;
1250 for (jt = flipbooks.begin(); jt != flipbooks.end(); ++jt)
1251 if ((*jt)->isVisible()) {
1252 reset(fx); // Also recalculate the preview
1253 (*jt)->parentWidget()->raise();
1254 return 0;
1255 }
1256 }
1257 }
1258
1259 FlipBook *result = 0;
1260 /*-- resultに必要なFlipbookを格納し、setLevelをする --*/
1261 previewInstance->addFlipbook(result);
1262
1263 /*-- Flipbookのクローン時以外は forceFlipbookがfalse --*/
1264 if (!forceFlipbook) /*-- startRenderを実行 --*/
1265 previewInstance->refreshViewRects();
1266
1267 return result;
1268 }
1269
1270 //-----------------------------------------------------------------------------
1271 /*! return true if the preview fx instance for specified fx is with sub-camera
1272 * activated
1273 */
1274
isSubCameraActive(TFxP fx)1275 bool PreviewFxManager::isSubCameraActive(TFxP fx) {
1276 if (!fx) return false;
1277
1278 unsigned long fxId = fx->getIdentifier();
1279 QMap<unsigned long, PreviewFxInstance *>::iterator it =
1280 m_previewInstances.find(fxId);
1281 if (it == m_previewInstances.end()) return false;
1282
1283 return it.value()->isSubCameraActive();
1284 }
1285
1286 //-----------------------------------------------------------------------------
1287
refreshView(TFxP fx)1288 void PreviewFxManager::refreshView(TFxP fx) {
1289 if (!fx) return;
1290
1291 unsigned long fxId = fx->getIdentifier();
1292 QMap<unsigned long, PreviewFxInstance *>::iterator it =
1293 m_previewInstances.find(fxId);
1294 if (it == m_previewInstances.end()) return;
1295
1296 it.value()->refreshViewRects();
1297 }
1298
1299 //-----------------------------------------------------------------------------
1300
1301 //! This slot is necessary to prevent problems with current implementation of
1302 //! the
1303 //! event-looping PreviewFxInstance::refreshViewRects function.
onRefreshViewRects(unsigned long id)1304 void PreviewFxManager::onRefreshViewRects(unsigned long id) {
1305 QMap<unsigned long, PreviewFxInstance *>::iterator it =
1306 m_previewInstances.find(id);
1307 if (it != m_previewInstances.end()) it.value()->refreshViewRects();
1308 }
1309
1310 //-----------------------------------------------------------------------------
1311
unfreeze(FlipBook * flipbook)1312 void PreviewFxManager::unfreeze(FlipBook *flipbook) {
1313 TFxP fx(flipbook->getPreviewedFx());
1314 if (!fx) return;
1315
1316 QMap<unsigned long, PreviewFxInstance *>::iterator it =
1317 m_previewInstances.find(fx->getIdentifier());
1318 if (it == m_previewInstances.end()) return;
1319
1320 PreviewFxInstance *previewInstance = it.value();
1321 std::set<FlipBook *> &frozenFlips = previewInstance->m_frozenFlips;
1322
1323 std::set<FlipBook *>::iterator jt = frozenFlips.find(flipbook);
1324 if (jt == frozenFlips.end()) return;
1325
1326 // Re-attach to the preview instance
1327 {
1328 frozenFlips.erase(jt);
1329
1330 // Before attaching, remove any old flipbook level from the cache
1331 flipbook->clearCache();
1332
1333 // Also any associated pb status
1334 delete flipbook->getProgressBarStatus();
1335 flipbook->setProgressBarStatus(NULL);
1336
1337 previewInstance->addFlipbook(flipbook);
1338
1339 // recompute frames, if necessary (call the same process as
1340 // PreviewFxManager::onXsheetChanged())
1341 previewInstance->updateRenderSettings();
1342 previewInstance->updateCamera();
1343 previewInstance->updateFrameRange();
1344 previewInstance->updateFlipbookTitles();
1345 previewInstance->updateAliases();
1346
1347 previewInstance->refreshViewRects();
1348 }
1349 }
1350
1351 //-----------------------------------------------------------------------------
1352
1353 //! Observe that detached flipbooks which maintain the previewed images also
1354 //! maintain the internal reference
1355 //! to the previewed fx returned by the FlipBook::getPreviewedFx() method, so
1356 //! the flipbook may be re-attached
1357 //! (ie un-freezed) to the same preview fx.
freeze(FlipBook * flipbook)1358 void PreviewFxManager::freeze(FlipBook *flipbook) {
1359 // Retrieve its previewed fx
1360 TFxP fx(flipbook->getPreviewedFx());
1361 if (!fx) return;
1362
1363 QMap<unsigned long, PreviewFxInstance *>::iterator it =
1364 m_previewInstances.find(fx->getIdentifier());
1365 if (it == m_previewInstances.end()) return;
1366
1367 PreviewFxInstance *previewInstance = it.value();
1368
1369 // First off, detach the flipbook from the preview instance and
1370 // insert it among the instance's frozen ones
1371 previewInstance->detachFlipbook(flipbook);
1372 previewInstance->m_frozenFlips.insert(flipbook);
1373
1374 // Then, perform the level copy
1375 {
1376 std::string levelName("freezed" + std::to_string(flipbook->getPoolIndex()) +
1377 ".noext");
1378 int i;
1379
1380 // Clone the preview images
1381 for (i = previewInstance->m_start; i <= previewInstance->m_end;
1382 i += previewInstance->m_step) {
1383 TImageP cachedImage =
1384 TImageCache::instance()->get(getCacheId(fx, i), false);
1385 if (cachedImage)
1386 TImageCache::instance()->add(levelName + std::to_string(i),
1387 cachedImage->cloneImage());
1388 }
1389
1390 // Associate a level with the cached images
1391 TLevelP freezedLevel;
1392 freezedLevel->setName(levelName);
1393 for (i = 0; i < previewInstance->m_level->getFrameCount(); ++i)
1394 freezedLevel->setFrame(TFrameId(i), 0);
1395 flipbook->setLevel(fx.getPointer(), previewInstance->m_xsheet.getPointer(),
1396 freezedLevel.getPointer(), 0,
1397 previewInstance->m_start + 1, previewInstance->m_end + 1,
1398 previewInstance->m_step, flipbook->getCurrentFrame(),
1399 previewInstance->m_snd.getPointer());
1400
1401 // Also, the associated PB must be cloned
1402 std::vector<UCHAR> *newPBStatuses = new std::vector<UCHAR>;
1403 *newPBStatuses = previewInstance->m_pbStatus;
1404 flipbook->setProgressBarStatus(newPBStatuses);
1405
1406 // Traverse the PB: frames under rendering must be signed as uncompleted
1407 std::vector<UCHAR>::iterator it;
1408 for (it = newPBStatuses->begin(); it != newPBStatuses->end(); ++it)
1409 if (*it == FlipSlider::PBFrameStarted)
1410 *it = FlipSlider::PBFrameNotStarted;
1411 }
1412 }
1413
1414 //-----------------------------------------------------------------------------
1415
detach(FlipBook * flipbook)1416 void PreviewFxManager::detach(FlipBook *flipbook) {
1417 // Retrieve its previewed fx
1418 TFxP fx(flipbook->getPreviewedFx());
1419 if (!fx) return;
1420
1421 // Search the flip among attached ones
1422 QMap<unsigned long, PreviewFxInstance *>::iterator it =
1423 m_previewInstances.find(fx->getIdentifier());
1424 if (it == m_previewInstances.end()) return;
1425
1426 PreviewFxInstance *previewInstance = it.value();
1427
1428 // Detach the flipbook (does nothing if flipbook is frozen)
1429 previewInstance->detachFlipbook(flipbook);
1430
1431 // Eventually, it could be in frozens; detach it from there too
1432 std::set<FlipBook *> &frozenFlips = previewInstance->m_frozenFlips;
1433
1434 std::set<FlipBook *>::iterator jt = frozenFlips.find(flipbook);
1435 if (jt != frozenFlips.end()) {
1436 flipbook->clearCache();
1437 delete flipbook->getProgressBarStatus();
1438 frozenFlips.erase(jt);
1439 }
1440
1441 // Finally, delete the preview instance if no flipbook (active or frozen)
1442 // remain
1443 if (previewInstance->m_flipbooks.empty() &&
1444 previewInstance->m_frozenFlips.empty()) {
1445 delete it.value();
1446 m_previewInstances.erase(it);
1447 }
1448 }
1449
1450 //-----------------------------------------------------------------------------
1451
onLevelChanged()1452 void PreviewFxManager::onLevelChanged() {
1453 if (m_previewInstances.size()) {
1454 // Build the level name as an alias keyword. All cache images associated
1455 // with an alias containing the level name will be updated.
1456 TXshLevel *xl = TApp::instance()->getCurrentLevel()->getLevel();
1457 std::string aliasKeyword;
1458 TFilePath fp = xl->getPath();
1459 aliasKeyword = ::to_string(fp.withType(""));
1460
1461 QMap<unsigned long, PreviewFxInstance *>::iterator it;
1462 for (it = m_previewInstances.begin(); it != m_previewInstances.end();
1463 ++it) {
1464 it.value()->updateAliasKeyword(aliasKeyword);
1465 emit refreshViewRects(it.key());
1466 // it.value()->refreshViewRects();
1467 }
1468 }
1469 }
1470
1471 //-----------------------------------------------------------------------------
1472
onFxChanged()1473 void PreviewFxManager::onFxChanged() {
1474 // Examinate all RenderInstances for ancestors of current fx
1475 if (m_previewInstances.size()) {
1476 TFxP fx = TApp::instance()->getCurrentFx()->getFx();
1477
1478 QMap<unsigned long, PreviewFxInstance *>::iterator it;
1479 for (it = m_previewInstances.begin(); it != m_previewInstances.end(); ++it)
1480 // if(areAncestorAndDescendant(it.value()->m_fx, fx)) //Currently not
1481 // trespassing sub-xsheet boundaries
1482 {
1483 // in case the flipbook is frozen
1484 if (it.value()->m_flipbooks.empty()) continue;
1485 it.value()->updateAliases();
1486 emit refreshViewRects(it.key());
1487 // it.value()->refreshViewRects();
1488 }
1489 }
1490 }
1491
1492 //-----------------------------------------------------------------------------
1493
onXsheetChanged()1494 void PreviewFxManager::onXsheetChanged() {
1495 // Update all rendered frames, if necessary
1496 if (m_previewInstances.size()) {
1497 QMap<unsigned long, PreviewFxInstance *>::iterator it;
1498 for (it = m_previewInstances.begin(); it != m_previewInstances.end();
1499 ++it) {
1500 // in case the flipbook is frozen
1501 if (it.value()->m_flipbooks.empty()) continue;
1502 it.value()->updateRenderSettings();
1503 it.value()->updateCamera();
1504 it.value()->updateFrameRange();
1505 it.value()->updateFlipbookTitles();
1506 it.value()->updateAliases();
1507 emit refreshViewRects(it.key());
1508 // it.value()->refreshViewRects();
1509 }
1510 }
1511 }
1512
1513 //-----------------------------------------------------------------------------
1514
onObjectChanged(bool isDragging)1515 void PreviewFxManager::onObjectChanged(bool isDragging) {
1516 if (isDragging) return;
1517 // Update all rendered frames, if necessary
1518 if (m_previewInstances.size()) {
1519 QMap<unsigned long, PreviewFxInstance *>::iterator it;
1520 for (it = m_previewInstances.begin(); it != m_previewInstances.end();
1521 ++it) {
1522 // in case the flipbook is frozen
1523 if (it.value()->m_flipbooks.empty()) continue;
1524 it.value()->updateFrameRange();
1525 it.value()->updateFlipbookTitles();
1526 it.value()->updateAliases();
1527 emit refreshViewRects(it.key());
1528 // it.value()->refreshViewRects();
1529 }
1530 }
1531 }
1532
1533 //-----------------------------------------------------------------------------
1534 /*--
1535 * 既にPreviewしたことがあり、Flipbookが開いているFxを再度Previewしたときに実行される
1536 * --*/
reset(TFxP fx)1537 void PreviewFxManager::reset(TFxP fx) {
1538 if (!fx) return;
1539
1540 unsigned long fxId = fx->getIdentifier();
1541 QMap<unsigned long, PreviewFxInstance *>::iterator it =
1542 m_previewInstances.find(fxId);
1543 if (it == m_previewInstances.end()) return;
1544
1545 it.value()->m_renderer.stopRendering(true);
1546
1547 // stopRendering(true) LOOPS and may destroy the preview instance. Recheck for
1548 // its presence
1549 it = m_previewInstances.find(fxId);
1550 if (it != m_previewInstances.end()) {
1551 it.value()->reset();
1552 it.value()->refreshViewRects();
1553 }
1554 }
1555
1556 //-----------------------------------------------------------------------------
1557
reset(TFxP fx,int frame)1558 void PreviewFxManager::reset(TFxP fx, int frame) {
1559 if (!fx) return;
1560
1561 unsigned long fxId = fx->getIdentifier();
1562 QMap<unsigned long, PreviewFxInstance *>::iterator it =
1563 m_previewInstances.find(fxId);
1564 if (it == m_previewInstances.end()) return;
1565
1566 if (it.value()->m_start > it.value()->m_end) return;
1567
1568 it.value()->m_renderer.stopRendering(true);
1569
1570 // stopRendering(true) LOOPS and may destroy the preview instance. Recheck for
1571 // its presence
1572 it = m_previewInstances.find(fxId);
1573 if (it != m_previewInstances.end()) {
1574 it.value()->reset(frame);
1575 it.value()->refreshViewRects();
1576 }
1577 }
1578
1579 //-----------------------------------------------------------------------------
1580
reset(bool detachFlipbooks)1581 void PreviewFxManager::reset(bool detachFlipbooks) {
1582 // Hard copy the instances pointers
1583 QMap<unsigned long, PreviewFxInstance *> previewInstances =
1584 m_previewInstances;
1585
1586 QMap<unsigned long, PreviewFxInstance *>::iterator it;
1587 for (it = previewInstances.begin(); it != previewInstances.end(); ++it) {
1588 // Just like the above, stopRendering(true) event-LOOPS...
1589 it.value()->m_renderer.stopRendering(true);
1590
1591 if (m_previewInstances.find(it.key()) == m_previewInstances.end()) continue;
1592
1593 if (detachFlipbooks) {
1594 // Reset all associated flipbooks
1595 PreviewFxInstance *previewInstance = it.value();
1596
1597 // Hard copy, since detach manipulates the original
1598 std::set<FlipBook *> flipbooks = previewInstance->m_flipbooks;
1599
1600 std::set<FlipBook *>::iterator jt;
1601 for (jt = flipbooks.begin(); jt != flipbooks.end(); ++jt) {
1602 // Detach and reset the flipbook
1603 (*jt)->reset(); // The detachment happens in here
1604 }
1605
1606 /*- Frozen
1607 * Flipがひとつも無い場合には、この時点でpreviewInstanceが除外されている
1608 * -*/
1609 if (m_previewInstances.find(it.key()) == m_previewInstances.end())
1610 continue;
1611
1612 // Same for frozen ones
1613
1614 if (!previewInstance->m_frozenFlips.empty() &&
1615 previewInstance->m_frozenFlips.size() < 20) {
1616 std::set<FlipBook *> frozenFlips = previewInstance->m_frozenFlips;
1617 for (jt = frozenFlips.begin(); jt != frozenFlips.end(); ++jt) {
1618 // Detach and reset the flipbook
1619 (*jt)->reset(); // The detachment happens in here
1620 }
1621 }
1622
1623 // The Preview instance should have been deleted at this point (due to
1624 // flipbook detachments)
1625 assert(m_previewInstances.find(it.key()) == m_previewInstances.end());
1626 } else {
1627 it.value()->reset();
1628 it.value()->refreshViewRects();
1629 }
1630 }
1631 }
1632
1633 //-----------------------------------------------------------------------------
1634
emitStartedFrame(unsigned long fxId,const TRenderPort::RenderData & renderData)1635 void PreviewFxManager::emitStartedFrame(
1636 unsigned long fxId, const TRenderPort::RenderData &renderData) {
1637 emit startedFrame(fxId, renderData);
1638 }
1639
1640 //-----------------------------------------------------------------------------
1641
emitRenderedFrame(unsigned long fxId,const TRenderPort::RenderData & renderData)1642 void PreviewFxManager::emitRenderedFrame(
1643 unsigned long fxId, const TRenderPort::RenderData &renderData) {
1644 emit renderedFrame(fxId, renderData);
1645 }
1646
1647 //-----------------------------------------------------------------------------
1648
onStartedFrame(unsigned long fxId,TRenderPort::RenderData renderData)1649 void PreviewFxManager::onStartedFrame(unsigned long fxId,
1650 TRenderPort::RenderData renderData) {
1651 QMap<unsigned long, PreviewFxInstance *>::iterator it =
1652 m_previewInstances.find(fxId);
1653 if (it != m_previewInstances.end()) {
1654 // Invoke the corresponding function. This happens in the MAIN THREAD
1655 it.value()->doOnRenderRasterStarted(renderData);
1656 }
1657 }
1658
1659 //-----------------------------------------------------------------------------
1660
onRenderedFrame(unsigned long fxId,TRenderPort::RenderData renderData)1661 void PreviewFxManager::onRenderedFrame(unsigned long fxId,
1662 TRenderPort::RenderData renderData) {
1663 QMap<unsigned long, PreviewFxInstance *>::iterator it =
1664 m_previewInstances.find(fxId);
1665 if (it != m_previewInstances.end()) {
1666 // Invoke the corresponding function. This happens in the MAIN THREAD
1667 it.value()->doOnRenderRasterCompleted(renderData);
1668 }
1669 }
1670
1671 //-----------------------------------------------------------------------------
1672
1673 //! The suspendRendering method allows suspension of the previewer's rendering
1674 //! activity for safety purposes, typically related to the fact that no
1675 //! rendering
1676 //! process should actually be performed as the underlying scene is about to
1677 //! change
1678 //! or being destroyed. Upon suspension, further rendering requests are silently
1679 //! rejected - and currently active ones are canceled and waited until they are
1680 //! no
1681 //! longer active.
suspendRendering(bool suspend)1682 void PreviewFxManager::suspendRendering(bool suspend) {
1683 suspendedRendering = suspend;
1684 if (suspend && previewerInstance) {
1685 QMap<unsigned long, PreviewFxInstance *>::iterator it;
1686 for (it = previewerInstance->m_previewInstances.begin();
1687 it != previewerInstance->m_previewInstances.end(); ++it) {
1688 it.value()->m_renderer.stopRendering(true);
1689 }
1690 }
1691 }
1692