Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonz/plasticdeformerfx.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzLib includes
Toshihiro Shimizu 890ddd
#include "toonz/txsheet.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshleveltypes.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshcell.h"
Toshihiro Shimizu 890ddd
#include "toonz/tcolumnfx.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshlevelcolumn.h"
Toshihiro Shimizu 890ddd
#include "toonz/dpiscale.h"
Toshihiro Shimizu 890ddd
#include "toonz/stage.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzExt includes
Toshihiro Shimizu 890ddd
#include "ext/plasticskeleton.h"
Toshihiro Shimizu 890ddd
#include "ext/plasticdeformerstorage.h"
Toshihiro Shimizu 890ddd
#include "ext/ttexturesstorage.h"
Toshihiro Shimizu 890ddd
#include "ext/plasticvisualsettings.h"
Toshihiro Shimizu 890ddd
#include "ext/meshutils.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzBase includes
Toshihiro Shimizu 890ddd
#include "trenderer.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzCore includes
Toshihiro Shimizu 890ddd
#include "tgl.h"
Toshihiro Shimizu 890ddd
#include "tofflinegl.h"
Toshihiro Shimizu 890ddd
#include "tgldisplaylistsmanager.h"
Toshihiro Shimizu 890ddd
#include "tconvert.h"
Toshihiro Shimizu 890ddd
#include "trop.h"
Toshihiro Shimizu 890ddd
d5d1ac
#include <qopenglframebufferobject></qopenglframebufferobject>
shun_iwasawa 7e52a2
#include <qoffscreensurface></qoffscreensurface>
shun_iwasawa 7e52a2
#include <qsurfaceformat></qsurfaceformat>
shun_iwasawa 7e52a2
#include <qopenglcontext></qopenglcontext>
shun_iwasawa 7e52a2
#include <qimage></qimage>
shun_iwasawa 7e52a2
Toshihiro Shimizu 890ddd
FX_IDENTIFIER_IS_HIDDEN(PlasticDeformerFx, "plasticDeformerFx")
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//***************************************************************************************************
Toshihiro Shimizu 890ddd
//    Local namespace
Toshihiro Shimizu 890ddd
//***************************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
std::string toString(const TAffine &aff) {
Shinya Kitaoka 120a6e
  return
Shinya Kitaoka 120a6e
      // Observe that toString distinguishes + and - 0. That is a problem
Shinya Kitaoka 120a6e
      // when comparing aliases - so near 0 values are explicitly rounded to 0.
Shinya Kitaoka 120a6e
      (areAlmostEqual(aff.a11, 0.0) ? "0" : ::to_string(aff.a11, 5)) + "," +
Shinya Kitaoka 120a6e
      (areAlmostEqual(aff.a12, 0.0) ? "0" : ::to_string(aff.a12, 5)) + "," +
Shinya Kitaoka 120a6e
      (areAlmostEqual(aff.a13, 0.0) ? "0" : ::to_string(aff.a13, 5)) + "," +
Shinya Kitaoka 120a6e
      (areAlmostEqual(aff.a21, 0.0) ? "0" : ::to_string(aff.a21, 5)) + "," +
Shinya Kitaoka 120a6e
      (areAlmostEqual(aff.a22, 0.0) ? "0" : ::to_string(aff.a22, 5)) + "," +
Shinya Kitaoka 120a6e
      (areAlmostEqual(aff.a23, 0.0) ? "0" : ::to_string(aff.a23, 5));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
std::string toString(SkVD *vd, double sdFrame) {
Shinya Kitaoka 120a6e
  std::string result;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (int p = 0; p < SkVD::PARAMS_COUNT; ++p)
Shinya Kitaoka 120a6e
    result += ::to_string(vd->m_params[p]->getValue(sdFrame), 5) + " ";
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return result;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
std::string toString(const PlasticSkeleton::vertex_type &vx) {
Shinya Kitaoka 120a6e
  // TODO: Add z and rigidity
Shinya Kitaoka 120a6e
  return ::to_string(vx.P().x, 5) + " " + ::to_string(vx.P().y, 5);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
std::string toString(const PlasticSkeletonDeformationP &sd, double sdFrame) {
Shinya Kitaoka 120a6e
  std::string result;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const PlasticSkeletonP &skeleton = sd->skeleton(sdFrame);
Shinya Kitaoka 120a6e
  if (!skeleton || skeleton->empty()) return result;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const tcg::list<plasticskeleton::vertex_type> &vertices =</plasticskeleton::vertex_type>
Shinya Kitaoka 120a6e
      skeleton->vertices();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  tcg::list<plasticskeleton::vertex_type>::const_iterator vt,</plasticskeleton::vertex_type>
Shinya Kitaoka 120a6e
      vEnd(vertices.end());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  result = toString(*vertices.begin());
Shinya Kitaoka 120a6e
  for (vt = vertices.begin(); vt != vEnd; ++vt) {
Shinya Kitaoka 120a6e
    result += "; " + toString(*vt);
Shinya Kitaoka 120a6e
    result += " " + toString(sd->vertexDeformation(vt->name()), sdFrame);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return result;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//***************************************************************************************************
Toshihiro Shimizu 890ddd
//    PlasticDeformerFx  implementation
Toshihiro Shimizu 890ddd
//***************************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
PlasticDeformerFx::PlasticDeformerFx() : TRasterFx() {
Shinya Kitaoka 120a6e
  addInputPort("source", m_port);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TFx *PlasticDeformerFx::clone(bool recursive) const {
Shinya Kitaoka 120a6e
  PlasticDeformerFx *fx =
Shinya Kitaoka 120a6e
      dynamic_cast<plasticdeformerfx *="">(TFx::clone(recursive));</plasticdeformerfx>
Shinya Kitaoka 120a6e
  assert(fx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  fx->m_xsh = m_xsh;
Shinya Kitaoka 120a6e
  fx->m_col = m_col;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return fx;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool PlasticDeformerFx::canHandle(const TRenderSettings &info, double frame) {
Shinya Kitaoka 120a6e
  // Yep. Affines are handled. Well - it's easy, since OpenGL lets you do that
Shinya Kitaoka 120a6e
  // directly
Shinya Kitaoka 120a6e
  // with a glPushMatrix...
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
std::string PlasticDeformerFx::getAlias(double frame,
Shinya Kitaoka 120a6e
                                        const TRenderSettings &info) const {
Shinya Kitaoka 120a6e
  std::string alias(getFxType());
Shinya Kitaoka 120a6e
  alias += "[";
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_port.isConnected()) {
Shinya Kitaoka 120a6e
    TRasterFxP ifx = m_port.getFx();
Shinya Kitaoka 120a6e
    assert(ifx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    alias += ifx->getAlias(frame, info);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TStageObject *meshColumnObj =
Shinya Kitaoka 120a6e
      m_xsh->getStageObject(TStageObjectId::ColumnId(m_col));
Shinya Kitaoka 120a6e
  const PlasticSkeletonDeformationP &sd =
Shinya Kitaoka 120a6e
      meshColumnObj->getPlasticSkeletonDeformation();
Shinya Kitaoka 120a6e
  if (sd) alias += ", " + toString(sd, meshColumnObj->paramsTime(frame));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  alias + "]";
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return alias;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool PlasticDeformerFx::doGetBBox(double frame, TRectD &bbox,
Shinya Kitaoka 120a6e
                                  const TRenderSettings &info) {
Shinya Kitaoka 120a6e
  if (!m_port.isConnected()) return false;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // It's hard work to calculate the bounding box of a plastic deformation.
Shinya Kitaoka 120a6e
  // Decline.
Shinya Kitaoka 120a6e
  bbox = TConsts::infiniteRectD;
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlasticDeformerFx::buildRenderSettings(double frame,
Shinya Kitaoka 120a6e
                                            TRenderSettings &info) {
Shinya Kitaoka 120a6e
  // As previously pointed out, this fx is able to handle affines. We can,
Shinya Kitaoka 120a6e
  // actually, *decide*
Shinya Kitaoka 120a6e
  // the input reference to work with.
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // So, the best choice is to let the *input fx* decide the appropriate
Shinya Kitaoka 120a6e
  // reference, by invoking
Shinya Kitaoka 120a6e
  // its handledAffine() method.
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  info.m_bpp    = 32;  // We need to fix the input to 32-bpp
Shinya Kitaoka 120a6e
  info.m_affine = m_port->handledAffine(info, frame);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool PlasticDeformerFx::buildTextureDataSl(double frame, TRenderSettings &info,
Shinya Kitaoka 120a6e
                                           TAffine &worldLevelToLevelAff) {
Shinya Kitaoka 120a6e
  int row = (int)frame;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Initialize level vars
Shinya Kitaoka 120a6e
  TLevelColumnFx *lcfx       = (TLevelColumnFx *)m_port.getFx();
Shinya Kitaoka 120a6e
  TXshLevelColumn *texColumn = lcfx->getColumn();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const TXshCell &texCell = texColumn->getCell(row);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXshSimpleLevel *texSl = texCell.getSimpleLevel();
Shinya Kitaoka 120a6e
  const TFrameId &texFid = texCell.getFrameId();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (!texSl || texSl->getType() == MESH_XSHLEVEL) return false;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Build dpi data
Shinya Kitaoka 120a6e
  TPointD texDpi(texSl->getDpi(texFid, 0));
Shinya Kitaoka 120a6e
  if (texDpi.x == 0.0 || texDpi.y == 0.0 || texSl->getType() == PLI_XSHLEVEL)
Shinya Kitaoka 120a6e
    texDpi.x = texDpi.y = Stage::inch;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Build reference transforms data
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // NOTE: TAffine() corresponds to IMAGE coordinates here, not WORLD
Shinya Kitaoka 120a6e
  // coordinates. This is achieved
Shinya Kitaoka 120a6e
  // by removing the level's dpi affine during render-tree build-up (see
Shinya Kitaoka 120a6e
  // scenefx.cpp).
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  worldLevelToLevelAff = TScale(texDpi.x / Stage::inch, texDpi.y / Stage::inch);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Initialize input render settings
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // In the case of vector images, in order to retain the image quality required
Shinya Kitaoka 120a6e
  // by info.m_affine,
Shinya Kitaoka 120a6e
  // the scale component is allowed too.
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // In the raster image case, we'll use the original image reference IF the
Shinya Kitaoka 120a6e
  // affine is a magnification
Shinya Kitaoka 120a6e
  // (ie the scale is > 1.0) - OTHERWISE, the OpenGL minification filter is too
Shinya Kitaoka 120a6e
  // crude since it renders
Shinya Kitaoka 120a6e
  // a fragment using its 4 adjacent pixels ONLY; in this case, we'll pass the
Shinya Kitaoka 120a6e
  // affine below.
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const TAffine &handledAff = TRasterFx::handledAffine(info, frame);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (texSl->getType() == PLI_XSHLEVEL) {
Shinya Kitaoka 120a6e
    info.m_affine = handledAff;
Shinya Kitaoka 120a6e
    buildRenderSettings(frame, info);
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    info.m_affine = TAffine();
Shinya Kitaoka 120a6e
    buildRenderSettings(frame, info);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // NOTE: scale = handledAff.a11 / worldLevelToLevelAff.a11
Shinya Kitaoka 120a6e
    if (handledAff.a11 < worldLevelToLevelAff.a11)
Shinya Kitaoka 120a6e
      info.m_affine =
Shinya Kitaoka 120a6e
          TScale(handledAff.a11 / worldLevelToLevelAff.a11) * info.m_affine;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool PlasticDeformerFx::buildTextureData(double frame, TRenderSettings &info,
Shinya Kitaoka 120a6e
                                         TAffine &worldLevelToLevelAff) {
Shinya Kitaoka 120a6e
  // Common case (typically happen with sub-xsheets)
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  buildRenderSettings(frame, info);  // Adjust the info
Shinya Kitaoka 120a6e
  worldLevelToLevelAff = TAffine();  // Reference match
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlasticDeformerFx::doCompute(TTile &tile, double frame,
Shinya Kitaoka 120a6e
                                  const TRenderSettings &info) {
Shinya Kitaoka 120a6e
  if (!m_port.isConnected()) {
Shinya Kitaoka 120a6e
    tile.getRaster()->clear();
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int row = (int)frame;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Build texture data
Shinya Kitaoka 120a6e
  TRenderSettings texInfo(info);
Shinya Kitaoka 120a6e
  TAffine worldTexLevelToTexLevelAff;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (dynamic_cast<tlevelcolumnfx *="">(m_port.getFx())) {</tlevelcolumnfx>
Shinya Kitaoka 120a6e
    if (!buildTextureDataSl(frame, texInfo, worldTexLevelToTexLevelAff)) return;
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    buildTextureData(frame, texInfo, worldTexLevelToTexLevelAff);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Initialize mesh level vars
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const TXshCell &meshCell = m_xsh->getCell(row, m_col);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXshSimpleLevel *meshSl = meshCell.getSimpleLevel();
Shinya Kitaoka 120a6e
  const TFrameId &meshFid = meshCell.getFrameId();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (!meshSl || meshSl->getType() != MESH_XSHLEVEL) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Retrieve mesh image and deformation
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TStageObject *meshColumnObj =
Shinya Kitaoka 120a6e
      m_xsh->getStageObject(TStageObjectId::ColumnId(m_col));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TMeshImageP mi(meshSl->getFrame(meshFid, false));
Shinya Kitaoka 120a6e
  if (!mi) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Retrieve deformation data
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const PlasticSkeletonDeformationP &sd =
Shinya Kitaoka 120a6e
      meshColumnObj->getPlasticSkeletonDeformation();
Shinya Kitaoka 120a6e
  assert(sd);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double sdFrame = meshColumnObj->paramsTime(frame);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Build dpi data
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TPointD meshDpi(meshSl->getDpi(meshFid, 0));
Shinya Kitaoka 120a6e
  assert(meshDpi.x != 0.0 && meshDpi.y != 0.0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Build reference transforms data
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Build affines
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const TAffine &imageToTextureAff           = texInfo.m_affine;
Shinya Kitaoka 120a6e
  const TAffine &worldTexLevelToWorldMeshAff = m_texPlacement;
Shinya Kitaoka 120a6e
  const TAffine &meshToWorldMeshAff =
Shinya Kitaoka 120a6e
      TScale(Stage::inch / meshDpi.x, Stage::inch / meshDpi.y);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const TAffine &meshToTexLevelAff = worldTexLevelToTexLevelAff *
Shinya Kitaoka 120a6e
                                     worldTexLevelToWorldMeshAff.inv() *
Shinya Kitaoka 120a6e
                                     meshToWorldMeshAff;
Shinya Kitaoka 120a6e
  const TAffine &meshToTextureAff = imageToTextureAff * meshToTexLevelAff;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Retrieve deformer data
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TScale worldMeshToMeshAff(meshDpi.x / Stage::inch, meshDpi.y / Stage::inch);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 2a7129
  std::unique_ptr<const plasticdeformerdatagroup=""> dataGroup(</const>
Shinya Kitaoka 120a6e
      PlasticDeformerStorage::instance()->processOnce(
Shinya Kitaoka 120a6e
          sdFrame, mi.getPointer(), sd.getPointer(), sd->skeletonId(sdFrame),
Shinya Kitaoka 120a6e
          worldMeshToMeshAff));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Build texture
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Build the mesh's bounding box and map it to input reference
Shinya Kitaoka 120a6e
  TRectD meshBBox(meshToTextureAff * mi->getBBox());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Now, build the tile's geometry
Shinya Kitaoka 120a6e
  TRectD texBBox;
Shinya Kitaoka 120a6e
  m_port->getBBox(frame, texBBox, texInfo);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRectD bbox = texBBox * meshBBox;
Shinya Kitaoka 120a6e
  if (bbox.getLx() <= 0.0 || bbox.getLy() <= 0.0) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  bbox.x0 = tfloor(bbox.x0);
Shinya Kitaoka 120a6e
  bbox.y0 = tfloor(bbox.y0);
Shinya Kitaoka 120a6e
  bbox.x1 = tceil(bbox.x1);
Shinya Kitaoka 120a6e
  bbox.y1 = tceil(bbox.y1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TDimension tileSize(tround(bbox.getLx()), tround(bbox.getLy()));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Then, compute the input image
Shinya Kitaoka 120a6e
  TTile inTile;
Shinya Kitaoka 120a6e
  m_port->allocateAndCompute(inTile, bbox.getP00(), tileSize, TRasterP(), frame,
Shinya Kitaoka 120a6e
                             texInfo);
shun_iwasawa 7e52a2
  QOpenGLContext *context;
Shinya Kitaoka 120a6e
  // Draw the textured mesh
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    // Prepare texture
Shinya Kitaoka 120a6e
    TRaster32P tex(inTile.getRaster());
Shinya Kitaoka 120a6e
    TRop::depremultiply(tex);  // Textures must be stored depremultiplied.
Shinya Kitaoka 120a6e
                               // See docs about the tglDraw() below.
Shinya Kitaoka 120a6e
    static TAtomicVar var;
Shinya Kitaoka 120a6e
    const std::string &texId = "render_tex " + std::to_string(++var);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Prepare an OpenGL context
shun_iwasawa 7e52a2
    context = new QOpenGLContext();
shun-iwasawa b08db1
    if (QOpenGLContext::currentContext())
shun-iwasawa b08db1
      context->setShareContext(QOpenGLContext::currentContext());
shun_iwasawa 7e52a2
    context->setFormat(QSurfaceFormat::defaultFormat());
shun_iwasawa 7e52a2
    context->create();
shun_iwasawa 7e52a2
    context->makeCurrent(info.m_offScreenSurface.get());
shun_iwasawa 7e52a2
shun_iwasawa 7e52a2
    TDimension d = tile.getRaster()->getSize();
shun_iwasawa 7e52a2
    QOpenGLFramebufferObject fb(d.lx, d.ly);
shun_iwasawa 7e52a2
shun_iwasawa 7e52a2
    fb.bind();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Load texture into the context
Shinya Kitaoka 120a6e
    TTexturesStorage *ts                = TTexturesStorage::instance();
Shinya Kitaoka 120a6e
    const DrawableTextureDataP &texData = ts->loadTexture(texId, tex, bbox);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Draw
shun_iwasawa 7e52a2
    glViewport(0, 0, d.lx, d.ly);
shun_iwasawa 7e52a2
    glClearColor(0, 0, 0, 0);
shun_iwasawa 7e52a2
    glClear(GL_COLOR_BUFFER_BIT);
shun_iwasawa 7e52a2
shun_iwasawa 7e52a2
    glMatrixMode(GL_PROJECTION);
shun_iwasawa 7e52a2
    glLoadIdentity();
shun_iwasawa 7e52a2
    gluOrtho2D(0, d.lx, 0, d.ly);
shun_iwasawa 7e52a2
shun_iwasawa 7e52a2
    glMatrixMode(GL_MODELVIEW);
shun_iwasawa 7e52a2
    glLoadIdentity();
Shinya Kitaoka 120a6e
    tglMultMatrix(TTranslation(-tile.m_pos) * info.m_affine *
Shinya Kitaoka 120a6e
                  meshToWorldMeshAff);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    glEnable(GL_BLEND);
Shinya Kitaoka 120a6e
    glEnable(GL_TEXTURE_2D);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    tglDraw(*mi, *texData, meshToTextureAff, *dataGroup);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Retrieve drawing and copy to output tile
Toshihiro Shimizu 890ddd
shun_iwasawa 7e52a2
    QImage img = fb.toImage().scaled(QSize(d.lx, d.ly), Qt::IgnoreAspectRatio,
shun_iwasawa 7e52a2
                                     Qt::SmoothTransformation);
shun_iwasawa 7e52a2
    int wrap      = tile.getRaster()->getLx() * sizeof(TPixel32);
shun_iwasawa 7e52a2
    uchar *srcPix = img.bits();
shun_iwasawa 7e52a2
    uchar *dstPix = tile.getRaster()->getRawData() + wrap * (d.ly - 1);
shun_iwasawa 7e52a2
    for (int y = 0; y < d.ly; y++) {
shun_iwasawa 7e52a2
      memcpy(dstPix, srcPix, wrap);
shun_iwasawa 7e52a2
      dstPix -= wrap;
shun_iwasawa 7e52a2
      srcPix += wrap;
shun_iwasawa 7e52a2
    }
shun_iwasawa 7e52a2
    fb.release();
shun_iwasawa 7e52a2
shun_iwasawa 7e52a2
    // context->getRaster(tile.getRaster());
shun_iwasawa 7e52a2
    glFlush();
shun_iwasawa 7e52a2
    glFinish();
Shinya Kitaoka 120a6e
    // Cleanup
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // No need to disable stuff - the context dies here
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // ts->unloadTexture(texId);                                // Auto-released
Shinya Kitaoka 120a6e
    // due to display list destruction
shun_iwasawa 7e52a2
    context->deleteLater();
shun_iwasawa 7e52a2
    // context->doneCurrent();
Shinya Kitaoka 120a6e
  }
shun_iwasawa 7e52a2
  assert(glGetError() == GL_NO_ERROR);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlasticDeformerFx::doDryCompute(TRectD &rect, double frame,
Shinya Kitaoka 120a6e
                                     const TRenderSettings &info) {
Shinya Kitaoka 120a6e
  if (!m_port.isConnected()) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int row = (int)frame;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRenderSettings texInfo(info);
Shinya Kitaoka 120a6e
  TAffine worldTexLevelToTexLevelAff;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (dynamic_cast<tlevelcolumnfx *="">(m_port.getFx())) {</tlevelcolumnfx>
Shinya Kitaoka 120a6e
    if (!buildTextureDataSl(frame, texInfo, worldTexLevelToTexLevelAff)) return;
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    buildTextureData(frame, texInfo, worldTexLevelToTexLevelAff);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const TXshCell &meshCell = m_xsh->getCell(row, m_col);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXshSimpleLevel *meshSl = meshCell.getSimpleLevel();
Shinya Kitaoka 120a6e
  const TFrameId &meshFid = meshCell.getFrameId();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (!meshSl || meshSl->getType() == MESH_XSHLEVEL) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TStageObject *meshColumnObj =
Shinya Kitaoka 120a6e
      m_xsh->getStageObject(TStageObjectId::ColumnId(m_col));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TMeshImageP mi(meshSl->getFrame(meshFid, false));
Shinya Kitaoka 120a6e
  if (!mi) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const PlasticSkeletonDeformationP &sd =
Shinya Kitaoka 120a6e
      meshColumnObj->getPlasticSkeletonDeformation();
Shinya Kitaoka 120a6e
  assert(sd);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TPointD meshDpi(meshSl->getDpi(meshFid, 0));
Shinya Kitaoka 120a6e
  assert(meshDpi.x != 0.0 && meshDpi.y != 0.0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const TAffine &textureToImageAff        = texInfo.m_affine;
Shinya Kitaoka 120a6e
  const TAffine &worldImageToWorldMeshAff = m_texPlacement;
Shinya Kitaoka 120a6e
  const TAffine &meshToWorldMeshAff =
Shinya Kitaoka 120a6e
      TScale(Stage::inch / meshDpi.x, Stage::inch / meshDpi.y);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const TAffine &meshToTextureAff =
Shinya Kitaoka 120a6e
      textureToImageAff.inv() * worldTexLevelToTexLevelAff *
Shinya Kitaoka 120a6e
      worldImageToWorldMeshAff.inv() * meshToWorldMeshAff;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Build the mesh's bounding box and map it to input reference
Shinya Kitaoka 120a6e
  TRectD meshBBox(meshToTextureAff * mi->getBBox());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Now, build the tile's geometry
Shinya Kitaoka 120a6e
  TRectD texBBox;
Shinya Kitaoka 120a6e
  m_port->getBBox(frame, texBBox, texInfo);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRectD bbox = texBBox * meshBBox;
Shinya Kitaoka 120a6e
  if (bbox.getLx() <= 0.0 || bbox.getLy() <= 0.0) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  bbox.x0 = tfloor(bbox.x0);
Shinya Kitaoka 120a6e
  bbox.y0 = tfloor(bbox.y0);
Shinya Kitaoka 120a6e
  bbox.x1 = tceil(bbox.x1);
Shinya Kitaoka 120a6e
  bbox.y1 = tceil(bbox.y1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_port->dryCompute(bbox, frame, texInfo);
Toshihiro Shimizu 890ddd
}