|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#include "morphtool.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tgl.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tvectorgl.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tvectorrenderdata.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tvectorimage.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tstroke.h"
|
|
Toshihiro Shimizu |
890ddd |
#include <math.h></math.h>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#include "tools/toolhandle.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "toonz/txshlevelhandle.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "toonz/tframehandle.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "toonz/txshsimplelevel.h"
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
class Deformation
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Toshihiro Shimizu |
890ddd |
std::vector<tpointd> m_controlPoints;</tpointd>
|
|
Toshihiro Shimizu |
890ddd |
int m_selected;
|
|
Toshihiro Shimizu |
890ddd |
TAffine m_aff;
|
|
Toshihiro Shimizu |
890ddd |
std::vector<tpointd> m_delta;</tpointd>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int getClosest(const TPointD &p) const;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
Deformation();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void update()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
TPointD p0 = m_controlPoints[0];
|
|
Toshihiro Shimizu |
890ddd |
TPointD p1 = m_controlPoints[2];
|
|
Toshihiro Shimizu |
890ddd |
TPointD p2 = m_controlPoints[4];
|
|
Toshihiro Shimizu |
890ddd |
double a00 = p0.x - p2.x, a01 = p1.x - p2.x, a10 = p0.y - p2.y, a11 = p1.y - p2.y;
|
|
Toshihiro Shimizu |
890ddd |
TAffine aff(a00, a01, 0, a10, a11, 0);
|
|
Toshihiro Shimizu |
890ddd |
aff = aff.inv();
|
|
Toshihiro Shimizu |
890ddd |
TPointD d = -(aff * p2);
|
|
Toshihiro Shimizu |
890ddd |
aff.a13 = d.x;
|
|
Toshihiro Shimizu |
890ddd |
aff.a23 = d.y;
|
|
Toshihiro Shimizu |
890ddd |
m_aff = aff;
|
|
Toshihiro Shimizu |
890ddd |
m_delta.resize(3);
|
|
Toshihiro Shimizu |
890ddd |
m_delta[0] = m_controlPoints[1] - p0;
|
|
Toshihiro Shimizu |
890ddd |
m_delta[1] = m_controlPoints[3] - p1;
|
|
Toshihiro Shimizu |
890ddd |
m_delta[2] = m_controlPoints[5] - p2;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TPointD apply(const TPointD &p, double t = 1.0)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
TPointD d = m_aff * p;
|
|
Toshihiro Shimizu |
890ddd |
double c0 = d.x, c1 = d.y, c2 = 1 - c0 - c1;
|
|
Toshihiro Shimizu |
890ddd |
TPointD delta = c0 * m_delta[0] + c1 * m_delta[1] + c2 * m_delta[2];
|
|
Toshihiro Shimizu |
890ddd |
return p + delta * t;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void deform(TStroke *dstStroke, const TStroke *srcStroke, double t = 1.0)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
int n = srcStroke->getControlPointCount();
|
|
Toshihiro Shimizu |
890ddd |
if (dstStroke->getControlPointCount() < n)
|
|
Toshihiro Shimizu |
890ddd |
n = dstStroke->getControlPointCount();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (int i = 0; i < n; i++) {
|
|
Toshihiro Shimizu |
890ddd |
TThickPoint srcPoint = srcStroke->getControlPoint(i);
|
|
Toshihiro Shimizu |
890ddd |
dstStroke->setControlPoint(i, apply(srcPoint, t));
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void deform(TVectorImage *dstImage, const TVectorImage *srcImage, double t = 1.0)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
update();
|
|
Toshihiro Shimizu |
890ddd |
int n = srcImage->getStrokeCount();
|
|
Toshihiro Shimizu |
890ddd |
if ((int)dstImage->getStrokeCount() < n)
|
|
Toshihiro Shimizu |
890ddd |
n = dstImage->getStrokeCount();
|
|
Toshihiro Shimizu |
890ddd |
std::vector<int> ii(n);</int>
|
|
Toshihiro Shimizu |
890ddd |
std::vector<tstroke *=""> oldStrokes(n);</tstroke>
|
|
Toshihiro Shimizu |
890ddd |
for (int i = 0; i < n; i++) {
|
|
Toshihiro Shimizu |
890ddd |
ii[i] = i;
|
|
Toshihiro Shimizu |
890ddd |
oldStrokes[i] = srcImage->getStroke(i);
|
|
Toshihiro Shimizu |
890ddd |
deform(dstImage->getStroke(i), oldStrokes[i], t);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
dstImage->notifyChangedStrokes(ii, oldStrokes);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void updateLevel()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
TTool::Application *app = TTool::getApplication();
|
|
Toshihiro Shimizu |
890ddd |
if (!app->getCurrentLevel()->getLevel())
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Toshihiro Shimizu |
890ddd |
TXshSimpleLevelP xl = app->getCurrentLevel()->getLevel()->getSimpleLevel();
|
|
Toshihiro Shimizu |
890ddd |
if (app->getCurrentFrame()->getFrameType() != TFrameHandle::LevelFrame)
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TFrameId fid = app->getCurrentFrame()->getFid();
|
|
Toshihiro Shimizu |
890ddd |
TVectorImageP src = xl->getFrame(fid, true);
|
|
Toshihiro Shimizu |
890ddd |
int count = src->getStrokeCount();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (int i = 1; i < 10; i++) {
|
|
Toshihiro Shimizu |
890ddd |
++fid;
|
|
Toshihiro Shimizu |
890ddd |
if (!xl->isFid(fid)) {
|
|
Toshihiro Shimizu |
890ddd |
TVectorImageP vi = new TVectorImage();
|
|
Toshihiro Shimizu |
890ddd |
xl->setFrame(fid, vi);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
TVectorImageP vi = xl->getFrame(fid, true);
|
|
Toshihiro Shimizu |
890ddd |
TVectorImageP dst = src->clone();
|
|
Toshihiro Shimizu |
890ddd |
deform(dst.getPointer(), src.getPointer(), (double)i / (double)9);
|
|
Toshihiro Shimizu |
890ddd |
count = dst->getStrokeCount();
|
|
Toshihiro Shimizu |
890ddd |
vi->mergeImage(dst, TAffine());
|
|
Toshihiro Shimizu |
890ddd |
app->getCurrentTool()->getTool()->notifyImageChanged(fid);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
Deformation::Deformation()
|
|
Toshihiro Shimizu |
890ddd |
: m_selected(-1)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_controlPoints.resize(6);
|
|
Toshihiro Shimizu |
890ddd |
m_controlPoints[0] = TPointD(-250, 100);
|
|
Toshihiro Shimizu |
890ddd |
m_controlPoints[2] = TPointD(0, -300);
|
|
Toshihiro Shimizu |
890ddd |
m_controlPoints[4] = TPointD(250, 100);
|
|
Toshihiro Shimizu |
890ddd |
for (int i = 0; i < 6; i += 2)
|
|
Toshihiro Shimizu |
890ddd |
m_controlPoints[i + 1] = m_controlPoints[i];
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int Deformation::getClosest(const TPointD &p) const
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
int k = -1;
|
|
Toshihiro Shimizu |
890ddd |
double closestD2 = 0;
|
|
Toshihiro Shimizu |
890ddd |
for (int i = 0; i < (int)m_controlPoints.size(); i++) {
|
|
Toshihiro Shimizu |
890ddd |
TPointD cp = m_controlPoints[i];
|
|
Toshihiro Shimizu |
890ddd |
double d2 = norm2(p - cp);
|
|
Toshihiro Shimizu |
890ddd |
if (k < 0 || d2 <= closestD2) {
|
|
Toshihiro Shimizu |
890ddd |
closestD2 = d2;
|
|
Toshihiro Shimizu |
890ddd |
k = i;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
return closestD2 < 100 ? k : -1;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
Deformation deformation;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Toshihiro Shimizu |
890ddd |
TThickPoint deform(const TThickPoint &p)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
double r2 = p.x*p.x+p.y*p.y;
|
|
Toshihiro Shimizu |
890ddd |
double f = exp(-r2*0.001);
|
|
Toshihiro Shimizu |
890ddd |
return p + delta * f;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
MorphTool::MorphTool()
|
|
Toshihiro Shimizu |
890ddd |
: m_pixelSize(1)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
MorphTool::~MorphTool()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void MorphTool::setImage(const TVectorImageP &vi)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_vi = vi;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void MorphTool::leftButtonDown(const TPointD &pos, const TMouseEvent &e)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_lastPos = m_firstPos = pos;
|
|
Toshihiro Shimizu |
890ddd |
int index = deformation.getClosest(pos);
|
|
Toshihiro Shimizu |
890ddd |
if (index >= 0)
|
|
Toshihiro Shimizu |
890ddd |
deformation.m_selected = index;
|
|
Toshihiro Shimizu |
890ddd |
else
|
|
Toshihiro Shimizu |
890ddd |
deformation.m_selected = -1;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (m_vi && index >= 0) {
|
|
Toshihiro Shimizu |
890ddd |
m_vi2 = m_vi->clone();
|
|
Toshihiro Shimizu |
890ddd |
deformation.deform(m_vi2.getPointer(), m_vi.getPointer());
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
m_vi2 = TVectorImageP();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void MorphTool::leftButtonDrag(const TPointD &pos, const TMouseEvent &e)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (deformation.m_selected < 0)
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Toshihiro Shimizu |
890ddd |
TPointD delta = pos - m_lastPos;
|
|
Toshihiro Shimizu |
890ddd |
m_lastPos = pos;
|
|
Toshihiro Shimizu |
890ddd |
deformation.m_controlPoints[deformation.m_selected] += delta;
|
|
Toshihiro Shimizu |
890ddd |
if ((deformation.m_selected & 1) == 0)
|
|
Toshihiro Shimizu |
890ddd |
deformation.m_controlPoints[deformation.m_selected + 1] += delta;
|
|
Toshihiro Shimizu |
890ddd |
if (m_vi2 && m_vi)
|
|
Toshihiro Shimizu |
890ddd |
deformation.deform(m_vi2.getPointer(), m_vi.getPointer());
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void MorphTool::leftButtonUp(const TPointD &pos, const TMouseEvent &e)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_vi2 = TVectorImageP();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void MorphTool::draw()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_pixelSize = sqrt(tglGetPixelSize2());
|
|
Toshihiro Shimizu |
890ddd |
if (m_vi2) {
|
|
Toshihiro Shimizu |
890ddd |
TVectorRenderData rd(TTranslation(10, 10), TRect(), 0, 0);
|
|
Toshihiro Shimizu |
890ddd |
tglDraw(rd, m_vi2.getPointer());
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double u = m_pixelSize * 5;
|
|
Toshihiro Shimizu |
890ddd |
for (int i = 0; i < (int)deformation.m_controlPoints.size(); i++) {
|
|
Toshihiro Shimizu |
890ddd |
TPointD p = deformation.m_controlPoints[i];
|
|
Toshihiro Shimizu |
890ddd |
bool selected = deformation.m_selected == i;
|
|
Toshihiro Shimizu |
890ddd |
bool base = (i & 1) == 0;
|
|
Toshihiro Shimizu |
890ddd |
if (base)
|
|
Toshihiro Shimizu |
890ddd |
if (selected)
|
|
Toshihiro Shimizu |
890ddd |
glColor3d(0.8, 0.8, 0.1);
|
|
Toshihiro Shimizu |
890ddd |
else
|
|
Toshihiro Shimizu |
890ddd |
glColor3d(0.5, 0.5, 0.1);
|
|
Toshihiro Shimizu |
890ddd |
else if (selected)
|
|
Toshihiro Shimizu |
890ddd |
glColor3d(0.8, 0.3, 0.1);
|
|
Toshihiro Shimizu |
890ddd |
else
|
|
Toshihiro Shimizu |
890ddd |
glColor3d(0.5, 0.1, 0.1);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double r = base ? u * 2 : u * 1;
|
|
Toshihiro Shimizu |
890ddd |
tglDrawDisk(p, r);
|
|
Toshihiro Shimizu |
890ddd |
glColor3d(0, 0, 0);
|
|
Toshihiro Shimizu |
890ddd |
tglDrawCircle(p, r);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
glColor3f(0, 1, 0);
|
|
Toshihiro Shimizu |
890ddd |
for (int i = 0; i + 1 < (int)deformation.m_controlPoints.size(); i += 2) {
|
|
Toshihiro Shimizu |
890ddd |
TPointD a = deformation.m_controlPoints[i];
|
|
Toshihiro Shimizu |
890ddd |
TPointD b = deformation.m_controlPoints[i + 1];
|
|
Toshihiro Shimizu |
890ddd |
tglDrawSegment(a, b);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Toshihiro Shimizu |
890ddd |
deformation.update();
|
|
Toshihiro Shimizu |
890ddd |
glBegin(GL_LINES);
|
|
Toshihiro Shimizu |
890ddd |
for(double x = -200; x<=200; x+=20)
|
|
Toshihiro Shimizu |
890ddd |
for(double y = -200; y<=200; y+=20)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
TPointD p0(x,y);
|
|
Toshihiro Shimizu |
890ddd |
TPointD p1 = deformation.apply(p0);
|
|
Toshihiro Shimizu |
890ddd |
glColor3d(0,1,0);
|
|
Toshihiro Shimizu |
890ddd |
tglVertex(p0);
|
|
Toshihiro Shimizu |
890ddd |
glColor3d(1,0,0);
|
|
Toshihiro Shimizu |
890ddd |
tglVertex(p1);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
glEnd();
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool MorphTool::keyDown(int key, TUINT32 flags, const TPoint &pos)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (key == 'A')
|
|
Toshihiro Shimizu |
890ddd |
deformation.updateLevel();
|
|
Toshihiro Shimizu |
890ddd |
else
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|