tahoma2d/toonz/sources/toonzqt/swatchviewer.cpp

1266 lines
40 KiB
C++
Raw Normal View History

2016-03-19 06:57:51 +13:00
#include "toonzqt/swatchviewer.h"
#include "toonzqt/gutil.h"
#include "toonzqt/menubarcommand.h"
#include "toonzqt/viewcommandids.h"
#include "../toonz/menubarcommandids.h"
2016-03-19 06:57:51 +13:00
#include <QPainter>
#include <QMouseEvent>
#include <QGestureEvent>
2016-03-19 06:57:51 +13:00
#include <QResizeEvent>
#include "trasterfx.h"
#include "toonz/tcolumnfx.h"
#include "tparamcontainer.h"
#include "tfxutil.h"
2016-06-15 18:43:10 +12:00
// Rendering cache management includes
2016-03-19 06:57:51 +13:00
#include "tfxcachemanager.h"
#include "tcacheresourcepool.h"
#include "tpassivecachemanager.h"
#include <QEventLoop>
#include <QCoreApplication>
#include <QDebug>
2022-02-25 21:33:12 +13:00
#include <QGuiApplication>
2016-03-19 06:57:51 +13:00
using namespace TFxUtil;
//#define USE_SQLITE_HDPOOL
//*************************************************************************************
// Swatch cache delegate
//*************************************************************************************
/*!
2016-06-15 18:43:10 +12:00
The swatch cache delegate is used to temporary store intermediate rendering
results
2016-03-19 06:57:51 +13:00
in cache when an fx is being edited.
2016-06-15 18:43:10 +12:00
Input fxs of an edited fx are typically requested to produce the same results
multiple times
as parameters of their schematic parent change - so, caching these results is a
remunerative
2016-03-19 06:57:51 +13:00
practice as long as the fx is open for edit.
2016-06-15 18:43:10 +12:00
This delegate stores resources on two different levels: one is directly related
to swatch rendering,
2016-03-19 06:57:51 +13:00
while the other is used to cache results on the other rendering contexts.
2016-06-15 18:43:10 +12:00
In the swatch case, we store the above mentioned input results associated with
the current scene
scale, releasing them when the scene scale changes; plus, the resource
associated with the current
2016-03-19 06:57:51 +13:00
output is also stored.
2016-06-15 18:43:10 +12:00
In other rendering contexts, the scene scale can be assumed constant - so the
above distinction
is unnecessary. All results from the input fxs are stored until the edited fx is
unset from the swatch.
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
Please observe that variations in the scene context - such as frame change,
schematic changes, scene changes
and so on - actually cause the fx to be re-set for edit in the swatch. Once this
happens, the previously
2016-03-19 06:57:51 +13:00
stored results are conveniently flushed from the cache.
*/
2016-06-15 18:43:10 +12:00
/*NOTE: This can be extended in case we realize multiple swatch viewers... It
should be sufficient to map
a swatch pointer to its associated cache data - the advantage being that cache
resources are shared at the
2016-03-19 06:57:51 +13:00
same scene zoom.*/
class SwatchCacheManager final : public TFxCacheManagerDelegate {
2016-06-15 18:43:10 +12:00
T_RENDER_RESOURCE_MANAGER
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
unsigned long m_setFxId;
std::set<unsigned long> m_childrenFxIds;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
std::set<TCacheResourceP> m_genericCacheContainer;
std::set<TCacheResourceP> m_swatchCacheContainer;
TCacheResourceP m_currEditedFxResult;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
QMutex m_mutex;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
SwatchCacheManager() {}
~SwatchCacheManager() {}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
static SwatchCacheManager *instance();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
void setFx(const TFxP &actualFx);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
void clearSwatchResults();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
void getResource(TCacheResourceP &resource, const std::string &alias,
const TFxP &fx, double frame, const TRenderSettings &rs,
2016-06-19 20:06:29 +12:00
ResourceDeclaration *resData) override;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// void onRenderInstanceStart(unsigned long renderId);
// void onRenderInstanceEnd(unsigned long renderId);
2016-03-19 06:57:51 +13:00
2016-06-19 20:06:29 +12:00
bool renderHasOwnership() override { return false; }
2016-03-19 06:57:51 +13:00
};
//*****************************************************************************************
// Manager generator
//*****************************************************************************************
class SwatchCacheManagerGenerator final
: public TRenderResourceManagerGenerator {
2016-06-19 20:06:29 +12:00
TRenderResourceManager *operator()(void) override {
2016-06-15 18:43:10 +12:00
// return new TPassiveCacheManager;
return SwatchCacheManager::instance();
}
2016-03-19 06:57:51 +13:00
};
2016-06-15 18:43:10 +12:00
MANAGER_FILESCOPE_DECLARATION_DEP(SwatchCacheManager,
SwatchCacheManagerGenerator,
TFxCacheManager::deps())
2016-03-19 06:57:51 +13:00
//=============================================================================
2016-06-15 18:43:10 +12:00
namespace {
2016-03-19 06:57:51 +13:00
//-----------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
//! Abilita o disabilita la cache nell'effetto \b fx di \b frame in funzione di
//! \b on
void setFxForCaching(TFx *fx) {
SwatchCacheManager::instance()->setFx(fx);
TPassiveCacheManager::instance()->releaseContextNamesWithPrefix("S");
2016-03-19 06:57:51 +13:00
}
//-----------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
//! Se name finisce con suffix ritorna la parte iniziale, altrimenti ""
std::string matchSuffix(std::string name, std::string suffix) {
if (name.length() <= suffix.length()) return "";
int i = name.length() - suffix.length();
if (name.substr(i) == suffix)
return name.substr(0, i);
else
return "";
2016-03-19 06:57:51 +13:00
}
//-----------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
TRaster32P createCrossIcon() {
TRaster32P crossIcon = TRaster32P(7, 7);
// m_crossIcon e' utilizzata per evidenziare gli eventuali \b Point
// memorizzati in \b m_points.
crossIcon->fill(TPixel32(0, 0, 0, 0));
TPixel32 *c = crossIcon->pixels(3) + 3;
for (int i = 1; i <= 3; i++)
c[i] = c[-i] = c[7 * i] = c[-7 * i] =
(i & 1) == 0 ? TPixel32::White : TPixel32::Red;
return crossIcon;
2016-03-19 06:57:51 +13:00
}
//-----------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
//! Disegna una freccia lunga \b len pixel.
/*!La punta della freccia si trova a coordinate (0,ly/2), la coda a
* (len-1,ly/2).
2022-02-25 21:33:12 +13:00
*/
2016-06-15 18:43:10 +12:00
TRaster32P createArrowShape(int len) {
2022-02-25 21:33:12 +13:00
int d = 5;
2016-06-15 18:43:10 +12:00
if (len < d) len = d;
TPixel32 c0(210, 210, 210);
TPixel32 c1(10, 10, 10);
TRaster32P ras(len, d * 2 + 1);
ras->clear();
ras->lock();
TPixel32 *pix = ras->pixels(d);
int x = 0;
for (x = 0; x < len; x++) pix[x] = (x & 8) == 0 ? c0 : c1;
for (x = 1; x < d; x++)
for (int y = -x; y < x; y++) {
assert(ras->getBounds().contains(TPoint(x, y + d)));
pix[len * y + x] = c0;
}
ras->unlock();
return ras;
}
//-----------------------------------------------------------------------------
// Preso da sceneViewer.cpp quando si spostera' lo SceneViewer in toonzqt
// mettere
2016-03-19 06:57:51 +13:00
// il codice in comune!
#define ZOOMLEVELS 30
#define NOZOOMINDEX 20
2016-06-15 18:43:10 +12:00
double ZoomFactors[ZOOMLEVELS] = {
0.001, 0.002, 0.003, 0.004, 0.005, 0.007, 0.01, 0.015, 0.02, 0.03,
0.04, 0.05, 0.0625, 0.0833, 0.125, 0.167, 0.25, 0.333, 0.5, 0.667,
1, 2, 3, 4, 5, 6, 7, 8, 12, 16};
double getQuantizedZoomFactor(double zf, bool forward) {
2020-04-12 17:19:20 +12:00
if ((forward && zf > ZoomFactors[ZOOMLEVELS - 1]) ||
2016-06-15 18:43:10 +12:00
areAlmostEqual(zf, ZoomFactors[ZOOMLEVELS - 1], 1e-5))
return zf;
2020-04-12 17:19:20 +12:00
else if ((!forward && zf < ZoomFactors[0]) ||
2016-06-15 18:43:10 +12:00
areAlmostEqual(zf, ZoomFactors[0], 1e-5))
return zf;
assert((!forward && zf > ZoomFactors[0]) ||
(forward && zf < ZoomFactors[ZOOMLEVELS - 1]));
int i = 0;
for (i = 0; i <= ZOOMLEVELS - 1; i++)
if (areAlmostEqual(zf, ZoomFactors[i], 1e-5)) zf = ZoomFactors[i];
if (forward && zf < ZoomFactors[0])
return ZoomFactors[0];
else if (!forward && zf > ZoomFactors[ZOOMLEVELS - 1])
return ZoomFactors[ZOOMLEVELS - 1];
for (i = 0; i < ZOOMLEVELS - 1; i++)
if (ZoomFactors[i + 1] - zf >= 0 && zf - ZoomFactors[i] >= 0) {
if (forward && ZoomFactors[i + 1] == zf)
return ZoomFactors[i + 2];
else if (!forward && ZoomFactors[i] == zf)
return ZoomFactors[i - 1];
else
return forward ? ZoomFactors[i + 1] : ZoomFactors[i];
}
return ZoomFactors[NOZOOMINDEX];
}
//-----------------------------------------------------------------------------
bool suspendedRendering = false; // Global vars for swatch rendering suspension
2016-03-19 06:57:51 +13:00
QEventLoop *waitingLoop = 0;
2016-06-15 18:43:10 +12:00
int submittedTasks = 0;
2016-03-19 06:57:51 +13:00
//-----------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
} // namespace
2016-03-19 06:57:51 +13:00
//=============================================================================
//=============================================================================
// SwatchViewer
//-----------------------------------------------------------------------------
#if QT_VERSION >= 0x050500
SwatchViewer::SwatchViewer(QWidget *parent, Qt::WindowFlags flags)
#else
SwatchViewer::SwatchViewer(QWidget *parent, Qt::WFlags flags)
#endif
2016-06-15 18:43:10 +12:00
: QWidget(parent, flags)
, m_fx(0)
, m_actualFxClone(0)
, m_mouseButton(Qt::NoButton)
, m_selectedPoint(0)
, m_pointPosDelta(TPointD())
, m_enabled(false)
, m_content()
, m_aff(TAffine())
, m_fxAff(TAffine())
, m_cameraRect()
, m_bgPainter(0)
, m_pos(TPoint())
, m_firstPos(TPoint())
, m_oldContent()
, m_curContent()
, m_executor()
, m_firstEnabled(true) {
2016-06-15 18:43:10 +12:00
// setMinimumSize(150,150);
setMinimumHeight(150);
setFixedWidth(150);
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
m_raster = TRaster32P(width(), height());
m_crossIcon = createCrossIcon();
setFocusPolicy(Qt::StrongFocus);
m_executor.setDedicatedThreads(true);
m_executor.setMaxActiveTasks(1);
m_renderer.enablePrecomputing(false);
setAttribute(Qt::WA_AcceptTouchEvents);
grabGesture(Qt::SwipeGesture);
grabGesture(Qt::PanGesture);
grabGesture(Qt::PinchGesture);
2016-03-19 06:57:51 +13:00
}
//-----------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
SwatchViewer::~SwatchViewer() {}
2016-03-19 06:57:51 +13:00
//-----------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
//! This static method is used to temporarily suspend all swatch-related render
//! processing, typically because the rendering scene is being deleted.
//! When a suspension is invoked, all further rendering requests made to
//! swatch viewers are silently rejected, while currently active or scheduled
//! ones
//! are canceled and waited for completion.
void SwatchViewer::suspendRendering(bool suspend, bool blocking) {
suspendedRendering = suspend;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (suspend && submittedTasks > 0 && blocking) {
QEventLoop loop;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
waitingLoop = &loop;
loop.exec();
waitingLoop = 0;
}
2016-03-19 06:57:51 +13:00
}
//-----------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void SwatchViewer::setCameraSize(const TDimension &cameraSize) {
TRect cameraRect(cameraSize);
if (cameraRect != m_cameraRect) {
m_cameraRect = cameraRect;
updateSize(size()); // Invoke a size update to adapt the widget to the new
// camera ratio
}
2016-03-19 06:57:51 +13:00
}
//-----------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void SwatchViewer::setFx(const TFxP &fx, const TFxP &actualFx, int frame) {
m_fx = m_actualFxClone = fx;
m_frame = frame;
m_points.clear();
m_pointPairs.clear();
if (!fx) {
::setFxForCaching(0);
computeContent();
return;
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// abilita la cache nel nuovo effetto corrente
::setFxForCaching(actualFx.getPointer());
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (NaAffineFx *affFx = dynamic_cast<NaAffineFx *>(m_fx.getPointer()))
m_fxAff = affFx->getPlacement(m_frame);
else
m_fxAff = TAffine();
int i;
for (i = 0; i < actualFx->getParams()->getParamCount(); i++) {
TPointParam *pointParam =
dynamic_cast<TPointParam *>(actualFx->getParams()->getParam(i));
if (pointParam) m_points.push_back(Point(i, pointParam));
}
// cerco i segmenti
int n = m_points.size();
for (i = 0; i < n; i++) {
std::string name = m_points[i].m_param->getName();
std::string prefix = matchSuffix(name, "_a");
if (prefix == "") continue;
std::string otherName = prefix + "_b";
int j;
for (j = 0; j < n; j++)
if (i != j && m_points[j].m_param->getName() == otherName) break;
if (j < n) {
m_pointPairs.push_back(std::make_pair(i, j));
m_points[i].m_pairFlag = m_points[j].m_pairFlag = true;
}
}
computeContent();
}
//-----------------------------------------------------------------------------
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
void SwatchViewer::updateFrame(int frame) {
m_frame = frame;
computeContent();
update();
2016-03-19 06:57:51 +13:00
}
//-----------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void SwatchViewer::setEnable(bool enabled) {
if (m_enabled == enabled) return;
m_enabled = enabled;
if (m_enabled) {
if (m_firstEnabled) {
m_firstEnabled = false;
fitView();
}
2016-06-15 18:43:10 +12:00
computeContent();
} else
2016-06-15 18:43:10 +12:00
update();
2016-03-19 06:57:51 +13:00
}
//-----------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void SwatchViewer::updateSize(const QSize &size) {
int h = size.height();
double ratio = m_cameraRect.getLy() > 0
? m_cameraRect.getLx() / (double)m_cameraRect.getLy()
: 1.0;
int w = std::min((int)(h * ratio), parentWidget()->width());
setFixedWidth(w);
if (w > 2 && h > 2)
m_raster = TRaster32P(TDimension(w, h));
else
m_raster = TRaster32P();
2016-03-19 06:57:51 +13:00
}
//-----------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void SwatchViewer::setBgPainter(TPixel32 color1, TPixel32 color2) {
if (color2 == TPixel32())
m_bgPainter = new SolidColorBgPainter("", color1);
else
m_bgPainter = new CheckboardBgPainter("", color1, color2);
updateRaster();
2016-03-19 06:57:51 +13:00
}
//-----------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
TPoint SwatchViewer::world2win(const TPointD &p) const {
TPointD center(width() * 0.5, height() * 0.5);
return convert(m_aff * m_fxAff * p + center);
2016-03-19 06:57:51 +13:00
}
//-----------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
TPointD SwatchViewer::win2world(const TPoint &p) const {
TPointD center(width() * 0.5, height() * 0.5);
TPointD point = TPointD(convert(p) - center);
return m_fxAff.inv() * m_aff.inv() * TPointD(point.x, -point.y);
2016-03-19 06:57:51 +13:00
}
//-----------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void SwatchViewer::zoom(const TPoint &pos, double factor) {
if (!m_content || factor == 1.0) return;
TPointD delta = convert(pos);
double scale = m_aff.det();
TAffine aff;
if ((scale < 2000 || factor < 1) && (scale > 0.004 || factor > 1)) {
aff = TTranslation(delta) * TScale(factor) * TTranslation(-delta);
setAff(aff * m_aff);
}
2016-03-19 06:57:51 +13:00
}
//-----------------------------------------------------------------------------
void SwatchViewer::resetView() { setAff(TAffine()); }
//-----------------------------------------------------------------------------
void SwatchViewer::fitView() {
if (m_cameraRect.isEmpty()) return;
double imageScale = std::min(
width() / ((double)getCameraSize().lx * (m_cameraMode ? 1 : 0.44)),
height() / ((double)getCameraSize().ly * (m_cameraMode ? 1 : 0.44)));
TAffine fitAffine = TScale(imageScale, imageScale);
fitAffine.a13 = 0;
fitAffine.a23 = 0;
setAff(fitAffine);
}
//-----------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void SwatchViewer::zoom(bool forward, bool reset) {
double scale2 = m_aff.det();
if (reset || ((scale2 < 2000 || !forward) && (scale2 > 0.004 || forward))) {
double oldZoomScale = sqrt(scale2);
double zoomScale =
reset ? 1 : getQuantizedZoomFactor(oldZoomScale, forward);
TAffine aff = TScale(zoomScale / oldZoomScale);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
setAff(aff * m_aff);
}
2016-03-19 06:57:51 +13:00
}
void SwatchViewer::pan(const TPoint &delta) {
TPointD step = convert(delta);
setAff(TTranslation(step.x, -step.y) * m_aff);
}
2016-03-19 06:57:51 +13:00
//-----------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void SwatchViewer::computeContent() {
if (suspendedRendering) return;
if (!m_enabled) return;
if (!m_raster) return;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Clear the swatch cache when the zoom scale has changed (cache results are
// not compatible
// between different scale levels)
if (m_aff.a11 != m_contentAff.a11 || m_panning)
2016-06-15 18:43:10 +12:00
SwatchCacheManager::instance()->clearSwatchResults();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
TRect rect(0, 0, width() - 1, height() - 1);
TDimension size = rect.getSize();
assert(m_raster->getSize() == size);
if (m_fx) {
// TFxP fx = makeAffine(m_fx, m_aff);
// TRasterFxP rasterFx = fx;
TRasterFxP rasterFx = m_fx;
if (rasterFx) {
m_executor.cancelAll();
m_executor.addTask(
new ContentRender(rasterFx.getPointer(), m_frame, size, this));
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
submittedTasks++;
return;
} else {
m_content = TRaster32P(size);
m_content->fill(TPixel32::Red);
}
} else {
m_content = TRaster32P(size);
m_content->fill(TPixel32::Transparent);
}
updateRaster();
2016-03-19 06:57:51 +13:00
}
//-----------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void SwatchViewer::updateRaster() {
QMutexLocker sl(&m_mutex);
if (!m_enabled) return;
if (!m_raster) return;
if (m_bgPainter)
m_bgPainter->paint(m_raster);
else
m_raster->fill(TPixel32(127, 127, 127));
if (m_cameraMode && !m_cameraRect.isEmpty()) {
TPointD p0(m_cameraRect.x0, m_cameraRect.y0);
TPointD p1(m_cameraRect.x1, m_cameraRect.y1);
TPointD center(width() * 0.5, height() * 0.5);
TPoint transP0 = convert(m_aff * p0 + center);
TPoint transP1 = convert(m_aff * p1 + center);
TPoint p = convert(
(TPointD(transP1.x, transP1.y) - TPointD(transP0.x, transP0.y)) * 0.5);
TRect rect(transP0 - p, transP1 - p);
m_content->fillOutside(rect, TPixel32(255, 0, 0, 255));
m_content->fillOutside(rect.enlarge(TDimension(1, 1)),
TPixel32(0, 0, 0, 0));
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (m_content) TRop::over(m_raster, m_content);
int i;
for (i = 0; i < (int)m_points.size(); i++) {
if (m_points[i].m_pairFlag) continue;
TPoint p = world2win(m_points[i].m_param->getValue(m_frame));
TRop::over(m_raster, m_crossIcon, p - TPoint(4, 4));
}
for (i = 0; i < (int)m_pointPairs.size(); i++) {
int i0 = m_pointPairs[i].first;
int i1 = m_pointPairs[i].second;
assert(i0 != i1);
assert(0 <= i0 && i0 < (int)m_points.size());
assert(0 <= i1 && i1 < (int)m_points.size());
2022-02-25 21:33:12 +13:00
TPoint p0 = world2win(m_points[i0].m_param->getValue(m_frame));
TPoint p1 = world2win(m_points[i1].m_param->getValue(m_frame));
TPoint delta = p1 - p0;
int len = tround(sqrt((double)(delta * delta)));
double phi = 0;
2016-06-15 18:43:10 +12:00
if (len > 0) phi = atan2((double)delta.y, (double)delta.x) * M_180_PI;
if (len > 500) {
// puo' succedere per zoom molto grandi.
// dovrei fare qualcosa, ma non so bene che cosa e non credo sia
// importantissimo
} else {
TRaster32P arrowShape = createArrowShape(len);
TAffine aff =
TRotation(phi).place(0, arrowShape->getLy() / 2, p0.x, p0.y);
TRop::over(m_raster, arrowShape, aff);
// verrebbe la tentazione di usare il filtro TRop::Bilinear (piu'veloce),
// ma la qualita' ne risente molto
}
}
update();
}
//-----------------------------------------------------------------------------
void SwatchViewer::setContent(const TRaster32P &content,
const TAffine &contentAff) {
m_content = content;
m_contentAff = contentAff;
updateRaster();
update();
}
//-----------------------------------------------------------------------------
void SwatchViewer::setAff(const TAffine &aff) {
m_aff = aff;
computeContent();
}
//-----------------------------------------------------------------------------
void SwatchViewer::paintEvent(QPaintEvent *event) {
QPainter p(this);
QRect rectBox = rect();
if (!m_enabled)
p.fillRect(rectBox, QBrush(QColor(120, 120, 120)));
else {
if (!m_raster) return;
QImage image = rasterToQImage(m_raster);
p.drawImage(rectBox, image);
if (m_computing) {
QPen pen;
pen.setColor(Qt::red);
pen.setWidth(3);
p.setPen(pen);
p.drawRect(rectBox.adjusted(0, 0, -1, -1));
}
}
}
//-----------------------------------------------------------------------------
void SwatchViewer::resizeEvent(QResizeEvent *re) {
int oldHeight = re->oldSize().height();
int newHeight = re->size().height();
if (oldHeight != newHeight) {
updateSize(QSize(newHeight, newHeight));
computeContent();
}
}
//-----------------------------------------------------------------------------
void SwatchViewer::mousePressEvent(QMouseEvent *event) {
// qDebug() << "[mousePressEvent]";
if (m_gestureActive && m_touchDevice == QTouchDevice::TouchScreen &&
!m_stylusUsed) {
return;
}
2016-06-15 18:43:10 +12:00
TPoint pos = TPoint(event->pos().x(), event->pos().y());
m_mouseButton = event->button();
if (m_mouseButton == Qt::LeftButton) {
m_selectedPoint = -1;
if (m_points.empty()) return;
TPointD p = win2world(pos);
TPointD q;
double minDist2 = 1e6;
int i;
for (i = 0; i < (int)m_points.size(); i++) {
TPointD paramPoint = m_points[i].m_param->getValue(m_frame);
double d2 = tdistance2(p, paramPoint);
if (m_selectedPoint < 0 || d2 < minDist2) {
m_selectedPoint = i;
minDist2 = d2;
q = paramPoint;
}
}
if (m_selectedPoint >= 0) {
m_pointPosDelta = q - p;
TPoint d = world2win(p) - world2win(q);
int dd2 = d.x * d.x + d.y * d.y;
if (dd2 > 400)
m_selectedPoint = -1;
else {
std::string name = m_points[m_selectedPoint].m_param->getName();
std::string prefix = matchSuffix(name, "_b");
if (prefix != "") {
std::string otherName = prefix + "_a";
int n = (int)m_points.size();
int j;
for (j = 0; j < n; j++)
if (i != j && m_points[j].m_param->getName() == otherName) break;
if (j < n) {
TPoint dist = world2win(m_points[m_selectedPoint].m_param->getValue(
m_frame)) -
world2win(m_points[j].m_param->getValue(m_frame));
int ddist2 = dist.x * dist.x + dist.y * dist.y;
if (ddist2 < 100) m_selectedPoint = j;
}
}
}
}
update();
} else if (m_mouseButton == Qt::MidButton) {
m_pos = pos;
m_firstPos = pos;
m_oldContent = getContent();
if (m_oldContent)
m_curContent = TRaster32P(m_oldContent->getSize());
else
m_curContent = TRaster32P();
}
}
//-----------------------------------------------------------------------------
void SwatchViewer::mouseMoveEvent(QMouseEvent *event) {
if (m_gestureActive && m_touchDevice == QTouchDevice::TouchScreen &&
!m_stylusUsed) {
return;
}
2016-06-15 18:43:10 +12:00
TPoint pos = TPoint(event->pos().x(), event->pos().y());
if (m_mouseButton == Qt::LeftButton) {
if (m_selectedPoint < 0 || m_selectedPoint >= (int)m_points.size()) return;
TPointD p = win2world(pos) + m_pointPosDelta;
int index = m_points[m_selectedPoint].m_index;
emit pointPositionChanged(index, p);
// It seems that mouse move events may jeopardize our rendering notification
// deliveries
// - probably because Qt considers them 'higher priority stuff' with respect
// to common queued signal-slot connections.
// In order to allow processing of the ContentRender::started() and
// ContentRender::finished()
// signals, we need to process events. We will exclude user input events (ie
// other mouse events)
// to avoid unnecessary recursions.
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
} else if (m_mouseButton == Qt::MidButton) {
pan(pos - m_pos);
m_pos = pos;
2016-06-15 18:43:10 +12:00
}
}
//-----------------------------------------------------------------------------
void SwatchViewer::mouseReleaseEvent(QMouseEvent *event) {
m_mouseButton = Qt::NoButton;
m_selectedPoint = -1;
TPoint pos = TPoint(event->pos().x(), event->pos().y());
if (event->button() == Qt::MidButton) {
if (!m_oldContent || !m_curContent) return;
TPointD p = convert(pos - m_pos);
setAff(TTranslation(p.x, -p.y) * m_aff);
update();
}
m_gestureActive = false;
m_zooming = false;
m_panning = false;
m_stylusUsed = false;
2016-06-15 18:43:10 +12:00
}
//-----------------------------------------------------------------------------
void SwatchViewer::wheelEvent(QWheelEvent *event) {
int delta = 0;
switch (event->source()) {
case Qt::MouseEventNotSynthesized: {
if (event->modifiers() & Qt::AltModifier)
delta = event->angleDelta().x();
else
delta = event->angleDelta().y();
break;
}
case Qt::MouseEventSynthesizedBySystem: {
QPoint numPixels = event->pixelDelta();
QPoint numDegrees = event->angleDelta() / 8;
if (!numPixels.isNull()) {
delta = event->pixelDelta().y();
} else if (!numDegrees.isNull()) {
QPoint numSteps = numDegrees / 15;
delta = numSteps.y();
}
break;
}
default: // Qt::MouseEventSynthesizedByQt,
// Qt::MouseEventSynthesizedByApplication
2022-02-25 21:33:12 +13:00
{
std::cout << "not supported event: Qt::MouseEventSynthesizedByQt, "
"Qt::MouseEventSynthesizedByApplication"
<< std::endl;
break;
}
} // end switch
if (abs(delta) > 0) {
if ((m_gestureActive == true &&
m_touchDevice == QTouchDevice::TouchScreen) ||
m_gestureActive == false) {
TPoint center(event->pos().x() - width() / 2,
-event->pos().y() + height() / 2);
zoom(center, exp(0.001 * event->delta()));
}
}
event->accept();
2016-06-15 18:43:10 +12:00
}
//-----------------------------------------------------------------------------
void SwatchViewer::keyPressEvent(QKeyEvent *event) {
int key = event->key();
std::string keyStr =
QKeySequence(key + event->modifiers()).toString().toStdString();
QAction *action = CommandManager::instance()->getActionFromShortcut(keyStr);
if (action) {
std::string actionId = CommandManager::instance()->getIdFromAction(action);
if (actionId == V_ZoomFit) {
fitView();
return;
} else if (actionId == V_ZoomReset) {
resetView();
return;
}
}
2016-06-15 18:43:10 +12:00
if (key == '+' || key == '-' || key == '0') {
zoom(key == '+', key == '0');
}
}
//-----------------------------------------------------------------------------
void SwatchViewer::hideEvent(QHideEvent *event) {
// Clear the swatch cache
::setFxForCaching(0);
2016-03-19 06:57:51 +13:00
}
//-------------------------------------------------------------------------------
void SwatchViewer::mouseDoubleClickEvent(QMouseEvent *event) {
// qDebug() << "[mouseDoubleClickEvent]";
if (m_gestureActive && !m_stylusUsed) {
m_gestureActive = false;
fitView();
return;
}
}
//------------------------------------------------------------------
void SwatchViewer::contextMenuEvent(QContextMenuEvent *event) {
QMenu *menu = new QMenu(this);
QAction *reset = menu->addAction(tr("Reset View"));
reset->setShortcut(
QKeySequence(CommandManager::instance()->getKeyFromId(V_ZoomReset)));
connect(reset, SIGNAL(triggered()), SLOT(resetView()));
QAction *fit = menu->addAction(tr("Fit To Window"));
fit->setShortcut(
QKeySequence(CommandManager::instance()->getKeyFromId(V_ZoomFit)));
connect(fit, SIGNAL(triggered()), SLOT(fitView()));
menu->exec(event->globalPos());
delete menu;
update();
}
//------------------------------------------------------------------
void SwatchViewer::tabletEvent(QTabletEvent *e) {
// qDebug() << "[tabletEvent]";
if (e->type() == QTabletEvent::TabletPress) {
m_stylusUsed = e->pointerType() ? true : false;
} else if (e->type() == QTabletEvent::TabletRelease) {
m_stylusUsed = false;
}
e->accept();
}
//------------------------------------------------------------------
void SwatchViewer::gestureEvent(QGestureEvent *e) {
// qDebug() << "[gestureEvent]";
m_gestureActive = false;
if (QGesture *swipe = e->gesture(Qt::SwipeGesture)) {
m_gestureActive = true;
} else if (QGesture *pan = e->gesture(Qt::PanGesture)) {
m_gestureActive = true;
}
if (QGesture *pinch = e->gesture(Qt::PinchGesture)) {
QPinchGesture *gesture = static_cast<QPinchGesture *>(pinch);
QPinchGesture::ChangeFlags changeFlags = gesture->changeFlags();
QPoint firstCenter = gesture->centerPoint().toPoint();
if (m_touchDevice == QTouchDevice::TouchScreen)
firstCenter = mapFromGlobal(firstCenter);
if (gesture->state() == Qt::GestureStarted) {
m_gestureActive = true;
} else if (gesture->state() == Qt::GestureFinished) {
m_gestureActive = false;
m_zooming = false;
m_scaleFactor = 0.0;
} else {
if (changeFlags & QPinchGesture::ScaleFactorChanged) {
double scaleFactor = gesture->scaleFactor();
// the scale factor makes for too sensitive scaling
// divide the change in half
if (scaleFactor > 1) {
double decimalValue = scaleFactor - 1;
decimalValue /= 1.5;
scaleFactor = 1 + decimalValue;
} else if (scaleFactor < 1) {
double decimalValue = 1 - scaleFactor;
decimalValue /= 1.5;
scaleFactor = 1 - decimalValue;
}
if (!m_zooming) {
double delta = scaleFactor - 1;
m_scaleFactor += delta;
if (m_scaleFactor > .2 || m_scaleFactor < -.2) {
m_zooming = true;
}
}
if (m_zooming) {
TPoint center(firstCenter.x() - width() / 2,
-firstCenter.y() + height() / 2);
zoom(center, scaleFactor);
m_panning = false;
}
m_gestureActive = true;
}
if (changeFlags & QPinchGesture::CenterPointChanged) {
QPointF centerDelta =
(gesture->centerPoint()) - (gesture->lastCenterPoint());
if (centerDelta.manhattanLength() > 1) {
// panQt(centerDelta.toPoint());
}
m_gestureActive = true;
}
}
}
e->accept();
}
void SwatchViewer::touchEvent(QTouchEvent *e, int type) {
// qDebug() << "[touchEvent]";
if (type == QEvent::TouchBegin) {
m_touchActive = true;
m_firstPanPoint = e->touchPoints().at(0).pos();
// obtain device type
m_touchDevice = e->device()->type();
} else if (m_touchActive) {
// touchpads must have 2 finger panning for tools and navigation to be
// functional on other devices, 1 finger panning is preferred
if ((e->touchPoints().count() == 2 &&
m_touchDevice == QTouchDevice::TouchPad) ||
(e->touchPoints().count() == 1 &&
m_touchDevice == QTouchDevice::TouchScreen)) {
QTouchEvent::TouchPoint panPoint = e->touchPoints().at(0);
if (!m_panning) {
QPointF deltaPoint = panPoint.pos() - m_firstPanPoint;
// minimize accidental and jerky zooming/rotating during 2 finger
// panning
if ((deltaPoint.manhattanLength() > 100) && !m_zooming) {
m_panning = true;
}
}
if (m_panning) {
QPoint curPos = panPoint.pos().toPoint();
QPoint lastPos = panPoint.lastPos().toPoint();
TPoint centerDelta =
TPoint(curPos.x(), curPos.y()) - TPoint(lastPos.x(), lastPos.y());
pan(centerDelta);
}
}
}
if (type == QEvent::TouchEnd || type == QEvent::TouchCancel) {
m_touchActive = false;
m_panning = false;
}
e->accept();
}
bool SwatchViewer::event(QEvent *e) {
/*
switch (e->type()) {
case QEvent::TabletPress: {
QTabletEvent *te = static_cast<QTabletEvent *>(e);
qDebug() << "[event] TabletPress: pointerType(" << te->pointerType()
<< ") device(" << te->device() << ")";
} break;
case QEvent::TabletRelease:
qDebug() << "[event] TabletRelease";
break;
case QEvent::TouchBegin:
qDebug() << "[event] TouchBegin";
break;
case QEvent::TouchEnd:
qDebug() << "[event] TouchEnd";
break;
case QEvent::TouchCancel:
qDebug() << "[event] TouchCancel";
break;
case QEvent::MouseButtonPress:
qDebug() << "[event] MouseButtonPress";
break;
case QEvent::MouseButtonDblClick:
qDebug() << "[event] MouseButtonDblClick";
break;
case QEvent::MouseButtonRelease:
qDebug() << "[event] MouseButtonRelease";
break;
case QEvent::Gesture:
qDebug() << "[event] Gesture";
break;
default:
break;
}
*/
2022-02-25 21:33:12 +13:00
if (e->type() == QEvent::Gesture && CommandManager::instance()
->getAction(MI_TouchGestureControl)
->isChecked()) {
gestureEvent(static_cast<QGestureEvent *>(e));
return true;
}
if ((e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchEnd ||
e->type() == QEvent::TouchCancel || e->type() == QEvent::TouchUpdate) &&
CommandManager::instance()
->getAction(MI_TouchGestureControl)
->isChecked()) {
touchEvent(static_cast<QTouchEvent *>(e), e->type());
m_gestureActive = true;
return true;
}
return QWidget::event(e);
}
2016-03-19 06:57:51 +13:00
//=============================================================================
// SwatchViewer::ContentRender
//-----------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
SwatchViewer::ContentRender::ContentRender(TRasterFx *fx, int frame,
const TDimension &size,
SwatchViewer *viewer)
: m_fx(fx)
, m_raster(0)
, m_frame(frame)
, m_size(size)
, m_aff(viewer->m_aff)
, m_viewer(viewer)
, m_started(false) {
// Is there a less complicated way...?
connect(this, SIGNAL(started(TThread::RunnableP)), this,
SLOT(onStarted(TThread::RunnableP)));
connect(this, SIGNAL(finished(TThread::RunnableP)), this,
SLOT(onFinished(TThread::RunnableP)));
connect(this, SIGNAL(exception(TThread::RunnableP)), this,
SLOT(onFinished(TThread::RunnableP)));
connect(this, SIGNAL(canceled(TThread::RunnableP)), this,
SLOT(onCanceled(TThread::RunnableP)),
Qt::QueuedConnection); // Starts will need to come *strictly before*
// cancels
2022-02-25 21:33:12 +13:00
m_info.m_isSwatch = true;
m_info.m_affine = m_aff;
m_info.m_cameraBox = TRectD(-0.5 * TPointD(m_size.lx, m_size.ly),
TDimensionD(m_size.lx, m_size.ly));
if (m_fx->getAlias(m_frame, m_info).find("plasticDeformerFx") !=
std::string::npos &&
QThread::currentThread() == qGuiApp->thread()) {
m_info.m_offScreenSurface.reset(new QOffscreenSurface());
m_info.m_offScreenSurface->setFormat(QSurfaceFormat::defaultFormat());
m_info.m_offScreenSurface->create();
}
2016-03-19 06:57:51 +13:00
}
//-----------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
SwatchViewer::ContentRender::~ContentRender() {}
2016-03-19 06:57:51 +13:00
//-----------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void SwatchViewer::ContentRender::run() {
if (suspendedRendering) return;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
unsigned long renderId = TRenderer::buildRenderId();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
TPassiveCacheManager::instance()->setContextName(renderId, "S");
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
m_viewer->m_renderer.install(renderId);
m_viewer->m_renderer.declareRenderStart(renderId);
m_viewer->m_renderer.declareFrameStart(m_frame);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
TTile tile;
m_fx->allocateAndCompute(tile, -0.5 * TPointD(m_size.lx, m_size.ly), m_size,
2022-02-25 21:33:12 +13:00
0, (double)m_frame, m_info);
2016-06-15 18:43:10 +12:00
m_raster = tile.getRaster();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
m_viewer->m_renderer.declareFrameEnd(m_frame);
m_viewer->m_renderer.declareRenderEnd(renderId);
m_viewer->m_renderer.uninstall();
2016-03-19 06:57:51 +13:00
}
//-----------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
int SwatchViewer::ContentRender::taskLoad() { return 100; }
2016-03-19 06:57:51 +13:00
//-----------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void SwatchViewer::ContentRender::onStarted(TThread::RunnableP task) {
m_started = true;
m_viewer->m_computing = true;
m_viewer->update();
2016-03-19 06:57:51 +13:00
}
//-----------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void SwatchViewer::ContentRender::onFinished(TThread::RunnableP task) {
m_viewer->m_computing = false;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
m_viewer->setContent(m_raster, m_aff);
if ((--submittedTasks == 0) && waitingLoop) waitingLoop->quit();
2016-03-19 06:57:51 +13:00
}
//-----------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void SwatchViewer::ContentRender::onCanceled(TThread::RunnableP task) {
if (m_started) return;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if ((--submittedTasks == 0) && waitingLoop) waitingLoop->quit();
2016-03-19 06:57:51 +13:00
}
//*************************************************************************************
// Swatch cache manager implementation
//*************************************************************************************
2016-06-15 18:43:10 +12:00
SwatchCacheManager *SwatchCacheManager::instance() {
static SwatchCacheManager theInstance;
return &theInstance;
2016-03-19 06:57:51 +13:00
}
//-----------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void SwatchCacheManager::setFx(const TFxP &fx) {
QMutexLocker locker(&m_mutex);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Update the fxs id data
if (fx == TFxP()) {
// Clear if no fx is set
m_setFxId = 0;
m_childrenFxIds.clear();
} else {
m_setFxId = fx->getIdentifier();
m_childrenFxIds.clear();
assert(m_setFxId != 0);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
TRasterFx *rfx = dynamic_cast<TRasterFx *>(fx.getPointer());
assert(rfx);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
for (int i = 0; i < fx->getInputPortCount(); ++i) {
// Fxs not allowing cache on the input port are skipped
if (!rfx->allowUserCacheOnPort(i)) continue;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
TFxPort *iport = fx->getInputPort(i);
if (iport && iport->isConnected()) {
TFx *child = iport->getFx();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// In the zerary case, extract the actual fx
TZeraryColumnFx *zcfx = dynamic_cast<TZeraryColumnFx *>(child);
2022-02-25 21:33:12 +13:00
if (zcfx) child = zcfx->getZeraryFx();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
assert(child && child->getIdentifier() != 0);
m_childrenFxIds.insert(child->getIdentifier());
}
}
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// NOTE: Check if this should be avoided in some case...
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Release the locks and clear the resources
if (m_currEditedFxResult) m_currEditedFxResult->releaseLock();
m_currEditedFxResult = TCacheResourceP();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
std::set<TCacheResourceP>::iterator it;
for (it = m_swatchCacheContainer.begin(); it != m_swatchCacheContainer.end();
++it)
(*it)->releaseLock();
m_swatchCacheContainer.clear();
2016-03-19 06:57:51 +13:00
#ifdef USE_SQLITE_HDPOOL
2016-06-15 18:43:10 +12:00
TCacheResourcePool::instance()->releaseReferences("S");
2016-03-19 06:57:51 +13:00
#else
2016-06-15 18:43:10 +12:00
for (it = m_genericCacheContainer.begin();
it != m_genericCacheContainer.end(); ++it)
(*it)->releaseLock();
m_genericCacheContainer.clear();
2016-03-19 06:57:51 +13:00
#endif
}
//-----------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
// This method is invoked by the swatch when its scene scale changes. Find it
// above.
void SwatchCacheManager::clearSwatchResults() {
QMutexLocker locker(&m_mutex);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (m_currEditedFxResult) m_currEditedFxResult->releaseLock();
m_currEditedFxResult = TCacheResourceP();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
std::set<TCacheResourceP>::iterator it;
for (it = m_swatchCacheContainer.begin(); it != m_swatchCacheContainer.end();
++it)
(*it)->releaseLock();
m_swatchCacheContainer.clear();
2016-03-19 06:57:51 +13:00
}
//-----------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void SwatchCacheManager::getResource(TCacheResourceP &resource,
const std::string &alias, const TFxP &fx,
double frame, const TRenderSettings &rs,
ResourceDeclaration *resData) {
// Only FX RESULTS are interesting - plus, avoid if we're not currently
// editing an fx.
if (!(fx && m_setFxId > 0)) return;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
QMutexLocker locker(&m_mutex);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Cache the result in case the fx's id is among the stored ones.
unsigned long fxId = fx->getIdentifier();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (fxId == m_setFxId && rs.m_isSwatch) {
if (!resource) resource = TCacheResourceP(alias, true);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
resource->addLock();
if (m_currEditedFxResult) m_currEditedFxResult->releaseLock();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
m_currEditedFxResult = resource;
return;
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (m_childrenFxIds.find(fxId) != m_childrenFxIds.end()) {
if (!resource) resource = TCacheResourceP(alias, true);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (rs.m_isSwatch) {
std::set<TCacheResourceP>::iterator it =
m_swatchCacheContainer.find(resource);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (it == m_swatchCacheContainer.end()) {
resource->addLock();
m_swatchCacheContainer.insert(resource);
}
} else {
2016-03-19 06:57:51 +13:00
#ifdef USE_SQLITE_HDPOOL
2016-06-15 18:43:10 +12:00
resource->enableBackup();
TCacheResourcePool::instance()->addReference(resource, "S");
2016-03-19 06:57:51 +13:00
#else
2016-06-15 18:43:10 +12:00
std::set<TCacheResourceP>::iterator it =
m_genericCacheContainer.find(resource);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (it == m_genericCacheContainer.end()) {
resource->addLock();
m_genericCacheContainer.insert(resource);
}
2016-03-19 06:57:51 +13:00
#endif
2016-06-15 18:43:10 +12:00
}
}
2016-03-19 06:57:51 +13:00
}