| |
| |
| #include "toonz/plasticdeformerfx.h" |
| |
| |
| #include "toonz/txsheet.h" |
| #include "toonz/txshleveltypes.h" |
| #include "toonz/txshcell.h" |
| #include "toonz/tcolumnfx.h" |
| #include "toonz/txshlevelcolumn.h" |
| #include "toonz/dpiscale.h" |
| #include "toonz/stage.h" |
| |
| |
| #include "ext/plasticskeleton.h" |
| #include "ext/plasticdeformerstorage.h" |
| #include "ext/ttexturesstorage.h" |
| #include "ext/plasticvisualsettings.h" |
| #include "ext/meshutils.h" |
| |
| |
| #include "trenderer.h" |
| |
| |
| #include "tgl.h" |
| #include "tofflinegl.h" |
| #include "tgldisplaylistsmanager.h" |
| #include "tconvert.h" |
| #include "trop.h" |
| |
| FX_IDENTIFIER_IS_HIDDEN(PlasticDeformerFx, "plasticDeformerFx") |
| |
| |
| |
| |
| |
| namespace |
| { |
| |
| std::string toString(const TAffine &aff) |
| { |
| return |
| |
| |
| (areAlmostEqual(aff.a11, 0.0) ? "0" : ::toString(aff.a11, 5)) + "," + |
| (areAlmostEqual(aff.a12, 0.0) ? "0" : ::toString(aff.a12, 5)) + "," + |
| (areAlmostEqual(aff.a13, 0.0) ? "0" : ::toString(aff.a13, 5)) + "," + |
| (areAlmostEqual(aff.a21, 0.0) ? "0" : ::toString(aff.a21, 5)) + "," + |
| (areAlmostEqual(aff.a22, 0.0) ? "0" : ::toString(aff.a22, 5)) + "," + |
| (areAlmostEqual(aff.a23, 0.0) ? "0" : ::toString(aff.a23, 5)); |
| } |
| |
| |
| |
| std::string toString(SkVD *vd, double sdFrame) |
| { |
| std::string result; |
| |
| for (int p = 0; p < SkVD::PARAMS_COUNT; ++p) |
| result += ::toString(vd->m_params[p]->getValue(sdFrame), 5) + " "; |
| |
| return result; |
| } |
| |
| |
| |
| std::string toString(const PlasticSkeleton::vertex_type &vx) |
| { |
| |
| return ::toString(vx.P().x, 5) + " " + ::toString(vx.P().y, 5); |
| } |
| |
| |
| |
| std::string toString(const PlasticSkeletonDeformationP &sd, double sdFrame) |
| { |
| std::string result; |
| |
| const PlasticSkeletonP &skeleton = sd->skeleton(sdFrame); |
| if (!skeleton || skeleton->empty()) |
| return result; |
| |
| const tcg::list<PlasticSkeleton::vertex_type> &vertices = skeleton->vertices(); |
| |
| tcg::list<PlasticSkeleton::vertex_type>::const_iterator vt, vEnd(vertices.end()); |
| |
| result = toString(*vertices.begin()); |
| for (vt = vertices.begin(); vt != vEnd; ++vt) { |
| result += "; " + toString(*vt); |
| result += " " + toString(sd->vertexDeformation(vt->name()), sdFrame); |
| } |
| |
| return result; |
| } |
| |
| } |
| |
| |
| |
| |
| |
| PlasticDeformerFx::PlasticDeformerFx() |
| : TRasterFx() |
| { |
| addInputPort("source", m_port); |
| } |
| |
| |
| |
| TFx *PlasticDeformerFx::clone(bool recursive) const |
| { |
| PlasticDeformerFx *fx = dynamic_cast<PlasticDeformerFx *>(TFx::clone(recursive)); |
| assert(fx); |
| |
| fx->m_xsh = m_xsh; |
| fx->m_col = m_col; |
| |
| return fx; |
| } |
| |
| |
| |
| bool PlasticDeformerFx::canHandle(const TRenderSettings &info, double frame) |
| { |
| |
| |
| |
| return true; |
| } |
| |
| |
| |
| string PlasticDeformerFx::getAlias(double frame, const TRenderSettings &info) const |
| { |
| std::string alias(getFxType()); |
| alias += "["; |
| |
| if (m_port.isConnected()) { |
| TRasterFxP ifx = m_port.getFx(); |
| assert(ifx); |
| |
| alias += ifx->getAlias(frame, info); |
| } |
| |
| TStageObject *meshColumnObj = m_xsh->getStageObject(TStageObjectId::ColumnId(m_col)); |
| const PlasticSkeletonDeformationP &sd = meshColumnObj->getPlasticSkeletonDeformation(); |
| if (sd) |
| alias += ", " + toString(sd, meshColumnObj->paramsTime(frame)); |
| |
| alias + "]"; |
| |
| return alias; |
| } |
| |
| |
| |
| bool PlasticDeformerFx::doGetBBox(double frame, TRectD &bbox, const TRenderSettings &info) |
| { |
| if (!m_port.isConnected()) |
| return false; |
| |
| |
| bbox = TConsts::infiniteRectD; |
| return true; |
| } |
| |
| |
| |
| void PlasticDeformerFx::buildRenderSettings(double frame, TRenderSettings &info) |
| { |
| |
| |
| |
| |
| |
| |
| info.m_bpp = 32; |
| info.m_affine = m_port->handledAffine(info, frame); |
| } |
| |
| |
| |
| bool PlasticDeformerFx::buildTextureDataSl( |
| double frame, TRenderSettings &info, TAffine &worldLevelToLevelAff) |
| { |
| int row = (int)frame; |
| |
| |
| TLevelColumnFx *lcfx = (TLevelColumnFx *)m_port.getFx(); |
| TXshLevelColumn *texColumn = lcfx->getColumn(); |
| |
| const TXshCell &texCell = texColumn->getCell(row); |
| |
| TXshSimpleLevel *texSl = texCell.getSimpleLevel(); |
| const TFrameId &texFid = texCell.getFrameId(); |
| |
| if (!texSl || texSl->getType() == MESH_XSHLEVEL) |
| return false; |
| |
| |
| TPointD texDpi(texSl->getDpi(texFid, 0)); |
| if (texDpi.x == 0.0 || texDpi.y == 0.0 || texSl->getType() == PLI_XSHLEVEL) |
| texDpi.x = texDpi.y = Stage::inch; |
| |
| |
| |
| |
| |
| |
| worldLevelToLevelAff = TScale(texDpi.x / Stage::inch, texDpi.y / Stage::inch); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| const TAffine &handledAff = TRasterFx::handledAffine(info, frame); |
| |
| if (texSl->getType() == PLI_XSHLEVEL) { |
| info.m_affine = handledAff; |
| buildRenderSettings(frame, info); |
| } else { |
| info.m_affine = TAffine(); |
| buildRenderSettings(frame, info); |
| |
| |
| if (handledAff.a11 < worldLevelToLevelAff.a11) |
| info.m_affine = TScale(handledAff.a11 / worldLevelToLevelAff.a11) * info.m_affine; |
| } |
| |
| return true; |
| } |
| |
| |
| |
| bool PlasticDeformerFx::buildTextureData( |
| double frame, TRenderSettings &info, TAffine &worldLevelToLevelAff) |
| { |
| |
| |
| buildRenderSettings(frame, info); |
| worldLevelToLevelAff = TAffine(); |
| |
| return true; |
| } |
| |
| |
| |
| void PlasticDeformerFx::doCompute(TTile &tile, double frame, const TRenderSettings &info) |
| { |
| if (!m_port.isConnected()) { |
| tile.getRaster()->clear(); |
| return; |
| } |
| |
| int row = (int)frame; |
| |
| |
| TRenderSettings texInfo(info); |
| TAffine worldTexLevelToTexLevelAff; |
| |
| if (dynamic_cast<TLevelColumnFx *>(m_port.getFx())) { |
| if (!buildTextureDataSl(frame, texInfo, worldTexLevelToTexLevelAff)) |
| return; |
| } else |
| buildTextureData(frame, texInfo, worldTexLevelToTexLevelAff); |
| |
| |
| |
| const TXshCell &meshCell = m_xsh->getCell(row, m_col); |
| |
| TXshSimpleLevel *meshSl = meshCell.getSimpleLevel(); |
| const TFrameId &meshFid = meshCell.getFrameId(); |
| |
| if (!meshSl || meshSl->getType() != MESH_XSHLEVEL) |
| return; |
| |
| |
| |
| TStageObject *meshColumnObj = m_xsh->getStageObject(TStageObjectId::ColumnId(m_col)); |
| |
| TMeshImageP mi(meshSl->getFrame(meshFid, false)); |
| if (!mi) |
| return; |
| |
| |
| |
| const PlasticSkeletonDeformationP &sd = meshColumnObj->getPlasticSkeletonDeformation(); |
| assert(sd); |
| |
| double sdFrame = meshColumnObj->paramsTime(frame); |
| |
| |
| |
| TPointD meshDpi(meshSl->getDpi(meshFid, 0)); |
| assert(meshDpi.x != 0.0 && meshDpi.y != 0.0); |
| |
| |
| |
| |
| |
| const TAffine &imageToTextureAff = texInfo.m_affine; |
| const TAffine &worldTexLevelToWorldMeshAff = m_texPlacement; |
| const TAffine &meshToWorldMeshAff = TScale(Stage::inch / meshDpi.x, Stage::inch / meshDpi.y); |
| |
| const TAffine &meshToTexLevelAff = worldTexLevelToTexLevelAff * worldTexLevelToWorldMeshAff.inv() * meshToWorldMeshAff; |
| const TAffine &meshToTextureAff = imageToTextureAff * meshToTexLevelAff; |
| |
| |
| |
| TScale worldMeshToMeshAff(meshDpi.x / Stage::inch, meshDpi.y / Stage::inch); |
| |
| std::auto_ptr<const PlasticDeformerDataGroup> dataGroup( |
| PlasticDeformerStorage::instance()->processOnce( |
| sdFrame, mi.getPointer(), sd.getPointer(), sd->skeletonId(sdFrame), worldMeshToMeshAff)); |
| |
| |
| |
| |
| TRectD meshBBox(meshToTextureAff * mi->getBBox()); |
| |
| |
| TRectD texBBox; |
| m_port->getBBox(frame, texBBox, texInfo); |
| |
| TRectD bbox = texBBox * meshBBox; |
| if (bbox.getLx() <= 0.0 || bbox.getLy() <= 0.0) |
| return; |
| |
| bbox.x0 = tfloor(bbox.x0); |
| bbox.y0 = tfloor(bbox.y0); |
| bbox.x1 = tceil(bbox.x1); |
| bbox.y1 = tceil(bbox.y1); |
| |
| TDimension tileSize(tround(bbox.getLx()), tround(bbox.getLy())); |
| |
| |
| TTile inTile; |
| m_port->allocateAndCompute(inTile, bbox.getP00(), tileSize, TRasterP(), frame, texInfo); |
| |
| |
| { |
| |
| TRaster32P tex(inTile.getRaster()); |
| TRop::depremultiply(tex); |
| |
| static TAtomicVar var; |
| const std::string &texId = "render_tex " + ::toString((int)++var); |
| |
| |
| std::auto_ptr<TOfflineGL> context(new TOfflineGL(tile.getRaster()->getSize())); |
| context->makeCurrent(); |
| |
| |
| TTexturesStorage *ts = TTexturesStorage::instance(); |
| const DrawableTextureDataP &texData = ts->loadTexture(texId, tex, bbox); |
| |
| |
| glPushMatrix(); |
| tglMultMatrix(TTranslation(-tile.m_pos) * info.m_affine * |
| meshToWorldMeshAff); |
| |
| glEnable(GL_BLEND); |
| glEnable(GL_TEXTURE_2D); |
| |
| tglDraw(*mi, *texData, meshToTextureAff, *dataGroup); |
| |
| |
| context->getRaster(tile.getRaster()); |
| |
| |
| |
| |
| |
| |
| context->doneCurrent(); |
| } |
| } |
| |
| |
| |
| void PlasticDeformerFx::doDryCompute(TRectD &rect, double frame, const TRenderSettings &info) |
| { |
| if (!m_port.isConnected()) |
| return; |
| |
| int row = (int)frame; |
| |
| TRenderSettings texInfo(info); |
| TAffine worldTexLevelToTexLevelAff; |
| |
| if (dynamic_cast<TLevelColumnFx *>(m_port.getFx())) { |
| if (!buildTextureDataSl(frame, texInfo, worldTexLevelToTexLevelAff)) |
| return; |
| } else |
| buildTextureData(frame, texInfo, worldTexLevelToTexLevelAff); |
| |
| const TXshCell &meshCell = m_xsh->getCell(row, m_col); |
| |
| TXshSimpleLevel *meshSl = meshCell.getSimpleLevel(); |
| const TFrameId &meshFid = meshCell.getFrameId(); |
| |
| if (!meshSl || meshSl->getType() == MESH_XSHLEVEL) |
| return; |
| |
| TStageObject *meshColumnObj = m_xsh->getStageObject(TStageObjectId::ColumnId(m_col)); |
| |
| TMeshImageP mi(meshSl->getFrame(meshFid, false)); |
| if (!mi) |
| return; |
| |
| const PlasticSkeletonDeformationP &sd = meshColumnObj->getPlasticSkeletonDeformation(); |
| assert(sd); |
| |
| TPointD meshDpi(meshSl->getDpi(meshFid, 0)); |
| assert(meshDpi.x != 0.0 && meshDpi.y != 0.0); |
| |
| const TAffine &textureToImageAff = texInfo.m_affine; |
| const TAffine &worldImageToWorldMeshAff = m_texPlacement; |
| const TAffine &meshToWorldMeshAff = TScale(Stage::inch / meshDpi.x, Stage::inch / meshDpi.y); |
| |
| const TAffine &meshToTextureAff = |
| textureToImageAff.inv() * worldTexLevelToTexLevelAff * worldImageToWorldMeshAff.inv() * meshToWorldMeshAff; |
| |
| |
| TRectD meshBBox(meshToTextureAff * mi->getBBox()); |
| |
| |
| TRectD texBBox; |
| m_port->getBBox(frame, texBBox, texInfo); |
| |
| TRectD bbox = texBBox * meshBBox; |
| if (bbox.getLx() <= 0.0 || bbox.getLy() <= 0.0) |
| return; |
| |
| bbox.x0 = tfloor(bbox.x0); |
| bbox.y0 = tfloor(bbox.y0); |
| bbox.x1 = tceil(bbox.x1); |
| bbox.y1 = tceil(bbox.y1); |
| |
| m_port->dryCompute(bbox, frame, texInfo); |
| } |
| |