Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonzqt/swatchviewer.h"
Toshihiro Shimizu 890ddd
#include "toonzqt/gutil.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <qpainter></qpainter>
Toshihiro Shimizu 890ddd
#include <qmouseevent></qmouseevent>
Toshihiro Shimizu 890ddd
#include <qresizeevent></qresizeevent>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "trasterfx.h"
Toshihiro Shimizu 890ddd
#include "toonz/tcolumnfx.h"
Toshihiro Shimizu 890ddd
#include "tparamcontainer.h"
Toshihiro Shimizu 890ddd
#include "tfxutil.h"
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// Rendering cache management includes
Toshihiro Shimizu 890ddd
#include "tfxcachemanager.h"
Toshihiro Shimizu 890ddd
#include "tcacheresourcepool.h"
Toshihiro Shimizu 890ddd
#include "tpassivecachemanager.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <qeventloop></qeventloop>
Toshihiro Shimizu 890ddd
#include <qcoreapplication></qcoreapplication>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using namespace TFxUtil;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//#define USE_SQLITE_HDPOOL
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//*************************************************************************************
Toshihiro Shimizu 890ddd
//    Swatch cache delegate
Toshihiro Shimizu 890ddd
//*************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*!
Shinya Kitaoka 120a6e
The swatch cache delegate is used to temporary store intermediate rendering
Shinya Kitaoka 120a6e
results
Toshihiro Shimizu 890ddd
in cache when an fx is being edited.
Shinya Kitaoka 120a6e
Input fxs of an edited fx are typically requested to produce the same results
Shinya Kitaoka 120a6e
multiple times
Shinya Kitaoka 120a6e
as parameters of their schematic parent change - so, caching these results is a
Shinya Kitaoka 120a6e
remunerative
Toshihiro Shimizu 890ddd
practice as long as the fx is open for edit.
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
This delegate stores resources on two different levels: one is directly related
Shinya Kitaoka 120a6e
to swatch rendering,
Toshihiro Shimizu 890ddd
while the other is used to cache results on the other rendering contexts.
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
In the swatch case, we store the above mentioned input results associated with
Shinya Kitaoka 120a6e
the current scene
Shinya Kitaoka 120a6e
scale, releasing them when the scene scale changes; plus, the resource
Shinya Kitaoka 120a6e
associated with the current
Toshihiro Shimizu 890ddd
output is also stored.
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
In other rendering contexts, the scene scale can be assumed constant - so the
Shinya Kitaoka 120a6e
above distinction
Shinya Kitaoka 120a6e
is unnecessary. All results from the input fxs are stored until the edited fx is
Shinya Kitaoka 120a6e
unset from the swatch.
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
Please observe that variations in the scene context - such as frame change,
Shinya Kitaoka 120a6e
schematic changes, scene changes
Shinya Kitaoka 120a6e
and so on - actually cause the fx to be re-set for edit in the swatch. Once this
Shinya Kitaoka 120a6e
happens, the previously
Toshihiro Shimizu 890ddd
stored results are conveniently flushed from the cache.
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
/*NOTE: This can be extended in case we realize multiple swatch viewers... It
Shinya Kitaoka 120a6e
should be sufficient to map
Shinya Kitaoka 120a6e
a swatch pointer to its associated cache data - the advantage being that cache
Shinya Kitaoka 120a6e
resources are shared at the
Toshihiro Shimizu 890ddd
same scene zoom.*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class SwatchCacheManager final : public TFxCacheManagerDelegate {
Shinya Kitaoka 120a6e
  T_RENDER_RESOURCE_MANAGER
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  unsigned long m_setFxId;
Shinya Kitaoka 120a6e
  std::set<unsigned long=""> m_childrenFxIds;</unsigned>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::set<tcacheresourcep> m_genericCacheContainer;</tcacheresourcep>
Shinya Kitaoka 120a6e
  std::set<tcacheresourcep> m_swatchCacheContainer;</tcacheresourcep>
Shinya Kitaoka 120a6e
  TCacheResourceP m_currEditedFxResult;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  QMutex m_mutex;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  SwatchCacheManager() {}
Shinya Kitaoka 120a6e
  ~SwatchCacheManager() {}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  static SwatchCacheManager *instance();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void setFx(const TFxP &actualFx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void clearSwatchResults();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void getResource(TCacheResourceP &resource, const std::string &alias,
Shinya Kitaoka 120a6e
                   const TFxP &fx, double frame, const TRenderSettings &rs,
Shinya Kitaoka 473e70
                   ResourceDeclaration *resData) override;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // void onRenderInstanceStart(unsigned long renderId);
Shinya Kitaoka 120a6e
  // void onRenderInstanceEnd(unsigned long renderId);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  bool renderHasOwnership() override { return false; }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//*****************************************************************************************
Toshihiro Shimizu 890ddd
//    Manager generator
Toshihiro Shimizu 890ddd
//*****************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class SwatchCacheManagerGenerator final
Shinya Kitaoka d1f6c4
    : public TRenderResourceManagerGenerator {
Shinya Kitaoka 473e70
  TRenderResourceManager *operator()(void) override {
Shinya Kitaoka 120a6e
    // return new TPassiveCacheManager;
Shinya Kitaoka 120a6e
    return SwatchCacheManager::instance();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
MANAGER_FILESCOPE_DECLARATION_DEP(SwatchCacheManager,
Shinya Kitaoka 120a6e
                                  SwatchCacheManagerGenerator,
Shinya Kitaoka 120a6e
                                  TFxCacheManager::deps())
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Abilita o disabilita la cache nell'effetto \b fx di \b frame in funzione di
Shinya Kitaoka 120a6e
//! \b on
Shinya Kitaoka 120a6e
void setFxForCaching(TFx *fx) {
Shinya Kitaoka 120a6e
  SwatchCacheManager::instance()->setFx(fx);
Shinya Kitaoka 120a6e
  TPassiveCacheManager::instance()->releaseContextNamesWithPrefix("S");
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Se name finisce con suffix ritorna la parte iniziale, altrimenti ""
Shinya Kitaoka 120a6e
std::string matchSuffix(std::string name, std::string suffix) {
Shinya Kitaoka 120a6e
  if (name.length() <= suffix.length()) return "";
Shinya Kitaoka 120a6e
  int i = name.length() - suffix.length();
Shinya Kitaoka 120a6e
  if (name.substr(i) == suffix)
Shinya Kitaoka 120a6e
    return name.substr(0, i);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    return "";
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TRaster32P createCrossIcon() {
Shinya Kitaoka 120a6e
  TRaster32P crossIcon = TRaster32P(7, 7);
Shinya Kitaoka 120a6e
  // m_crossIcon e' utilizzata per evidenziare gli eventuali \b Point
Shinya Kitaoka 120a6e
  // memorizzati in \b m_points.
Shinya Kitaoka 120a6e
  crossIcon->fill(TPixel32(0, 0, 0, 0));
Shinya Kitaoka 120a6e
  TPixel32 *c = crossIcon->pixels(3) + 3;
Shinya Kitaoka 120a6e
  for (int i = 1; i <= 3; i++)
Shinya Kitaoka 120a6e
    c[i] = c[-i] = c[7 * i] = c[-7 * i] =
Shinya Kitaoka 120a6e
        (i & 1) == 0 ? TPixel32::White : TPixel32::Red;
Shinya Kitaoka 120a6e
  return crossIcon;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
//! Disegna una freccia lunga \b len pixel.
Shinya Kitaoka 120a6e
/*!La punta della freccia si trova a coordinate (0,ly/2), la coda a
Shinya Kitaoka 120a6e
 * (len-1,ly/2).
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
TRaster32P createArrowShape(int len) {
Shinya Kitaoka 120a6e
  int d            = 5;
Shinya Kitaoka 120a6e
  if (len < d) len = d;
Shinya Kitaoka 120a6e
  TPixel32 c0(210, 210, 210);
Shinya Kitaoka 120a6e
  TPixel32 c1(10, 10, 10);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TRaster32P ras(len, d * 2 + 1);
Shinya Kitaoka 120a6e
  ras->clear();
Shinya Kitaoka 120a6e
  ras->lock();
Shinya Kitaoka 120a6e
  TPixel32 *pix = ras->pixels(d);
Shinya Kitaoka 120a6e
  int x         = 0;
Shinya Kitaoka 120a6e
  for (x = 0; x < len; x++) pix[x] = (x & 8) == 0 ? c0 : c1;
Shinya Kitaoka 120a6e
  for (x = 1; x < d; x++)
Shinya Kitaoka 120a6e
    for (int y = -x; y < x; y++) {
Shinya Kitaoka 120a6e
      assert(ras->getBounds().contains(TPoint(x, y + d)));
Shinya Kitaoka 120a6e
      pix[len * y + x] = c0;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  ras->unlock();
Shinya Kitaoka 120a6e
  return ras;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
// Preso da sceneViewer.cpp quando si spostera' lo SceneViewer in toonzqt
Shinya Kitaoka 120a6e
// mettere
Toshihiro Shimizu 890ddd
// il codice in comune!
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define ZOOMLEVELS 30
Toshihiro Shimizu 890ddd
#define NOZOOMINDEX 20
Shinya Kitaoka 120a6e
double ZoomFactors[ZOOMLEVELS] = {
Shinya Kitaoka 120a6e
    0.001, 0.002, 0.003,  0.004,  0.005, 0.007, 0.01, 0.015, 0.02, 0.03,
Shinya Kitaoka 120a6e
    0.04,  0.05,  0.0625, 0.0833, 0.125, 0.167, 0.25, 0.333, 0.5,  0.667,
Shinya Kitaoka 120a6e
    1,     2,     3,      4,      5,     6,     7,    8,     12,   16};
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
double getQuantizedZoomFactor(double zf, bool forward) {
Shinya Kitaoka 120a6e
  if (forward && zf > ZoomFactors[ZOOMLEVELS - 1] ||
Shinya Kitaoka 120a6e
      areAlmostEqual(zf, ZoomFactors[ZOOMLEVELS - 1], 1e-5))
Shinya Kitaoka 120a6e
    return zf;
Shinya Kitaoka 120a6e
  else if (!forward && zf < ZoomFactors[0] ||
Shinya Kitaoka 120a6e
           areAlmostEqual(zf, ZoomFactors[0], 1e-5))
Shinya Kitaoka 120a6e
    return zf;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert((!forward && zf > ZoomFactors[0]) ||
Shinya Kitaoka 120a6e
         (forward && zf < ZoomFactors[ZOOMLEVELS - 1]));
Shinya Kitaoka 120a6e
  int i = 0;
Shinya Kitaoka 120a6e
  for (i = 0; i <= ZOOMLEVELS - 1; i++)
Shinya Kitaoka 120a6e
    if (areAlmostEqual(zf, ZoomFactors[i], 1e-5)) zf = ZoomFactors[i];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (forward && zf < ZoomFactors[0])
Shinya Kitaoka 120a6e
    return ZoomFactors[0];
Shinya Kitaoka 120a6e
  else if (!forward && zf > ZoomFactors[ZOOMLEVELS - 1])
Shinya Kitaoka 120a6e
    return ZoomFactors[ZOOMLEVELS - 1];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (i = 0; i < ZOOMLEVELS - 1; i++)
Shinya Kitaoka 120a6e
    if (ZoomFactors[i + 1] - zf >= 0 && zf - ZoomFactors[i] >= 0) {
Shinya Kitaoka 120a6e
      if (forward && ZoomFactors[i + 1] == zf)
Shinya Kitaoka 120a6e
        return ZoomFactors[i + 2];
Shinya Kitaoka 120a6e
      else if (!forward && ZoomFactors[i] == zf)
Shinya Kitaoka 120a6e
        return ZoomFactors[i - 1];
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        return forward ? ZoomFactors[i + 1] : ZoomFactors[i];
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  return ZoomFactors[NOZOOMINDEX];
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
bool suspendedRendering = false;  // Global vars for swatch rendering suspension
Toshihiro Shimizu 890ddd
QEventLoop *waitingLoop = 0;
Shinya Kitaoka 120a6e
int submittedTasks      = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
// SwatchViewer
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#if QT_VERSION >= 0x050500
Toshihiro Shimizu 890ddd
SwatchViewer::SwatchViewer(QWidget *parent, Qt::WindowFlags flags)
Toshihiro Shimizu 890ddd
#else
Toshihiro Shimizu 890ddd
SwatchViewer::SwatchViewer(QWidget *parent, Qt::WFlags flags)
Toshihiro Shimizu 890ddd
#endif
Shinya Kitaoka 120a6e
    : QWidget(parent, flags)
Shinya Kitaoka 120a6e
    , m_fx(0)
Shinya Kitaoka 120a6e
    , m_actualFxClone(0)
Shinya Kitaoka 120a6e
    , m_mouseButton(Qt::NoButton)
Shinya Kitaoka 120a6e
    , m_selectedPoint(0)
Shinya Kitaoka 120a6e
    , m_pointPosDelta(TPointD())
Shinya Kitaoka 120a6e
    , m_enabled(false)
Shinya Kitaoka 120a6e
    , m_content()
Shinya Kitaoka 120a6e
    , m_aff(TAffine())
Shinya Kitaoka 120a6e
    , m_fxAff(TAffine())
Shinya Kitaoka 120a6e
    , m_cameraRect()
Shinya Kitaoka 120a6e
    , m_bgPainter(0)
Shinya Kitaoka 120a6e
    , m_pos(TPoint())
Shinya Kitaoka 120a6e
    , m_firstPos(TPoint())
Shinya Kitaoka 120a6e
    , m_oldContent()
Shinya Kitaoka 120a6e
    , m_curContent()
Shinya Kitaoka 120a6e
    , m_executor() {
Shinya Kitaoka 120a6e
  // setMinimumSize(150,150);
Shinya Kitaoka 120a6e
  setMinimumHeight(150);
Shinya Kitaoka 120a6e
  setFixedWidth(150);
Shinya Kitaoka 120a6e
  setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_raster    = TRaster32P(width(), height());
Shinya Kitaoka 120a6e
  m_crossIcon = createCrossIcon();
Shinya Kitaoka 120a6e
  setFocusPolicy(Qt::StrongFocus);
Shinya Kitaoka 120a6e
  m_executor.setDedicatedThreads(true);
Shinya Kitaoka 120a6e
  m_executor.setMaxActiveTasks(1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_renderer.enablePrecomputing(false);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
SwatchViewer::~SwatchViewer() {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! This static method is used to temporarily suspend all swatch-related render
Shinya Kitaoka 120a6e
//! processing, typically because the rendering scene is being deleted.
Shinya Kitaoka 120a6e
//! When a suspension is invoked, all further rendering requests made to
Shinya Kitaoka 120a6e
//! swatch viewers are silently rejected, while currently active or scheduled
Shinya Kitaoka 120a6e
//! ones
Shinya Kitaoka 120a6e
//! are canceled and waited for completion.
Shinya Kitaoka 120a6e
void SwatchViewer::suspendRendering(bool suspend, bool blocking) {
Shinya Kitaoka 120a6e
  suspendedRendering = suspend;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (suspend && submittedTasks > 0 && blocking) {
Shinya Kitaoka 120a6e
    QEventLoop loop;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    waitingLoop = &loop;
Shinya Kitaoka 120a6e
    loop.exec();
Shinya Kitaoka 120a6e
    waitingLoop = 0;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SwatchViewer::setCameraSize(const TDimension &cameraSize) {
Shinya Kitaoka 120a6e
  TRect cameraRect(cameraSize);
Shinya Kitaoka 120a6e
  if (cameraRect != m_cameraRect) {
Shinya Kitaoka 120a6e
    m_cameraRect = cameraRect;
Shinya Kitaoka 120a6e
    updateSize(size());  // Invoke a size update to adapt the widget to the new
Shinya Kitaoka 120a6e
                         // camera ratio
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SwatchViewer::setFx(const TFxP &fx, const TFxP &actualFx, int frame) {
Shinya Kitaoka 120a6e
  m_fx = m_actualFxClone = fx;
Shinya Kitaoka 120a6e
  m_frame                = frame;
Shinya Kitaoka 120a6e
  m_points.clear();
Shinya Kitaoka 120a6e
  m_pointPairs.clear();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!fx) {
Shinya Kitaoka 120a6e
    ::setFxForCaching(0);
Shinya Kitaoka 120a6e
    computeContent();
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // abilita la cache nel nuovo effetto corrente
Shinya Kitaoka 120a6e
  ::setFxForCaching(actualFx.getPointer());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (NaAffineFx *affFx = dynamic_cast<naaffinefx *="">(m_fx.getPointer()))</naaffinefx>
Shinya Kitaoka 120a6e
    m_fxAff = affFx->getPlacement(m_frame);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    m_fxAff = TAffine();
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < actualFx->getParams()->getParamCount(); i++) {
Shinya Kitaoka 120a6e
    TPointParam *pointParam =
Shinya Kitaoka 120a6e
        dynamic_cast<tpointparam *="">(actualFx->getParams()->getParam(i));</tpointparam>
Shinya Kitaoka 120a6e
    if (pointParam) m_points.push_back(Point(i, pointParam));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  // cerco i segmenti
Shinya Kitaoka 120a6e
  int n = m_points.size();
Shinya Kitaoka 120a6e
  for (i = 0; i < n; i++) {
Shinya Kitaoka 120a6e
    std::string name   = m_points[i].m_param->getName();
Shinya Kitaoka 120a6e
    std::string prefix = matchSuffix(name, "_a");
Shinya Kitaoka 120a6e
    if (prefix == "") continue;
Shinya Kitaoka 120a6e
    std::string otherName = prefix + "_b";
Shinya Kitaoka 120a6e
    int j;
Shinya Kitaoka 120a6e
    for (j = 0; j < n; j++)
Shinya Kitaoka 120a6e
      if (i != j && m_points[j].m_param->getName() == otherName) break;
Shinya Kitaoka 120a6e
    if (j < n) {
Shinya Kitaoka 120a6e
      m_pointPairs.push_back(std::make_pair(i, j));
Shinya Kitaoka 120a6e
      m_points[i].m_pairFlag = m_points[j].m_pairFlag = true;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  computeContent();
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SwatchViewer::updateFrame(int frame) {
Shinya Kitaoka 120a6e
  m_frame = frame;
Shinya Kitaoka 120a6e
  computeContent();
Shinya Kitaoka 120a6e
  update();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SwatchViewer::setEnable(bool enabled) {
Shinya Kitaoka 120a6e
  if (m_enabled == enabled) return;
Shinya Kitaoka 120a6e
  m_enabled = enabled;
Shinya Kitaoka 120a6e
  if (m_enabled)
Shinya Kitaoka 120a6e
    computeContent();
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    update();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SwatchViewer::updateSize(const QSize &size) {
Shinya Kitaoka 120a6e
  int h        = size.height();
Shinya Kitaoka 120a6e
  double ratio = m_cameraRect.getLy() > 0
Shinya Kitaoka 120a6e
                     ? m_cameraRect.getLx() / (double)m_cameraRect.getLy()
Shinya Kitaoka 120a6e
                     : 1.0;
Shinya Kitaoka 120a6e
  int w = std::min((int)(h * ratio), parentWidget()->width());
Shinya Kitaoka 120a6e
  setFixedWidth(w);
Shinya Kitaoka 120a6e
  if (w > 2 && h > 2)
Shinya Kitaoka 120a6e
    m_raster = TRaster32P(TDimension(w, h));
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    m_raster = TRaster32P();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SwatchViewer::setBgPainter(TPixel32 color1, TPixel32 color2) {
Shinya Kitaoka 120a6e
  if (color2 == TPixel32())
Shinya Kitaoka 120a6e
    m_bgPainter = new SolidColorBgPainter("", color1);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    m_bgPainter = new CheckboardBgPainter("", color1, color2);
Shinya Kitaoka 120a6e
  updateRaster();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TPoint SwatchViewer::world2win(const TPointD &p) const {
Shinya Kitaoka 120a6e
  TPointD center(width() * 0.5, height() * 0.5);
Shinya Kitaoka 120a6e
  return convert(m_aff * m_fxAff * p + center);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TPointD SwatchViewer::win2world(const TPoint &p) const {
Shinya Kitaoka 120a6e
  TPointD center(width() * 0.5, height() * 0.5);
Shinya Kitaoka 120a6e
  TPointD point = TPointD(convert(p) - center);
Shinya Kitaoka 120a6e
  return m_fxAff.inv() * m_aff.inv() * TPointD(point.x, -point.y);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SwatchViewer::zoom(const TPoint &pos, double factor) {
Shinya Kitaoka 120a6e
  if (!m_content || factor == 1.0) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TPointD delta = convert(pos);
Shinya Kitaoka 120a6e
  double scale  = m_aff.det();
Shinya Kitaoka 120a6e
  TAffine aff;
Shinya Kitaoka 120a6e
  if ((scale < 2000 || factor < 1) && (scale > 0.004 || factor > 1)) {
Shinya Kitaoka 120a6e
    aff = TTranslation(delta) * TScale(factor) * TTranslation(-delta);
Shinya Kitaoka 120a6e
    setAff(aff * m_aff);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SwatchViewer::zoom(bool forward, bool reset) {
Shinya Kitaoka 120a6e
  double scale2 = m_aff.det();
Shinya Kitaoka 120a6e
  if (reset || ((scale2 < 2000 || !forward) && (scale2 > 0.004 || forward))) {
Shinya Kitaoka 120a6e
    double oldZoomScale = sqrt(scale2);
Shinya Kitaoka 120a6e
    double zoomScale =
Shinya Kitaoka 120a6e
        reset ? 1 : getQuantizedZoomFactor(oldZoomScale, forward);
Shinya Kitaoka 120a6e
    TAffine aff = TScale(zoomScale / oldZoomScale);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    setAff(aff * m_aff);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SwatchViewer::computeContent() {
Shinya Kitaoka 120a6e
  if (suspendedRendering) return;
Shinya Kitaoka 120a6e
  if (!m_enabled) return;
Shinya Kitaoka 120a6e
  if (!m_raster) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Clear the swatch cache when the zoom scale has changed (cache results are
Shinya Kitaoka 120a6e
  // not compatible
Shinya Kitaoka 120a6e
  // between different scale levels)
Shinya Kitaoka 120a6e
  if (m_aff.a11 != m_contentAff.a11)
Shinya Kitaoka 120a6e
    SwatchCacheManager::instance()->clearSwatchResults();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRect rect(0, 0, width() - 1, height() - 1);
Shinya Kitaoka 120a6e
  TDimension size = rect.getSize();
Shinya Kitaoka 120a6e
  assert(m_raster->getSize() == size);
Shinya Kitaoka 120a6e
  if (m_fx) {
Shinya Kitaoka 120a6e
    // TFxP fx = makeAffine(m_fx, m_aff);
Shinya Kitaoka 120a6e
    // TRasterFxP rasterFx = fx;
Shinya Kitaoka 120a6e
    TRasterFxP rasterFx = m_fx;
Shinya Kitaoka 120a6e
    if (rasterFx) {
Shinya Kitaoka 120a6e
      m_executor.cancelAll();
Shinya Kitaoka 120a6e
      m_executor.addTask(
Shinya Kitaoka 120a6e
          new ContentRender(rasterFx.getPointer(), m_frame, size, this));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      submittedTasks++;
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      m_content = TRaster32P(size);
Shinya Kitaoka 120a6e
      m_content->fill(TPixel32::Red);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    m_content = TRaster32P(size);
Shinya Kitaoka 120a6e
    m_content->fill(TPixel32::Transparent);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  updateRaster();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SwatchViewer::updateRaster() {
Shinya Kitaoka 120a6e
  QMutexLocker sl(&m_mutex);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!m_enabled) return;
Shinya Kitaoka 120a6e
  if (!m_raster) return;
Shinya Kitaoka 120a6e
  if (m_bgPainter)
Shinya Kitaoka 120a6e
    m_bgPainter->paint(m_raster);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    m_raster->fill(TPixel32(127, 127, 127));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_cameraMode && !m_cameraRect.isEmpty()) {
Shinya Kitaoka 120a6e
    TPointD p0(m_cameraRect.x0, m_cameraRect.y0);
Shinya Kitaoka 120a6e
    TPointD p1(m_cameraRect.x1, m_cameraRect.y1);
Shinya Kitaoka 120a6e
    TPointD center(width() * 0.5, height() * 0.5);
Shinya Kitaoka 120a6e
    TPoint transP0 = convert(m_aff * p0 + center);
Shinya Kitaoka 120a6e
    TPoint transP1 = convert(m_aff * p1 + center);
Shinya Kitaoka 120a6e
    TPoint p       = convert(
Shinya Kitaoka 120a6e
        (TPointD(transP1.x, transP1.y) - TPointD(transP0.x, transP0.y)) * 0.5);
Shinya Kitaoka 120a6e
    TRect rect(transP0 - p, transP1 - p);
Shinya Kitaoka 120a6e
    m_content->fillOutside(rect, TPixel32(255, 0, 0, 255));
Shinya Kitaoka 120a6e
    m_content->fillOutside(rect.enlarge(TDimension(1, 1)),
Shinya Kitaoka 120a6e
                           TPixel32(0, 0, 0, 0));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_content) TRop::over(m_raster, m_content);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < (int)m_points.size(); i++) {
Shinya Kitaoka 120a6e
    if (m_points[i].m_pairFlag) continue;
Shinya Kitaoka 120a6e
    TPoint p = world2win(m_points[i].m_param->getValue(m_frame));
Shinya Kitaoka 120a6e
    TRop::over(m_raster, m_crossIcon, p - TPoint(4, 4));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  for (i = 0; i < (int)m_pointPairs.size(); i++) {
Shinya Kitaoka 120a6e
    int i0 = m_pointPairs[i].first;
Shinya Kitaoka 120a6e
    int i1 = m_pointPairs[i].second;
Shinya Kitaoka 120a6e
    assert(i0 != i1);
Shinya Kitaoka 120a6e
    assert(0 <= i0 && i0 < (int)m_points.size());
Shinya Kitaoka 120a6e
    assert(0 <= i1 && i1 < (int)m_points.size());
Shinya Kitaoka 120a6e
    TPoint p0        = world2win(m_points[i0].m_param->getValue(m_frame));
Shinya Kitaoka 120a6e
    TPoint p1        = world2win(m_points[i1].m_param->getValue(m_frame));
Shinya Kitaoka 120a6e
    TPoint delta     = p1 - p0;
Shinya Kitaoka 120a6e
    int len          = tround(sqrt((double)(delta * delta)));
Shinya Kitaoka 120a6e
    double phi       = 0;
Shinya Kitaoka 120a6e
    if (len > 0) phi = atan2((double)delta.y, (double)delta.x) * M_180_PI;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (len > 500) {
Shinya Kitaoka 120a6e
      // puo' succedere per zoom molto grandi.
Shinya Kitaoka 120a6e
      // dovrei fare qualcosa, ma non so bene che cosa e non credo sia
Shinya Kitaoka 120a6e
      // importantissimo
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      TRaster32P arrowShape = createArrowShape(len);
Shinya Kitaoka 120a6e
      TAffine aff =
Shinya Kitaoka 120a6e
          TRotation(phi).place(0, arrowShape->getLy() / 2, p0.x, p0.y);
Shinya Kitaoka 120a6e
      TRop::over(m_raster, arrowShape, aff);
Shinya Kitaoka 120a6e
      // verrebbe la tentazione di usare il filtro TRop::Bilinear (piu'veloce),
Shinya Kitaoka 120a6e
      // ma la qualita' ne risente molto
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  update();
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void SwatchViewer::setContent(const TRaster32P &content,
Shinya Kitaoka 120a6e
                              const TAffine &contentAff) {
Shinya Kitaoka 120a6e
  m_content    = content;
Shinya Kitaoka 120a6e
  m_contentAff = contentAff;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  updateRaster();
Shinya Kitaoka 120a6e
  update();
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void SwatchViewer::setAff(const TAffine &aff) {
Shinya Kitaoka 120a6e
  m_aff = aff;
Shinya Kitaoka 120a6e
  computeContent();
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void SwatchViewer::paintEvent(QPaintEvent *event) {
Shinya Kitaoka 120a6e
  QPainter p(this);
Shinya Kitaoka 120a6e
  QRect rectBox = rect();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!m_enabled)
Shinya Kitaoka 120a6e
    p.fillRect(rectBox, QBrush(QColor(120, 120, 120)));
Shinya Kitaoka 120a6e
  else {
Shinya Kitaoka 120a6e
    if (!m_raster) return;
Shinya Kitaoka 120a6e
    QImage image = rasterToQImage(m_raster);
Shinya Kitaoka 120a6e
    p.drawImage(rectBox, image);
Shinya Kitaoka 120a6e
    if (m_computing) {
Shinya Kitaoka 120a6e
      QPen pen;
Shinya Kitaoka 120a6e
      pen.setColor(Qt::red);
Shinya Kitaoka 120a6e
      pen.setWidth(3);
Shinya Kitaoka 120a6e
      p.setPen(pen);
Shinya Kitaoka 120a6e
      p.drawRect(rectBox.adjusted(0, 0, -1, -1));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void SwatchViewer::resizeEvent(QResizeEvent *re) {
Shinya Kitaoka 120a6e
  int oldHeight = re->oldSize().height();
Shinya Kitaoka 120a6e
  int newHeight = re->size().height();
Shinya Kitaoka 120a6e
  if (oldHeight != newHeight) {
Shinya Kitaoka 120a6e
    updateSize(QSize(newHeight, newHeight));
Shinya Kitaoka 120a6e
    computeContent();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void SwatchViewer::mousePressEvent(QMouseEvent *event) {
Shinya Kitaoka 120a6e
  TPoint pos    = TPoint(event->pos().x(), event->pos().y());
Shinya Kitaoka 120a6e
  m_mouseButton = event->button();
Shinya Kitaoka 120a6e
  if (m_mouseButton == Qt::LeftButton) {
Shinya Kitaoka 120a6e
    m_selectedPoint = -1;
Shinya Kitaoka 120a6e
    if (m_points.empty()) return;
Shinya Kitaoka 120a6e
    TPointD p = win2world(pos);
Shinya Kitaoka 120a6e
    TPointD q;
Shinya Kitaoka 120a6e
    double minDist2 = 1e6;
Shinya Kitaoka 120a6e
    int i;
Shinya Kitaoka 120a6e
    for (i = 0; i < (int)m_points.size(); i++) {
Shinya Kitaoka 120a6e
      TPointD paramPoint = m_points[i].m_param->getValue(m_frame);
Shinya Kitaoka 120a6e
      double d2          = tdistance2(p, paramPoint);
Shinya Kitaoka 120a6e
      if (m_selectedPoint < 0 || d2 < minDist2) {
Shinya Kitaoka 120a6e
        m_selectedPoint = i;
Shinya Kitaoka 120a6e
        minDist2        = d2;
Shinya Kitaoka 120a6e
        q               = paramPoint;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (m_selectedPoint >= 0) {
Shinya Kitaoka 120a6e
      m_pointPosDelta = q - p;
Shinya Kitaoka 120a6e
      TPoint d        = world2win(p) - world2win(q);
Shinya Kitaoka 120a6e
      int dd2         = d.x * d.x + d.y * d.y;
Shinya Kitaoka 120a6e
      if (dd2 > 400)
Shinya Kitaoka 120a6e
        m_selectedPoint = -1;
Shinya Kitaoka 120a6e
      else {
Shinya Kitaoka 120a6e
        std::string name   = m_points[m_selectedPoint].m_param->getName();
Shinya Kitaoka 120a6e
        std::string prefix = matchSuffix(name, "_b");
Shinya Kitaoka 120a6e
        if (prefix != "") {
Shinya Kitaoka 120a6e
          std::string otherName = prefix + "_a";
Shinya Kitaoka 120a6e
          int n                 = (int)m_points.size();
Shinya Kitaoka 120a6e
          int j;
Shinya Kitaoka 120a6e
          for (j = 0; j < n; j++)
Shinya Kitaoka 120a6e
            if (i != j && m_points[j].m_param->getName() == otherName) break;
Shinya Kitaoka 120a6e
          if (j < n) {
Shinya Kitaoka 120a6e
            TPoint dist = world2win(m_points[m_selectedPoint].m_param->getValue(
Shinya Kitaoka 120a6e
                              m_frame)) -
Shinya Kitaoka 120a6e
                          world2win(m_points[j].m_param->getValue(m_frame));
Shinya Kitaoka 120a6e
            int ddist2 = dist.x * dist.x + dist.y * dist.y;
Shinya Kitaoka 120a6e
            if (ddist2 < 100) m_selectedPoint = j;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    update();
Shinya Kitaoka 120a6e
  } else if (m_mouseButton == Qt::MidButton) {
Shinya Kitaoka 120a6e
    m_pos        = pos;
Shinya Kitaoka 120a6e
    m_firstPos   = pos;
Shinya Kitaoka 120a6e
    m_oldContent = getContent();
Shinya Kitaoka 120a6e
    if (m_oldContent)
Shinya Kitaoka 120a6e
      m_curContent = TRaster32P(m_oldContent->getSize());
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      m_curContent = TRaster32P();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void SwatchViewer::mouseMoveEvent(QMouseEvent *event) {
Shinya Kitaoka 120a6e
  TPoint pos = TPoint(event->pos().x(), event->pos().y());
Shinya Kitaoka 120a6e
  if (m_mouseButton == Qt::LeftButton) {
Shinya Kitaoka 120a6e
    if (m_selectedPoint < 0 || m_selectedPoint >= (int)m_points.size()) return;
Shinya Kitaoka 120a6e
    TPointD p = win2world(pos) + m_pointPosDelta;
Shinya Kitaoka 120a6e
    int index = m_points[m_selectedPoint].m_index;
Shinya Kitaoka 120a6e
    emit pointPositionChanged(index, p);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // It seems that mouse move events may jeopardize our rendering notification
Shinya Kitaoka 120a6e
    // deliveries
Shinya Kitaoka 120a6e
    // - probably because Qt considers them 'higher priority stuff' with respect
Shinya Kitaoka 120a6e
    // to common queued signal-slot connections.
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // In order to allow processing of the ContentRender::started() and
Shinya Kitaoka 120a6e
    // ContentRender::finished()
Shinya Kitaoka 120a6e
    // signals, we need to process events. We will exclude user input events (ie
Shinya Kitaoka 120a6e
    // other mouse events)
Shinya Kitaoka 120a6e
    // to avoid unnecessary recursions.
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
Shinya Kitaoka 120a6e
  } else if (m_mouseButton == Qt::MidButton) {
Shinya Kitaoka 120a6e
    if (!m_oldContent || !m_curContent) return;
Shinya Kitaoka 120a6e
    m_curContent->fill(TPixel32::Transparent);
Shinya Kitaoka 120a6e
    TPointD step = convert(pos - m_pos);
Shinya Kitaoka 120a6e
    // Devo aggiornare l'affine per riposizionare la camera.
Shinya Kitaoka 120a6e
    m_aff    = TTranslation(step.x, -step.y) * m_aff;
Shinya Kitaoka 120a6e
    m_pos    = pos;
Shinya Kitaoka 120a6e
    TPoint p = pos - m_firstPos;
Shinya Kitaoka 120a6e
    m_curContent->copy(m_oldContent, TPoint(p.x, -p.y));
Shinya Kitaoka 120a6e
    setContent(m_curContent, TTranslation(step.x, -step.y) * m_contentAff);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void SwatchViewer::mouseReleaseEvent(QMouseEvent *event) {
Shinya Kitaoka 120a6e
  m_mouseButton   = Qt::NoButton;
Shinya Kitaoka 120a6e
  m_selectedPoint = -1;
Shinya Kitaoka 120a6e
  TPoint pos      = TPoint(event->pos().x(), event->pos().y());
Shinya Kitaoka 120a6e
  if (event->button() == Qt::MidButton) {
Shinya Kitaoka 120a6e
    if (!m_oldContent || !m_curContent) return;
Shinya Kitaoka 120a6e
    TPointD p = convert(pos - m_pos);
Shinya Kitaoka 120a6e
    setAff(TTranslation(p.x, -p.y) * m_aff);
Shinya Kitaoka 120a6e
    update();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void SwatchViewer::wheelEvent(QWheelEvent *event) {
Shinya Kitaoka 120a6e
  TPoint center(event->pos().x() - width() / 2,
Shinya Kitaoka 120a6e
                -event->pos().y() + height() / 2);
Shinya Kitaoka 120a6e
  zoom(center, exp(0.001 * event->delta()));
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void SwatchViewer::keyPressEvent(QKeyEvent *event) {
Shinya Kitaoka 120a6e
  int key = event->key();
Shinya Kitaoka 120a6e
  if (key == '+' || key == '-' || key == '0') {
Shinya Kitaoka 120a6e
    zoom(key == '+', key == '0');
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void SwatchViewer::hideEvent(QHideEvent *event) {
Shinya Kitaoka 120a6e
  // Clear the swatch cache
Shinya Kitaoka 120a6e
  ::setFxForCaching(0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
// SwatchViewer::ContentRender
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
SwatchViewer::ContentRender::ContentRender(TRasterFx *fx, int frame,
Shinya Kitaoka 120a6e
                                           const TDimension &size,
Shinya Kitaoka 120a6e
                                           SwatchViewer *viewer)
Shinya Kitaoka 120a6e
    : m_fx(fx)
Shinya Kitaoka 120a6e
    , m_raster(0)
Shinya Kitaoka 120a6e
    , m_frame(frame)
Shinya Kitaoka 120a6e
    , m_size(size)
Shinya Kitaoka 120a6e
    , m_aff(viewer->m_aff)
Shinya Kitaoka 120a6e
    , m_viewer(viewer)
Shinya Kitaoka 120a6e
    , m_started(false) {
Shinya Kitaoka 120a6e
  // Is there a less complicated way...?
Shinya Kitaoka 120a6e
  connect(this, SIGNAL(started(TThread::RunnableP)), this,
Shinya Kitaoka 120a6e
          SLOT(onStarted(TThread::RunnableP)));
Shinya Kitaoka 120a6e
  connect(this, SIGNAL(finished(TThread::RunnableP)), this,
Shinya Kitaoka 120a6e
          SLOT(onFinished(TThread::RunnableP)));
Shinya Kitaoka 120a6e
  connect(this, SIGNAL(exception(TThread::RunnableP)), this,
Shinya Kitaoka 120a6e
          SLOT(onFinished(TThread::RunnableP)));
Shinya Kitaoka 120a6e
  connect(this, SIGNAL(canceled(TThread::RunnableP)), this,
Shinya Kitaoka 120a6e
          SLOT(onCanceled(TThread::RunnableP)),
Shinya Kitaoka 120a6e
          Qt::QueuedConnection);  // Starts will need to come *strictly before*
Shinya Kitaoka 120a6e
                                  // cancels
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
SwatchViewer::ContentRender::~ContentRender() {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SwatchViewer::ContentRender::run() {
Shinya Kitaoka 120a6e
  if (suspendedRendering) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  unsigned long renderId = TRenderer::buildRenderId();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TPassiveCacheManager::instance()->setContextName(renderId, "S");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_viewer->m_renderer.install(renderId);
Shinya Kitaoka 120a6e
  m_viewer->m_renderer.declareRenderStart(renderId);
Shinya Kitaoka 120a6e
  m_viewer->m_renderer.declareFrameStart(m_frame);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRenderSettings info;
Shinya Kitaoka 120a6e
  info.m_isSwatch = true;
Shinya Kitaoka 120a6e
  info.m_affine   = m_aff;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TTile tile;
Shinya Kitaoka 120a6e
  m_fx->allocateAndCompute(tile, -0.5 * TPointD(m_size.lx, m_size.ly), m_size,
Shinya Kitaoka 120a6e
                           0, (double)m_frame, info);
Shinya Kitaoka 120a6e
  m_raster = tile.getRaster();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_viewer->m_renderer.declareFrameEnd(m_frame);
Shinya Kitaoka 120a6e
  m_viewer->m_renderer.declareRenderEnd(renderId);
Shinya Kitaoka 120a6e
  m_viewer->m_renderer.uninstall();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int SwatchViewer::ContentRender::taskLoad() { return 100; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SwatchViewer::ContentRender::onStarted(TThread::RunnableP task) {
Shinya Kitaoka 120a6e
  m_started             = true;
Shinya Kitaoka 120a6e
  m_viewer->m_computing = true;
Shinya Kitaoka 120a6e
  m_viewer->update();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SwatchViewer::ContentRender::onFinished(TThread::RunnableP task) {
Shinya Kitaoka 120a6e
  m_viewer->m_computing = false;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_viewer->setContent(m_raster, m_aff);
Shinya Kitaoka 120a6e
  if ((--submittedTasks == 0) && waitingLoop) waitingLoop->quit();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SwatchViewer::ContentRender::onCanceled(TThread::RunnableP task) {
Shinya Kitaoka 120a6e
  if (m_started) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if ((--submittedTasks == 0) && waitingLoop) waitingLoop->quit();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//*************************************************************************************
Toshihiro Shimizu 890ddd
//    Swatch cache manager implementation
Toshihiro Shimizu 890ddd
//*************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
SwatchCacheManager *SwatchCacheManager::instance() {
Shinya Kitaoka 120a6e
  static SwatchCacheManager theInstance;
Shinya Kitaoka 120a6e
  return &theInstance;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SwatchCacheManager::setFx(const TFxP &fx) {
Shinya Kitaoka 120a6e
  QMutexLocker locker(&m_mutex);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Update the fxs id data
Shinya Kitaoka 120a6e
  if (fx == TFxP()) {
Shinya Kitaoka 120a6e
    // Clear if no fx is set
Shinya Kitaoka 120a6e
    m_setFxId = 0;
Shinya Kitaoka 120a6e
    m_childrenFxIds.clear();
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    m_setFxId = fx->getIdentifier();
Shinya Kitaoka 120a6e
    m_childrenFxIds.clear();
Shinya Kitaoka 120a6e
    assert(m_setFxId != 0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    TRasterFx *rfx = dynamic_cast<trasterfx *="">(fx.getPointer());</trasterfx>
Shinya Kitaoka 120a6e
    assert(rfx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    for (int i = 0; i < fx->getInputPortCount(); ++i) {
Shinya Kitaoka 120a6e
      // Fxs not allowing cache on the input port are skipped
Shinya Kitaoka 120a6e
      if (!rfx->allowUserCacheOnPort(i)) continue;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      TFxPort *iport = fx->getInputPort(i);
Shinya Kitaoka 120a6e
      if (iport && iport->isConnected()) {
Shinya Kitaoka 120a6e
        TFx *child = iport->getFx();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
        // In the zerary case, extract the actual fx
Shinya Kitaoka 120a6e
        TZeraryColumnFx *zcfx = dynamic_cast<tzerarycolumnfx *="">(child);</tzerarycolumnfx>
Shinya Kitaoka 120a6e
        if (zcfx) child       = zcfx->getZeraryFx();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
        assert(child && child->getIdentifier() != 0);
Shinya Kitaoka 120a6e
        m_childrenFxIds.insert(child->getIdentifier());
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // NOTE: Check if this should be avoided in some case...
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Release the locks and clear the resources
Shinya Kitaoka 120a6e
  if (m_currEditedFxResult) m_currEditedFxResult->releaseLock();
Shinya Kitaoka 120a6e
  m_currEditedFxResult = TCacheResourceP();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::set<tcacheresourcep>::iterator it;</tcacheresourcep>
Shinya Kitaoka 120a6e
  for (it = m_swatchCacheContainer.begin(); it != m_swatchCacheContainer.end();
Shinya Kitaoka 120a6e
       ++it)
Shinya Kitaoka 120a6e
    (*it)->releaseLock();
Shinya Kitaoka 120a6e
  m_swatchCacheContainer.clear();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef USE_SQLITE_HDPOOL
Shinya Kitaoka 120a6e
  TCacheResourcePool::instance()->releaseReferences("S");
Toshihiro Shimizu 890ddd
#else
Shinya Kitaoka 120a6e
  for (it = m_genericCacheContainer.begin();
Shinya Kitaoka 120a6e
       it != m_genericCacheContainer.end(); ++it)
Shinya Kitaoka 120a6e
    (*it)->releaseLock();
Shinya Kitaoka 120a6e
  m_genericCacheContainer.clear();
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// This method is invoked by the swatch when its scene scale changes. Find it
Shinya Kitaoka 120a6e
// above.
Shinya Kitaoka 120a6e
void SwatchCacheManager::clearSwatchResults() {
Shinya Kitaoka 120a6e
  QMutexLocker locker(&m_mutex);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_currEditedFxResult) m_currEditedFxResult->releaseLock();
Shinya Kitaoka 120a6e
  m_currEditedFxResult = TCacheResourceP();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::set<tcacheresourcep>::iterator it;</tcacheresourcep>
Shinya Kitaoka 120a6e
  for (it = m_swatchCacheContainer.begin(); it != m_swatchCacheContainer.end();
Shinya Kitaoka 120a6e
       ++it)
Shinya Kitaoka 120a6e
    (*it)->releaseLock();
Shinya Kitaoka 120a6e
  m_swatchCacheContainer.clear();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void SwatchCacheManager::getResource(TCacheResourceP &resource,
Shinya Kitaoka 120a6e
                                     const std::string &alias, const TFxP &fx,
Shinya Kitaoka 120a6e
                                     double frame, const TRenderSettings &rs,
Shinya Kitaoka 120a6e
                                     ResourceDeclaration *resData) {
Shinya Kitaoka 120a6e
  // Only FX RESULTS are interesting - plus, avoid if we're not currently
Shinya Kitaoka 120a6e
  // editing an fx.
Shinya Kitaoka 120a6e
  if (!(fx && m_setFxId > 0)) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  QMutexLocker locker(&m_mutex);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Cache the result in case the fx's id is among the stored ones.
Shinya Kitaoka 120a6e
  unsigned long fxId = fx->getIdentifier();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (fxId == m_setFxId && rs.m_isSwatch) {
Shinya Kitaoka 120a6e
    if (!resource) resource = TCacheResourceP(alias, true);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    resource->addLock();
Shinya Kitaoka 120a6e
    if (m_currEditedFxResult) m_currEditedFxResult->releaseLock();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    m_currEditedFxResult = resource;
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_childrenFxIds.find(fxId) != m_childrenFxIds.end()) {
Shinya Kitaoka 120a6e
    if (!resource) resource = TCacheResourceP(alias, true);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (rs.m_isSwatch) {
Shinya Kitaoka 120a6e
      std::set<tcacheresourcep>::iterator it =</tcacheresourcep>
Shinya Kitaoka 120a6e
          m_swatchCacheContainer.find(resource);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      if (it == m_swatchCacheContainer.end()) {
Shinya Kitaoka 120a6e
        resource->addLock();
Shinya Kitaoka 120a6e
        m_swatchCacheContainer.insert(resource);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    } else {
Toshihiro Shimizu 890ddd
#ifdef USE_SQLITE_HDPOOL
Shinya Kitaoka 120a6e
      resource->enableBackup();
Shinya Kitaoka 120a6e
      TCacheResourcePool::instance()->addReference(resource, "S");
Toshihiro Shimizu 890ddd
#else
Shinya Kitaoka 120a6e
      std::set<tcacheresourcep>::iterator it =</tcacheresourcep>
Shinya Kitaoka 120a6e
          m_genericCacheContainer.find(resource);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      if (it == m_genericCacheContainer.end()) {
Shinya Kitaoka 120a6e
        resource->addLock();
Shinya Kitaoka 120a6e
        m_genericCacheContainer.insert(resource);
Shinya Kitaoka 120a6e
      }
Toshihiro Shimizu 890ddd
#endif
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}