#include "morpher.h" #include #include "glypheditor.h" #include "glyphviewer.h" #include #include #include #include #include #include #include #include #include #include #include #include class MorphInc { public: MorphInc(); virtual ~MorphInc(); void cleanup(); float _alpha_stroke_src; float _alpha_fill_src; float _alpha_stroke_dest; float _alpha_fill_dest; boolean _same_stroke; boolean _same_fill; Color* _stroke_dest; Color* _fill_dest; Coord* _x; Coord* _y; Transformer _t; }; MorphInc::MorphInc () { _x = nil; _y = nil; _stroke_dest = nil; _fill_dest = nil; cleanup(); } MorphInc::~MorphInc () { cleanup(); } void MorphInc::cleanup () { delete _x; delete _y; _x = nil; _y = nil; _alpha_stroke_src = 0.0; _alpha_fill_src = 0.0; _alpha_stroke_dest = 0.0; _alpha_fill_dest = 0.0; Resource::unref(_stroke_dest); Resource::unref(_fill_dest); _stroke_dest = nil; _fill_dest = nil; _same_stroke = false; _same_fill = false; Transformer t; *(&_t) = *(&t); } class MorphGraphic : public Graphic31 { public: MorphGraphic(Graphic31* src = nil, Graphic31* dest = nil, long steps = 0); virtual ~MorphGraphic(); void reinit(Graphic31* src = nil, Graphic31* dest = nil, long steps = 0); void forward(long = 1); void reverse(long = 1); boolean done(); long total_steps(); long counter(); virtual void draw_gs (Canvas*, Graphic31*); virtual Graphic31& operator = (Graphic31&); protected: void expandLine(Coord*, Coord*, int, Coord*, Coord*, int, boolean); void expandSpline(Coord*, Coord*, int, Coord*, Coord*, int, boolean); protected: Graphic31* _src; Graphic31* _dest; MorphInc _morph_inc; long _steps; long _count; }; inline long MorphGraphic::total_steps () { return _steps; } inline long MorphGraphic::counter () { return _count; } inline boolean MorphGraphic::done () { return _steps == _count || _count == 0; } MorphGraphic::MorphGraphic(Graphic31* src, Graphic31* dest, long steps) { _src = nil; _dest = nil; reinit(src, dest, steps); } MorphGraphic::~MorphGraphic () { Resource::unref(_src); Resource::unref(_dest); } Graphic31& MorphGraphic::operator = (Graphic31& g) { Graphic31::operator = (g); _curved = g.curved(); _closed = g.closed(); return *this; } void MorphGraphic::forward (long steps) { if (_count+steps <= _steps) { _count += steps; } else { return; } for (int i = 0; i < _ctrlpts; i++) { _x[i] += _morph_inc._x[i]*steps; _y[i] += _morph_inc._y[i]*steps; } recompute_shape(); if (!_morph_inc._same_stroke && _stroke != nil) { stroke( new Color( *_stroke, _stroke->alpha()+_morph_inc._alpha_stroke_src*steps ) ); } if (!_morph_inc._same_fill && _fill != nil) { fill( new Color(*_fill, _fill->alpha()+_morph_inc._alpha_fill_src*steps) ); } Color* stroke_dest = _morph_inc._stroke_dest; if (!_morph_inc._same_stroke && stroke_dest != nil) { _morph_inc._stroke_dest = new Color( *stroke_dest, stroke_dest->alpha()+ _morph_inc._alpha_stroke_dest*steps ); _morph_inc._stroke_dest->ref(); stroke_dest->unref(); } Color* fill_dest = _morph_inc._fill_dest; if (!_morph_inc._same_fill && fill_dest != nil) { _morph_inc._fill_dest = new Color( *fill_dest, fill_dest->alpha()+_morph_inc._alpha_fill_dest*steps ); _morph_inc._fill_dest->ref(); fill_dest->unref(); } Coord a00 = 1.0, a01 = 0.0, a10= 0.0, a11 = 1.0, a20 = 0.0, a21 = 0.0; Coord b00 = 1.0, b01 = 0.0, b10= 0.0, b11 = 1.0, b20 = 0.0, b21 = 0.0; _t->matrix(a00, a01, a10, a11, a20, a21); _morph_inc._t.matrix(b00, b01, b10, b11, b20, b21); a00 += b00*steps; a01 += b01*steps; a10 += b10*steps; a11 += b11*steps; a20 += b20*steps; a21 += b21*steps; Transformer t(a00, a01, a10, a11, a20, a21); *_t = t; } void MorphGraphic::reverse (long steps) { if (_count-steps >= 0) { _count -= steps; } else { return; } for (int i = 0; i < _ctrlpts; i++) { _x[i] -= _morph_inc._x[i]*steps; _y[i] -= _morph_inc._y[i]*steps; } recompute_shape(); if (!_morph_inc._same_stroke && _stroke != nil) { stroke( new Color( *_stroke, _stroke->alpha()-_morph_inc._alpha_stroke_src*steps ) ); } if (!_morph_inc._same_fill && _fill != nil) { fill( new Color(*_fill, _fill->alpha()-_morph_inc._alpha_fill_src*steps) ); } Color* stroke_dest = _morph_inc._stroke_dest; if (!_morph_inc._same_stroke && stroke_dest != nil) { _morph_inc._stroke_dest = new Color( *stroke_dest, stroke_dest->alpha()- _morph_inc._alpha_stroke_dest*steps ); _morph_inc._stroke_dest->ref(); stroke_dest->unref(); } Color* fill_dest = _morph_inc._fill_dest; if (!_morph_inc._same_fill && fill_dest != nil) { _morph_inc._fill_dest = new Color( *fill_dest, fill_dest->alpha()-_morph_inc._alpha_fill_dest*steps ); _morph_inc._fill_dest->ref(); fill_dest->unref(); } Coord a00 = 1.0, a01 = 0.0, a10= 0.0, a11 = 1.0, a20 = 0.0, a21 = 0.0; Coord b00 = 1.0, b01 = 0.0, b10= 0.0, b11 = 1.0, b20 = 0.0, b21 = 0.0; _t->matrix(a00, a01, a10, a11, a20, a21); _morph_inc._t.matrix(b00, b01, b10, b11, b20, b21); a00 -= b00*steps; a01 -= b01*steps; a10 -= b10*steps; a11 -= b11*steps; a20 -= b20*steps; a21 -= b21*steps; Transformer t(a00, a01, a10, a11, a20, a21); *_t = t; } void MorphGraphic::reinit (Graphic31* src, Graphic31* dest, long steps) { Resource::ref(src); Resource::ref(dest); Resource::unref(_src); Resource::unref(_dest); _morph_inc.cleanup(); _src = src; _dest = dest; _steps = steps; _count = 0; if (_src != nil && _dest != nil) { Coord* x0, *y0, *x1, *y1; *this = *src; const Color* dstroke = _dest->stroke(); if ( dstroke != nil && _stroke != nil && _brush != nil && _dest->brush() != nil && (_brush->width() == _dest->brush()->width()) && (_closed == _dest->closed()) ) { ColorIntensity rs, gs, bs; ColorIntensity rd, gd, bd; dstroke->intensities(rd, gd, bd); _stroke->intensities(rs, gs, bs); if (rd == rs && gd == gs && bd == bs) { _morph_inc._same_stroke = true; } } if (!_morph_inc._same_stroke) { if (dstroke != nil) { _morph_inc._stroke_dest = new Color(*dstroke, 0.0); _morph_inc._stroke_dest->ref(); _morph_inc._alpha_stroke_dest = dstroke->alpha()/(float)steps; } if (_stroke != nil) { _morph_inc._alpha_stroke_src = -_stroke->alpha()/(float)steps; } } const Color* dfill = _dest->fill(); if (dfill != nil && _fill != nil) { ColorIntensity rs, gs, bs; ColorIntensity rd, gd, bd; dfill->intensities(rd, gd, bd); _fill->intensities(rs, gs, bs); if (rd == rs && gd == gs && bd == bs) { _morph_inc._same_fill = true; } } if (!_morph_inc._same_fill) { if (dfill != nil) { _morph_inc._fill_dest = new Color(*dfill, 0.0); _morph_inc._fill_dest->ref(); _morph_inc._alpha_fill_dest = dfill->alpha()/(float)steps; } if (_fill != nil) { _morph_inc._alpha_fill_src = -_fill->alpha()/(float)steps; } } int count0 = _src->ctrlpts(x0, y0); int count1 = _dest->ctrlpts(x1, y1); _curved = _src->curved(); if (_dest->curved()) { _curved = true; } static Coord sx[1000]; static Coord sy[1000]; if (!_src->curved() && _dest->curved()) { sx[0] = x0[0]; sy[0] = y0[0]; int k = 1; for (int j = 0; j < count0; j++) { sx[k] = x0[j]; sy[k++] = y0[j]; sx[k] = x0[j]; sy[k++] = y0[j]; sx[k] = x0[j]; sy[k++] = y0[j]; } count0 = k; x0 = sx; y0 = sy; } else if (_src->curved() && !_dest->curved()) { sx[0] = x1[0]; sy[0] = y1[0]; int k = 1; for (int j = 0; j < count1; j++) { sx[k] = x1[j]; sy[k++] = y1[j]; sx[k] = x1[j]; sy[k++] = y1[j]; sx[k] = x1[j]; sy[k++] = y1[j]; } count1 = k; x1 = sx; y1 = sy; } int count = max(count0, count1); _morph_inc._x = new Coord[count]; _morph_inc._y = new Coord[count]; delete _x; delete _y; _x = new Coord[count]; _y = new Coord[count]; _buf_size = count; _ctrlpts = count; if (count0 > count1) { if (!_curved) { expandLine( x1, y1, count1, _morph_inc._x, _morph_inc._y, count, _dest->closed() ); } else { expandSpline( x1, y1, count1, _morph_inc._x, _morph_inc._y, count, _dest->closed() ); } x1 = _morph_inc._x; y1 = _morph_inc._y; } else { if (!_curved) { expandLine( x0, y0, count0, _morph_inc._x, _morph_inc._y, count, _src->closed() ); } else { expandSpline( x0, y0, count0, _morph_inc._x, _morph_inc._y, count, _src->closed() ); } x0 = _morph_inc._x; y0 = _morph_inc._y; } for (int i = 0; i < _ctrlpts; i++) { _x[i] = x0[i]; _y[i] = y0[i]; _morph_inc._x[i] = (x1[i]-x0[i])/(float)steps; _morph_inc._y[i] = (y1[i]-y0[i])/(float)steps; } Coord a00 = 1.0, a01 = 0.0, a10= 0.0, a11 = 1.0, a20 = 0.0, a21 = 0.0; Coord b00 = 1.0, b01 = 0.0, b10= 0.0, b11 = 1.0, b20 = 0.0, b21 = 0.0; if (_src->transformer() != nil) { _src->transformer()->matrix(a00, a01, a10, a11, a20, a21); } if (_dest->transformer() != nil) { _dest->transformer()->matrix(b00, b01, b10, b11, b20, b21); } a00 = (b00-a00)/(float)steps; a01 = (b01-a01)/(float)steps; a10 = (b10-a10)/(float)steps; a11 = (b11-a11)/(float)steps; a20 = (b20-a20)/(float)steps; a21 = (b21-a21)/(float)steps; Transformer t(a00, a01, a10, a11, a20, a21); _morph_inc._t = t; recompute_shape(); } } void MorphGraphic::draw_gs (Canvas* c, Graphic31* gs) { const Brush* brush = gs->brush(); const Color* stroke = gs->stroke(); const Color* fill = gs->fill(); Transformer* tx = gs->transformer(); if (tx != nil) { c->push_transform(); c->transform(*tx); } c->new_path(); c->move_to(_x[0], _y[0]); if (_curved) { for (int i = 1; i < _ctrlpts; i += 3) { c->curve_to( _x[i + 2], _y[i + 2], _x[i], _y[i], _x[i + 1], _y[i + 1] ); } } else { for (int i = 1; i < _ctrlpts; ++i) { c->line_to(_x[i], _y[i]); } } if (_morph_inc._same_stroke) { if (_closed) { c->close_path(); } if (brush != nil && stroke != nil) { c->stroke(stroke, brush); } } else { Color* dest_stroke = _morph_inc._stroke_dest; const Brush* dest_brush = _dest->brush(); if (_closed && !_dest->closed()) { if (dest_brush != nil && dest_stroke != nil) { c->stroke(dest_stroke, dest_brush); } c->close_path(); if (brush != nil && stroke != nil) { c->stroke(stroke, brush); } } else if (!_closed && _dest->closed()) { if (brush != nil && stroke != nil) { c->stroke(stroke, brush); } c->close_path(); if (dest_brush != nil && dest_stroke != nil) { c->stroke(dest_stroke, dest_brush); } } else if (!_closed && !_dest->closed()) { if (brush != nil && stroke != nil) { c->stroke(stroke, brush); } if (dest_brush != nil && dest_stroke != nil) { c->stroke(dest_stroke, dest_brush); } } else { c->close_path(); if (brush != nil && stroke != nil) { c->stroke(stroke, brush); } if (dest_brush != nil && dest_stroke != nil) { c->stroke(dest_stroke, dest_brush); } } } if (fill != nil) { c->fill(fill); } if (!_morph_inc._same_fill) { Color* dest_fill = _morph_inc._fill_dest; if (dest_fill != nil) { c->fill(dest_fill); } } if (tx != nil) { c->pop_transform(); } } void MorphGraphic::expandLine ( Coord* x0, Coord* y0, int count0, Coord* x1, Coord* y1, int count1, boolean closed ) { int slot; int diff = count1 - count0; if (closed) { slot = diff/count0+1; } else { slot = diff/(count0-1)+1; } int j = 0; int total = 0; for (int i = 0; i < count0; i++) { x1[j] = x0[i]; y1[j++] = y0[i]; for (int k = 0;total < diff && k < slot; k++) { float factor = (float)(k+1)/(float)(slot+1); if ((i+1) == count0) { x1[j] = (x0[0]-x0[i])*factor + x0[i]; y1[j++] = (y0[0]-y0[i])*factor + y0[i]; } else { x1[j] = (x0[i+1]-x0[i])*factor + x0[i]; y1[j++] = (y0[i+1]-y0[i])*factor + y0[i]; } total++; } } } void MorphGraphic::expandSpline ( Coord* x0, Coord* y0, int count0, Coord* x1, Coord* y1, int count1, boolean closed ) { int slot; int diff = count1 - count0; if (closed) { slot = (int)(diff/count0/3.0)+1; } else { slot = (int)(diff/(count0-1)/3.0)+1; } int j = 0; int total = 0; int i; for (i = 0; i < count0; i++) { x1[j] = x0[i]; y1[j++] = y0[i]; float factor = 1.0/(float)(slot+1); for (int k = 0;total+3 <= diff && k < slot; k++) { float xfactor = (k+1)*factor; if ((i+1) == count0) { x1[j] = (x0[0]-x0[i])*xfactor+x0[i]; y1[j] = (y0[0]-y0[i])*xfactor+y0[i]; } else { x1[j] = (x0[i+1]-x0[i])*xfactor+x0[i]; y1[j] = (y0[i+1]-y0[i])*xfactor+y0[i]; } x1[j+1] = (x1[j]+x0[i])/2.0; y1[j+1] = (y1[j]+y0[i])/2.0; x1[j+2] = 2*x1[j]-x1[j+1]; y1[j+2] = 2*y1[j]-y1[j+1]; total += 3; j += 3; } } diff -= total; for (j = 0; j < diff; j++) { x1[j] = x0[i-1]; y1[j] = y0[i-1]; } } declarePtrList(GraphicList, Graphic31); // implementPtrList(GraphicList, Graphic31); declarePtrList(MGraphicList, MorphGraphic); implementPtrList(MGraphicList, MorphGraphic); declarePtrList(MMGraphicList, MGraphicList); implementPtrList(MMGraphicList, MGraphicList); declareIOCallback(Morpher); implementIOCallback(Morpher); class MorpherImpl { public: MorpherImpl(long size, long steps, GlyphEditor*, IOHandler*); virtual ~MorpherImpl(); void init(); void new_session(); void clean_lists(); void interpolate(Graphic31*, Graphic31*); GraphicList* _glist; MMGraphicList* _mmglist; GraphicMaster* _gmaster; GlyphEditor* _ged; IOHandler* _callback; unsigned int _mode; long _count; long _steps; }; MorpherImpl::MorpherImpl ( long size, long steps, GlyphEditor* ged, IOHandler* callback ) { _glist = new GraphicList(size); _mmglist = new MMGraphicList(8); _ged = ged; Resource::ref(_ged); _callback = callback; _mode = Morpher::p; _steps = steps; _count = 0; _gmaster = new GraphicMaster; _gmaster->ref(); } MorpherImpl::~MorpherImpl () { Resource::unref(_ged); _gmaster->unref(); delete _callback; } void MorpherImpl::clean_lists () { int i, j; for (i = 0; i < _glist->count(); i++) { _glist->item(i)->unref(); } delete _glist; _glist = nil; for (i = 0; i < _mmglist->count(); i++) { MGraphicList* ml = _mmglist->item(i); for (j = 0; j < ml->count(); j++) { ml->item(j)->unref(); } delete ml; } delete _mmglist; _mmglist = nil; } void MorpherImpl::interpolate (Graphic31* src, Graphic31* dest) { MGraphicList* cur = _mmglist->item(_mmglist->count()-1); int src_count = (int)src->count_(); int dest_count = (int)dest->count_(); if (src_count == 0 && dest_count == 0) { MorphGraphic* mgr = new MorphGraphic(src, dest, _steps); mgr->ref(); cur->append(mgr); } else if (src_count > 0 && dest_count > 0) { int max_count = max(src_count, dest_count); for (int i = 0; i < max_count; i++) { int src_i = min(i, src_count-1); int dest_i = min(i, dest_count-1); interpolate(src->component_(src_i), dest->component_(dest_i)); } } else if (src_count == 0) { for (int i = 0; i < dest_count; i++) { interpolate(src, dest->component_(i)); } } else { for (int i = 0; i < src_count; i++) { interpolate(src->component_(i), dest); } } } void MorpherImpl::init () { long count = _glist->count(); if (count > 1) { MGraphicList* mglist = new MGraphicList; _mmglist->append(mglist); interpolate(_glist->item(count-2), _glist->item(count-1)); if (count == 2) { for (int i = 0; i < mglist->count(); i++) { _gmaster->append_(mglist->item(i)); } } } } void MorpherImpl::new_session () { _ged->viewer()->root(new GraphicMaster); _ged->viewer()->redraw(); clean_lists(); _glist = new GraphicList; _mmglist = new MMGraphicList; _gmaster->unref(); _gmaster = new GraphicMaster; _gmaster->ref(); _count = 0; } Morpher::Morpher (long size, long steps, GlyphEditor* ged) { _m_impl = new MorpherImpl( size, steps, ged, new IOCallback(Morpher)(this, &Morpher::tick) ); } Morpher::~Morpher () { delete _m_impl; } void Morpher::init () { _m_impl->init(); } void Morpher::new_session () { _m_impl->new_session(); } void Morpher::execute (unsigned int code) { if (_m_impl->_mode != code) { _m_impl->_mode = code; switch(code) { case fr: case rp: case rps: case ff: case fp: case fps: case r: { Dispatcher::instance().startTimer( 0, 100000, _m_impl->_callback ); if (code == r) { append(_m_impl->_ged->viewer()->root()); init(); } else { _m_impl->_ged->viewer()->root(_m_impl->_gmaster); } } break; case cp: { _m_impl->_ged->viewer()->root(_m_impl->_gmaster); if (_m_impl->_count == _m_impl->_mmglist->count()) { Coord l, b, r, t; GlyphEditor* ged = _m_impl->_ged; Graphic31* mgr = ged->viewer()->root(); Window* w = ged->window(); Canvas* c = w->canvas(); mgr->getbounds(l, b, r, t); c->damage(l, b, r, t); rewind(); } Dispatcher::instance().startTimer( 0, 100000, _m_impl->_callback ); } break; case p: Dispatcher::instance().stopTimer(_m_impl->_callback); break; default: break; } } } void Morpher::rewind() { for (int i = 0; i < _m_impl->_mmglist->count(); i++) { MGraphicList* mglist = _m_impl->_mmglist->item(i); for (int j = 0; j < mglist->count(); j++) { MorphGraphic* mgr = mglist->item(j); mgr->reverse(mgr->counter()); } } _m_impl->_count = 0; } void Morpher::tick (long, long) { if (_m_impl->_mode == r || _m_impl->_mmglist->count() == 0) { _m_impl->_ged->pause(); return; } int code = _m_impl->_mode; long s_timer = 100000; long rate = s_timer/3; if (code == fr || code == ff) { rate = s_timer/10; } Coord l, b, r, t; GlyphEditor* ged = _m_impl->_ged; Graphic31* root = ged->viewer()->root(); MGraphicList* mglist = _m_impl->_mmglist->item(_m_impl->_count); long gcount = mglist->count(); Window* w = ged->window(); Canvas* c = w->canvas(); switch(code) { case fr: case rp: case rps: case fp: case ff: case fps: case cp: { MorphGraphic* mgr = nil; root->getbounds(l, b, r, t); c->damage(l, b, r, t); int i; for (i = 0; i < gcount; i++) { mgr = mglist->item(i); if (code == fr || code == rp || code == rps) { mgr->reverse(); } else { mgr->forward(); } } root->getbounds(l, b, r, t); c->damage(l, b, r, t); CanvasRep& rep = *c->rep(); CanvasDamage& cd = rep.damage_; rep.start_repair(); root->drawclipped(c, cd.left, cd.bottom, cd.right, cd.top); rep.finish_repair(); w->display()->flush(); if (!mgr->done()) { if (code == fps || code == rps) { _m_impl->_ged->pause(); } else { Dispatcher::instance().startTimer( 0, rate, _m_impl->_callback ); } } else { boolean done = false; if (code == fr || code == rp || code == rps) { _m_impl->_count--; if (_m_impl->_count < 0) { _m_impl->_count++; done = true; } } else { _m_impl->_count++; if (_m_impl->_count == _m_impl->_mmglist->count()) { _m_impl->_count--; done = true; } } if (!done || code == cp) { gcount = root->count_(); root->getbounds(l, b, r, t); c->damage(l, b, r, t); int i; for (i = 0; i < gcount; i++) { root->remove_(0); } if (done && code == cp) { mglist = _m_impl->_mmglist->item(0); rewind(); } else { mglist = _m_impl->_mmglist->item(_m_impl->_count); } gcount = mglist->count(); for (i = 0; i < gcount; i++) { root->append_(mglist->item(i)); } if (code == fps || code == rps) { _m_impl->_ged->pause(); } else { Dispatcher::instance().startTimer( 0, rate, _m_impl->_callback ); } } else { _m_impl->_ged->pause(); } } break; } default: break; } } long Morpher::count () { return _m_impl->_glist->count(); } Graphic31* Morpher::item (long index) const { return _m_impl->_glist->item(index); } void Morpher::prepend (Graphic31* g) { g->ref(); _m_impl->_glist->prepend(g); } void Morpher::append (Graphic31* g) { g->ref(); _m_impl->_glist->append(g); } void Morpher::insert (long index, Graphic31* g) { g->ref(); _m_impl->_glist->insert(index, g); } void Morpher::remove (long index) { Graphic31* g = item(index); if (g != nil) { g->unref(); _m_impl->_glist->remove(index); } } void Morpher::remove_all () { long count = _m_impl->_glist->count(); for(int i = 0; i < count; i++) { _m_impl->_glist->item(i)->unref(); } _m_impl->_glist->remove_all(); }