2016-03-19 06:57:51 +13:00
// TnzCore includes
# include "tstroke.h"
# include "tgl.h"
// TnzBase includes
# include "tenv.h"
// TnzLib includes
# include "toonz/tstageobjectcmd.h"
# include "toonz/toonzimageutils.h"
# include "toonz/txshcolumn.h"
# include "toonz/txshsimplelevel.h"
# include "toonz/tstageobjecttree.h"
# include "toonz/tstageobjectspline.h"
# include "toonz/toonzscene.h"
# include "toonz/stage.h"
# include "toonz/txshcell.h"
# include "toonz/dpiscale.h"
# include "toonz/skeleton.h"
# include "toonz/tscenehandle.h"
# include "toonz/tobjecthandle.h"
# include "toonz/tpinnedrangeset.h"
# include "toonz/tframehandle.h"
# include "toonz/tcolumnhandle.h"
# include "toonz/txsheethandle.h"
# include "toonz/stageobjectutil.h"
// TnzQt includes
# include "toonzqt/selection.h"
# include "toonzqt/selectioncommandids.h"
// TnzTools includes
# include "tools/tool.h"
# include "tools/cursors.h"
# include "tools/toolutils.h"
# include "tw/keycodes.h"
// Qt includes
# include <QCoreApplication> // Qt translation support
# include <QPainter>
# include <QGLWidget>
# include <QPainterPath>
# include <QString>
# include <QImage>
# include <QFont>
# include <QFontMetrics>
# include "skeletonsubtools.h"
# include "skeletontool.h"
using namespace SkeletonSubtools ;
TEnv : : IntVar SkeletonGlobalKeyFrame ( " SkeletonToolGlobalKeyFrame " , 0 ) ;
TEnv : : IntVar SkeletonInverseKinematics ( " SkeletonToolInverseKinematics " , 0 ) ;
# define BUILD_SKELETON L"Build Skeleton"
# define ANIMATE L"Animate"
# define INVERSE_KINEMATICS L"Inverse Kinematics"
const double alpha = 0.4 ;
using SkeletonSubtools : : HookData ;
//============================================================
inline std : : string removeTrailingH ( std : : string handle )
{
if ( handle . find ( " H " ) = = 0 )
return handle . substr ( 1 ) ;
else
return handle ;
}
//============================================================
//
// util
//
//------------------------------------------------------------
// return true iff column ancestorIndex is column descentIndex or its parent or the parent of the parent, etc.
bool isAncestorOf ( int ancestorIndex , int descendentIndex )
{
TStageObjectId ancestorId = TStageObjectId : : ColumnId ( ancestorIndex ) ;
TStageObjectId descendentId = TStageObjectId : : ColumnId ( descendentIndex ) ;
TXsheet * xsh = TTool : : getApplication ( ) - > getCurrentXsheet ( ) - > getXsheet ( ) ;
while ( descendentId ! = ancestorId & & descendentId . isColumn ( ) )
descendentId = xsh - > getStageObjectParent ( descendentId ) ;
return descendentId = = ancestorId ;
}
//------------------------------------------------------------
void getHooks ( std : : vector < HookData > & hooks , TXsheet * xsh , int row , int col , TPointD dpiScale )
{
// nota. hook position is in the coordinate system of the parent object.
// a inch is Stage::inch
TXshCell cell = xsh - > getCell ( row , col ) ;
if ( ! cell . m_level )
return ;
TStageObjectId columnId = TStageObjectId : : ColumnId ( col ) ;
// handle is the current handle (pivot) of the column. It can be H1,H2,... or A,B,C,...
std : : string handle = xsh - > getStageObject ( TStageObjectId : : ColumnId ( col ) ) - > getHandle ( ) ;
bool handleIsHook = handle . find ( " H " ) = = 0 ;
TAffine aff = xsh - > getPlacement ( columnId , row ) ;
// imageDpiAff represent the scale factor between the image and the camera
// derived by dpi match (i.e. ignoring geometric transformation)
// cameraPos = imageDpiAff * imagePos
TAffine imageDpiAff ;
if ( cell . m_level - > getSimpleLevel ( ) )
imageDpiAff = getDpiAffine ( cell . m_level - > getSimpleLevel ( ) , cell . m_frameId , true ) ;
// center (inches)
TPointD center = xsh - > getCenter ( columnId , row ) ; // getHooks
if ( handleIsHook )
center = TPointD ( 0 , 0 ) ;
// add the hook #0 (i.e. the regular center)
hooks . push_back ( HookData ( xsh , col , 0 , aff * TScale ( Stage : : inch ) * center ) ) ;
// add the regular hooks
HookSet * hookSet = cell . m_level - > getHookSet ( ) ;
if ( hookSet & & hookSet - > getHookCount ( ) > 0 ) {
for ( int j = 0 ; j < hookSet - > getHookCount ( ) ; j + + ) {
Hook * hook = hookSet - > getHook ( j ) ;
if ( hook & & ! hook - > isEmpty ( ) ) {
TPointD pos = hook - > getAPos ( cell . m_frameId ) ;
pos = aff * imageDpiAff * pos ;
hooks . push_back ( HookData ( xsh , col , j + 1 , pos ) ) ;
}
}
}
}
//-------------------------------------------------------------------
void getConnectedColumns ( std : : set < int > & connectedColumns , TXsheet * xsh , int col )
{
TStageObjectId id ;
// insert col and all column ancestors
id = TStageObjectId : : ColumnId ( col ) ;
do {
connectedColumns . insert ( id . getIndex ( ) ) ;
id = xsh - > getStageObjectParent ( id ) ;
} while ( id . isColumn ( ) ) ;
// for each column
for ( int i = 0 ; i < xsh - > getColumnCount ( ) ; i + + ) {
id = TStageObjectId : : ColumnId ( i ) ;
std : : vector < TStageObjectId > stack ;
// find a column ancestor already connected; put all the column ancestors in stack
while ( id . isColumn ( ) & & connectedColumns . count ( id . getIndex ( ) ) = = 0 ) {
stack . push_back ( id ) ;
id = xsh - > getStageObjectParent ( id ) ;
}
if ( id . isColumn ( ) ) {
// the stack is connected
for ( int j = 0 ; j < ( int ) stack . size ( ) ; j + + )
connectedColumns . insert ( stack [ j ] . getIndex ( ) ) ;
}
}
}
bool canShowBone ( Skeleton : : Bone * bone , TXsheet * xsh , int row )
{
TStageObjectId id = bone - > getStageObject ( ) - > getId ( ) ;
if ( ! xsh - > getCell ( row , id . getIndex ( ) ) . isEmpty ( ) & & xsh - > getColumn ( id . getIndex ( ) ) - > isCamstandVisible ( ) )
return true ;
int i ;
for ( i = 0 ; i < bone - > getChildCount ( ) ; i + + ) {
if ( canShowBone ( bone - > getChild ( i ) , xsh , row ) )
return true ;
}
return false ;
}
//============================================================
HookData : : HookData ( TXsheet * xsh , int columnIndex , int hookId , const TPointD & pos )
: m_columnIndex ( columnIndex ) , m_hookId ( hookId ) , m_pos ( pos ) , m_isPivot ( false )
{
std : : string handle = xsh - > getStageObject ( TStageObjectId : : ColumnId ( columnIndex ) ) - > getHandle ( ) ;
if ( m_hookId = = 0 ) {
// if the current handle is a hook the the hook#0 should be the default center, i.e. B
if ( handle . find ( " H " ) = = 0 )
m_name = " B " ;
else {
m_name = handle ;
m_isPivot = true ;
}
} else {
m_name = toString ( m_hookId ) ;
m_isPivot = " H " + m_name = = handle ;
}
}
//============================================================
enum ToolDevice {
TD_None = - 1 ,
TD_Translation = 1 ,
TD_Rotation ,
TD_Center ,
TD_ChangeParent ,
TD_ChangeDrawing ,
TD_IncrementDrawing ,
TD_DecrementDrawing ,
TD_InverseKinematics ,
TD_Hook = 10000 ,
TD_LockStageObject = 20000 ,
TD_MagicLink = 30000 ,
TD_Test = 100000
} ;
//============================================================
//
// SkeletonTool
//
//------------------------------------------------------------
SkeletonTool skeletonTool ;
//-------------------------------------------------------------------
SkeletonTool : : SkeletonTool ( )
: TTool ( " T_Skeleton " ) , m_active ( false ) , m_device ( TD_None ) , m_mode ( " Mode: " ) , m_showOnlyActiveSkeleton ( " Show Only Active Skeleton " , false ) , m_globalKeyframes ( " Global Key " , false ) , m_dragTool ( 0 ) , m_firstTime ( true ) , m_currentFrame ( - 1 ) , m_parentProbe ( ) , m_parentProbeEnabled ( false ) , m_otherColumn ( - 1 ) , m_otherColumnBBoxAff ( ) , m_otherColumnBBox ( ) , m_labelPos ( 0 , 0 ) , m_label ( " " )
{
bind ( TTool : : CommonLevels ) ;
m_prop . bind ( m_mode ) ;
m_prop . bind ( m_globalKeyframes ) ;
m_prop . bind ( m_showOnlyActiveSkeleton ) ;
m_mode . setId ( " SkeletonMode " ) ;
m_globalKeyframes . setId ( " GlobalKey " ) ;
m_showOnlyActiveSkeleton . setId ( " ShowOnlyActiveSkeleton " ) ;
m_mode . addValue ( BUILD_SKELETON ) ;
m_mode . addValue ( ANIMATE ) ;
m_mode . addValue ( INVERSE_KINEMATICS ) ;
m_commandHandler = new CommandHandler ( ) ;
m_commandHandler - > setTempPinnedSet ( & m_temporaryPinnedColumns ) ;
}
//-------------------------------------------------------------------
SkeletonTool : : ~ SkeletonTool ( )
{
delete m_dragTool ;
}
//-------------------------------------------------------------------
2016-04-19 19:32:17 +12:00
bool SkeletonTool : : onPropertyChanged ( std : : string propertyName )
2016-03-19 06:57:51 +13:00
{
SkeletonGlobalKeyFrame = ( int ) ( m_globalKeyframes . getValue ( ) ) ;
// SkeletonInverseKinematics=(int)(m_ikEnabled.getValue());
invalidate ( ) ;
return false ;
}
//-------------------------------------------------------------------
bool SkeletonTool : : isGlobalKeyframesEnabled ( ) const
{
return m_globalKeyframes . getValue ( ) ;
}
//-------------------------------------------------------------------
void SkeletonTool : : updateTranslation ( )
{
// m_ikEnabled.setQStringName(tr("Inverse Kinematics"));
m_showOnlyActiveSkeleton . setQStringName ( tr ( " Show Only Active Skeleton " ) ) ;
m_globalKeyframes . setQStringName ( tr ( " Global Key " ) ) ;
m_mode . setQStringName ( tr ( " Mode: " ) ) ;
}
//-------------------------------------------------------------------
bool SkeletonTool : : doesApply ( ) const
{
TTool : : Application * app = TTool : : getApplication ( ) ;
TXsheet * xsh = app - > getCurrentXsheet ( ) - > getXsheet ( ) ;
assert ( xsh ) ;
TStageObjectId objId = app - > getCurrentObject ( ) - > getObjectId ( ) ;
if ( objId . isColumn ( ) ) {
TXshColumn * column = xsh - > getColumn ( objId . getIndex ( ) ) ;
if ( column & & column - > getSoundColumn ( ) )
return false ;
}
return true ;
}
//-------------------------------------------------------------------
void SkeletonTool : : mouseMove ( const TPointD & , const TMouseEvent & e )
{
int selectedDevice = pick ( e . m_pos ) ;
if ( selectedDevice ! = m_device ) {
m_device = selectedDevice ;
invalidate ( ) ;
}
}
//-------------------------------------------------------------------
void SkeletonTool : : leftButtonDown ( const TPointD & ppos , const TMouseEvent & e )
{
m_otherColumn = - 1 ;
m_otherColumnBBox = TRectD ( ) ;
m_otherColumnBBoxAff = TAffine ( ) ;
m_labelPos = TPointD ( 0 , 0 ) ;
m_label = " " ;
TUndoManager : : manager ( ) - > beginBlock ( ) ;
if ( ! doesApply ( ) )
return ;
assert ( m_dragTool = = 0 ) ;
m_dragTool = 0 ;
TTool : : Application * app = TTool : : getApplication ( ) ;
int currentColumnIndex = app - > getCurrentColumn ( ) - > getColumnIndex ( ) ;
TXsheet * xsh = app - > getCurrentScene ( ) - > getScene ( ) - > getXsheet ( ) ;
TPointD pos = ppos ;
int selectedDevice = pick ( e . m_pos ) ;
// cambio drawing
if ( selectedDevice = = TD_ChangeDrawing | |
selectedDevice = = TD_IncrementDrawing | |
selectedDevice = = TD_DecrementDrawing ) {
int d = 0 ;
if ( selectedDevice = = TD_IncrementDrawing )
d = 1 ;
else if ( selectedDevice = = TD_DecrementDrawing )
d = - 1 ;
m_dragTool = new ChangeDrawingTool ( this , d ) ;
m_dragTool - > leftButtonDown ( ppos , e ) ;
return ;
}
// click su un hook: attacca la colonna corrente tramite quell'hook
if ( TD_Hook < = selectedDevice & & selectedDevice < TD_Hook + 50 ) {
TXsheet * xsh = app - > getCurrentXsheet ( ) - > getXsheet ( ) ;
TStageObjectId objId = TStageObjectId : : ColumnId ( currentColumnIndex ) ;
TPointD p0 = getCurrentColumnMatrix ( ) * TPointD ( 0 , 0 ) ;
HookData hook ( xsh , currentColumnIndex , selectedDevice - TD_Hook , p0 ) ;
TStageObjectCmd : : setHandle ( objId , hook . getHandle ( ) , app - > getCurrentXsheet ( ) ) ;
app - > getCurrentXsheet ( ) - > notifyXsheetChanged ( ) ;
invalidate ( ) ;
return ;
}
// magic link
if ( TD_MagicLink < = selectedDevice & & selectedDevice < TD_MagicLink + ( int ) m_magicLinks . size ( ) ) {
magicLink ( selectedDevice - TD_MagicLink ) ;
app - > getCurrentXsheet ( ) - > notifyXsheetChanged ( ) ;
return ;
}
m_device = selectedDevice ;
bool justSelected = false ;
if ( m_device < 0 ) {
// nessun gadget cliccato. Eventualmente seleziono la colonna
std : : vector < int > columnIndexes ;
getViewer ( ) - > posToColumnIndexes ( e . m_pos , columnIndexes , getPixelSize ( ) * 5 , false ) ;
if ( ! columnIndexes . empty ( ) ) {
int columnIndex ;
columnIndex = columnIndexes . back ( ) ;
if ( columnIndex > = 0 & & columnIndex ! = currentColumnIndex ) {
if ( ! isColumnLocked ( columnIndex ) ) {
pos = getMatrix ( ) * pos ;
app - > getCurrentColumn ( ) - > setColumnIndex ( columnIndex ) ;
updateMatrix ( ) ;
currentColumnIndex = columnIndex ;
justSelected = true ;
pos = getMatrix ( ) . inv ( ) * pos ;
} else {
m_label = " Column is locked " ;
m_labelPos = pos ;
}
}
}
}
if ( m_device < 0 ) {
if ( m_mode . getValue ( ) = = INVERSE_KINEMATICS )
m_device = TD_InverseKinematics ;
else if ( m_mode . getValue ( ) = = ANIMATE )
m_device = TD_Rotation ;
}
// lock/unlock: modalita IK
if ( TD_LockStageObject < = m_device & & m_device < TD_LockStageObject + 1000 ) {
int columnIndex = m_device - TD_LockStageObject ;
int frame = app - > getCurrentFrame ( ) - > getFrame ( ) ;
togglePinnedStatus ( columnIndex , frame , e . isShiftPressed ( ) ) ;
invalidate ( ) ;
m_dragTool = 0 ;
return ;
}
switch ( m_device ) {
case TD_Center :
m_dragTool = new DragCenterTool ( this ) ;
break ;
case TD_Translation :
m_dragTool = new DragPositionTool ( this ) ;
break ;
case TD_Rotation :
m_dragTool = new DragRotationTool ( this , justSelected ) ;
break ;
case TD_ChangeParent :
m_dragTool = new ParentChangeTool ( this , getViewer ( ) ) ;
break ;
case TD_InverseKinematics : {
Skeleton * skeleton = new Skeleton ( ) ;
buildSkeleton ( * skeleton , currentColumnIndex ) ;
m_dragTool = new IKTool ( this , getViewer ( ) , skeleton , currentColumnIndex ) ;
break ;
}
}
if ( m_dragTool ) {
m_dragTool - > leftButtonDown ( pos , e ) ;
invalidate ( ) ;
}
}
//-------------------------------------------------------------------
void SkeletonTool : : leftButtonDrag ( const TPointD & pos , const TMouseEvent & e )
{
if ( m_dragTool ) {
m_dragTool - > leftButtonDrag ( pos , e ) ;
invalidate ( ) ;
}
}
//-------------------------------------------------------------------
void SkeletonTool : : leftButtonUp ( const TPointD & pos , const TMouseEvent & e )
{
m_label = " " ;
m_labelPos = TPointD ( 0 , 0 ) ;
if ( m_dragTool ) {
m_dragTool - > leftButtonUp ( pos , e ) ;
delete m_dragTool ;
m_dragTool = 0 ;
TTool : : getApplication ( ) - > getCurrentXsheet ( ) - > notifyXsheetChanged ( ) ;
TTool : : getApplication ( ) - > getCurrentObject ( ) - > notifyObjectIdChanged ( false ) ; // Keyframes navigator reads this
}
if ( m_device = = TD_IncrementDrawing | | m_device = = TD_DecrementDrawing | | m_device = = TD_ChangeDrawing )
m_device = pick ( e . m_pos ) ;
else
m_device = - 1 ;
invalidate ( ) ;
TUndoManager : : manager ( ) - > endBlock ( ) ;
}
//-------------------------------------------------------------------
bool SkeletonTool : : keyDown ( int key , TUINT32 flags , const TPoint & pos )
{
ChangeDrawingTool tool ( this , 0 ) ;
if ( key = = TwConsts : : TK_UpArrow )
tool . changeDrawing ( 1 ) ;
else if ( key = = TwConsts : : TK_DownArrow )
tool . changeDrawing ( - 1 ) ;
else
return false ;
invalidate ( ) ;
return true ;
}
//-------------------------------------------------------------------
class TogglePinnedStatusUndo : public TUndo
{
SkeletonTool * m_tool ;
std : : set < int > m_oldTemp , m_newTemp ;
int m_columnIndex , m_oldColumnIndex ;
std : : pair < int , int > m_newRange , m_oldRange ;
TAffine m_oldPlacement , m_newPlacement ;
std : : vector < std : : pair < TStageObjectId , TStageObject : : Keyframe > > m_keyframes ;
int m_frame ;
public :
TogglePinnedStatusUndo ( SkeletonTool * tool , int frame )
: m_tool ( tool ) , m_oldTemp ( ) , m_newTemp ( ) , m_columnIndex ( - 1 ) , m_oldColumnIndex ( - 1 ) , m_newRange ( 0 , - 1 ) , m_oldRange ( 0 , - 1 ) , m_frame ( frame )
{
}
void addBoneId ( const TStageObjectId & id )
{
TStageObject * stageObject = getXsheet ( ) - > getStageObject ( id ) ;
if ( stageObject ) {
TStageObject : : Keyframe k = stageObject - > getKeyframe ( m_frame ) ;
m_keyframes . push_back ( std : : make_pair ( id , k ) ) ;
}
}
void setOldRange ( int columnIndex , int first , int second , const TAffine & placement )
{
m_oldColumnIndex = columnIndex ;
m_oldRange = std : : make_pair ( first , second ) ;
m_oldPlacement = placement ;
}
void setNewRange ( int columnIndex , int first , int second , const TAffine & placement )
{
m_columnIndex = columnIndex ;
m_newRange = std : : make_pair ( first , second ) ;
m_newPlacement = placement ;
}
void setOldTemp ( const std : : set < int > & oldTemp ) { m_oldTemp = oldTemp ; }
void setNewTemp ( const std : : set < int > & newTemp ) { m_newTemp = newTemp ; }
TStageObject * getStageObject ( int columnIndex ) const
{
return TTool : : getApplication ( )
- > getCurrentXsheet ( )
- > getXsheet ( )
- > getStageObject ( TStageObjectId : : ColumnId ( columnIndex ) ) ;
}
TPinnedRangeSet * getRangeSet ( int columnIndex ) const
{
return getStageObject ( columnIndex ) - > getPinnedRangeSet ( ) ;
}
TXsheet * getXsheet ( ) const
{
return TTool : : getApplication ( ) - > getCurrentXsheet ( ) - > getXsheet ( ) ;
}
void notify ( ) const
{
m_tool - > invalidate ( ) ;
TXsheet * xsh = getXsheet ( ) ;
int index = m_columnIndex ;
if ( index < 0 )
index = m_oldColumnIndex ;
if ( index > = 0 ) {
TStageObjectId id = TStageObjectId : : ColumnId ( index ) ;
TStageObjectId parentId ;
while ( parentId = xsh - > getStageObjectParent ( id ) , parentId . isColumn ( ) )
id = parentId ;
xsh - > getStageObject ( id ) - > invalidate ( ) ;
TTool : : getApplication ( ) - > getCurrentXsheet ( ) - > notifyXsheetChanged ( ) ;
TTool : : getApplication ( ) - > getCurrentObject ( ) - > notifyObjectIdChanged ( false ) ;
}
}
void undo ( ) const
{
m_tool - > setTemporaryPinnedColumns ( m_oldTemp ) ;
if ( m_columnIndex > = 0 )
getRangeSet ( m_columnIndex ) - > removeRange ( m_newRange . first , m_newRange . second ) ;
if ( m_oldColumnIndex > = 0 ) {
TPinnedRangeSet * rangeSet = getRangeSet ( m_oldColumnIndex ) ;
rangeSet - > setRange ( m_oldRange . first , m_oldRange . second ) ;
rangeSet - > setPlacement ( m_oldPlacement ) ;
}
TXsheet * xsh = getXsheet ( ) ;
for ( int i = 0 ; i < ( int ) m_keyframes . size ( ) ; i + + ) {
TStageObject * stageObject = getXsheet ( ) - > getStageObject ( m_keyframes [ i ] . first ) ;
if ( ! stageObject )
continue ;
stageObject - > removeKeyframeWithoutUndo ( m_frame ) ;
if ( m_keyframes [ i ] . second . m_isKeyframe )
stageObject - > setKeyframeWithoutUndo ( m_frame , m_keyframes [ i ] . second ) ;
}
notify ( ) ;
}
void redo ( ) const
{
TXsheet * xsh = getXsheet ( ) ;
for ( int i = 0 ; i < ( int ) m_keyframes . size ( ) ; i + + ) {
TStageObject * stageObject = getXsheet ( ) - > getStageObject ( m_keyframes [ i ] . first ) ;
if ( stageObject )
stageObject - > setKeyframeWithoutUndo ( m_frame ) ;
}
m_tool - > setTemporaryPinnedColumns ( m_newTemp ) ;
if ( m_oldColumnIndex > = 0 )
getRangeSet ( m_oldColumnIndex ) - > removeRange ( m_oldRange . first , m_oldRange . second ) ;
if ( m_columnIndex > = 0 ) {
TPinnedRangeSet * rangeSet = getRangeSet ( m_columnIndex ) ;
rangeSet - > setRange ( m_newRange . first , m_newRange . second ) ;
rangeSet - > setPlacement ( m_newPlacement ) ;
}
notify ( ) ;
}
int getSize ( ) const
{
return sizeof * this ;
}
} ;
//-------------------------------------------------------------------
void SkeletonTool : : togglePinnedStatus ( int columnIndex , int frame , bool shiftPressed )
{
Skeleton skeleton ;
buildSkeleton ( skeleton , columnIndex ) ;
if ( ! skeleton . getRootBone ( ) | | ! skeleton . getRootBone ( ) - > getStageObject ( ) )
return ;
Skeleton : : Bone * bone = skeleton . getBoneByColumnIndex ( columnIndex ) ;
assert ( bone ) ;
if ( ! bone )
return ;
TogglePinnedStatusUndo * undo = new TogglePinnedStatusUndo ( this , frame ) ;
for ( int i = 0 ; i < skeleton . getBoneCount ( ) ; i + + ) {
TStageObject * obj = skeleton . getBone ( i ) - > getStageObject ( ) ;
if ( obj ) {
undo - > addBoneId ( obj - > getId ( ) ) ;
obj - > setKeyframeWithoutUndo ( frame ) ;
}
}
getApplication ( ) - > getCurrentXsheet ( ) - > notifyXsheetChanged ( ) ;
getApplication ( ) - > getCurrentObject ( ) - > notifyObjectIdChanged ( false ) ;
undo - > setOldTemp ( m_temporaryPinnedColumns ) ;
bool isTemporaryPinned = m_temporaryPinnedColumns . count ( columnIndex ) > 0 ;
if ( shiftPressed | | isTemporaryPinned ) {
if ( isTemporaryPinned )
m_temporaryPinnedColumns . erase ( columnIndex ) ;
else
m_temporaryPinnedColumns . insert ( columnIndex ) ;
} else {
TXsheet * xsh = TTool : : getApplication ( ) - > getCurrentXsheet ( ) - > getXsheet ( ) ;
TAffine placement = xsh - > getPlacement ( bone - > getStageObject ( ) - > getId ( ) , frame ) ;
TStageObjectId rootId = skeleton . getRootBone ( ) - > getStageObject ( ) - > getId ( ) ;
TAffine rootPlacement = xsh - > getPlacement ( rootId , frame ) ;
int pinnedStatus = bone - > getPinnedStatus ( ) ;
if ( pinnedStatus ! = Skeleton : : Bone : : PINNED ) {
int oldPinned = - 1 ;
for ( int i = 0 ; i < skeleton . getBoneCount ( ) ; i + + ) {
TStageObject * obj = skeleton . getBone ( i ) - > getStageObject ( ) ;
if ( obj - > getPinnedRangeSet ( ) - > isPinned ( frame ) ) {
oldPinned = i ;
break ;
}
}
int lastFrame = 1000000 ;
if ( oldPinned > = 0 ) {
assert ( skeleton . getBone ( oldPinned ) ! = bone ) ;
TStageObject * obj = skeleton . getBone ( oldPinned ) - > getStageObject ( ) ;
const TPinnedRangeSet : : Range * range = obj - > getPinnedRangeSet ( ) - > getRange ( frame ) ;
assert ( range & & range - > first < = frame & & frame < = range - > second ) ;
lastFrame = range - > second ;
TPinnedRangeSet * rangeSet = obj - > getPinnedRangeSet ( ) ;
rangeSet - > removeRange ( frame , range - > second ) ;
obj - > invalidate ( ) ;
undo - > setOldRange ( oldPinned , frame , range - > second , rangeSet - > getPlacement ( ) ) ;
} else {
for ( int i = 0 ; i < skeleton . getBoneCount ( ) ; i + + ) {
TStageObject * obj = skeleton . getBone ( i ) - > getStageObject ( ) ;
const TPinnedRangeSet : : Range * range = obj - > getPinnedRangeSet ( ) - > getNextRange ( frame ) ;
if ( range ) {
assert ( range - > first > frame ) ;
if ( range - > first - 1 < lastFrame )
lastFrame = range - > first - 1 ;
}
}
}
TStageObject * obj = bone - > getStageObject ( ) ;
TPinnedRangeSet * rangeSet = obj - > getPinnedRangeSet ( ) ;
rangeSet - > setRange ( frame , lastFrame ) ;
if ( frame = = 0 ) {
// this code should be moved elsewhere, possibly in the stageobject implementation
// the idea is to remove the normal
TStageObject * rootObj = skeleton . getRootBone ( ) - > getStageObject ( ) ;
rootObj - > setStatus ( TStageObject : : XY ) ;
placement = rootObj - > getPlacement ( 0 ) . inv ( ) * placement ;
rootObj - > setStatus ( TStageObject : : IK ) ;
rangeSet - > setPlacement ( placement ) ;
rootObj - > invalidate ( ) ;
}
undo - > setNewRange ( bone - > getColumnIndex ( ) , frame , lastFrame , rangeSet - > getPlacement ( ) ) ;
}
}
undo - > setNewTemp ( m_temporaryPinnedColumns ) ;
TUndoManager : : manager ( ) - > add ( undo ) ;
}
//-------------------------------------------------------------------
void SkeletonTool : : drawSkeleton ( const Skeleton & skeleton , int row )
{
bool buildingSkeleton = m_mode . getValue ( ) = = BUILD_SKELETON ;
bool ikEnabled = m_mode . getValue ( ) = = INVERSE_KINEMATICS ;
TXsheet * xsh = getXsheet ( ) ;
std : : vector < int > showBoneIndex ;
int i ;
for ( i = 0 ; i < skeleton . getBoneCount ( ) ; i + + ) {
Skeleton : : Bone * bone = skeleton . getBone ( i ) ;
TStageObjectId id = bone - > getStageObject ( ) - > getId ( ) ;
bool canShow = canShowBone ( bone , xsh , row ) ;
if ( ! canShow )
continue ;
showBoneIndex . push_back ( i ) ;
}
bool changingParent = dynamic_cast < ParentChangeTool * > ( m_dragTool ) ! = 0 ;
TStageObjectId currentObjectId = TTool : : getApplication ( ) - > getCurrentObject ( ) - > getObjectId ( ) ;
2016-04-19 19:32:17 +12:00
std : : string currentHandle = xsh - > getStageObject ( currentObjectId ) - > getHandle ( ) ;
2016-03-19 06:57:51 +13:00
for ( i = 0 ; i < ( int ) showBoneIndex . size ( ) ; i + + ) {
Skeleton : : Bone * bone = skeleton . getBone ( showBoneIndex [ i ] ) ;
TStageObjectId id = bone - > getStageObject ( ) - > getId ( ) ;
bool isCurrent = id = = currentObjectId ;
if ( isCurrent & & buildingSkeleton & & m_parentProbeEnabled ) {
if ( ! m_magicLinks . empty ( ) ) {
drawBone ( bone - > getCenter ( ) , m_magicLinks [ 0 ] . m_h1 . m_pos , false ) ;
}
drawBone ( bone - > getCenter ( ) , m_parentProbe , true ) ;
} else if ( ikEnabled ) {
if ( bone - > getParent ( ) )
drawIKBone ( bone - > getCenter ( ) , bone - > getParent ( ) - > getCenter ( ) ) ;
} else if ( bone - > getParent ( ) | | isCurrent ) {
double pixelSize = getPixelSize ( ) ;
TPointD a = bone - > getCenter ( ) ;
TPointD b , pm ;
if ( bone - > getParent ( ) ) {
b = bone - > getParent ( ) - > getCenter ( ) ;
pm = ( a + b ) * 0.5 ;
} else {
pm = b = a + TPointD ( 0 , 60 ) * pixelSize ;
}
bool boneIsVisible = false ;
if ( buildingSkeleton ) {
boneIsVisible = true ;
if ( bone - > isSelected ( ) )
drawBone ( a , b , true ) ;
else if ( ! m_showOnlyActiveSkeleton . getValue ( ) )
drawBone ( a , b , false ) ;
else
boneIsVisible = false ;
}
if ( boneIsVisible & & isCurrent ) {
// draw change parent gadget
double r = pixelSize * 5 ;
if ( isPicking ( ) ) {
// int code = TD_ResetParent + bone->getStageObject()->getId().getIndex();
glPushName ( TD_ChangeParent ) ;
tglDrawDisk ( pm , r ) ;
glPopName ( ) ;
} else {
if ( m_device = = TD_ChangeParent ) {
glColor4d ( 0.47 * alpha , 0.6 * alpha , 0.65 * alpha , alpha ) ;
r * = 1.5 ;
} else
glColor4d ( 0.37 * alpha , 0.5 * alpha , 0.55 * alpha , alpha ) ;
glRectd ( pm . x - r , pm . y - r , pm . x + r , pm . y + r ) ;
glColor3d ( 0 , 0 , 0 ) ;
tglDrawRect ( pm . x - r , pm . y - r , pm . x + r , pm . y + r ) ;
}
}
}
}
for ( i = 0 ; i < ( int ) showBoneIndex . size ( ) ; i + + ) {
Skeleton : : Bone * bone = skeleton . getBone ( showBoneIndex [ i ] ) ;
if ( ! m_showOnlyActiveSkeleton . getValue ( ) | | bone - > isSelected ( ) )
drawJoint ( bone - > getCenter ( ) ,
currentObjectId = = bone - > getStageObject ( ) - > getId ( ) & &
currentHandle . find ( " H " ) ! = 0 ) ;
}
}
//-------------------------------------------------------------------
void SkeletonTool : : getImageBoundingBox ( TRectD & bbox , TAffine & aff , int frame , int columnIndex )
{
TAffine columnAff = getXsheet ( ) - > getPlacement ( TStageObjectId : : ColumnId ( columnIndex ) , frame ) ;
// TAffine affine = getColumnMatrix(columnIndex);
TXshCell cell = getXsheet ( ) - > getCell ( frame , columnIndex ) ;
TImageP image = cell . getImage ( false ) ;
TToonzImageP ti = image ;
TVectorImageP vi = image ;
if ( ti ) {
TAffine imageDpiAff ;
if ( cell . m_level - > getSimpleLevel ( ) )
imageDpiAff = getDpiAffine ( cell . m_level - > getSimpleLevel ( ) , cell . m_frameId , true ) ;
aff = columnAff * imageDpiAff ;
bbox = ToonzImageUtils : : convertRasterToWorld ( convert ( ti - > getBBox ( ) ) , ti ) * ti - > getSubsampling ( ) ;
ToolUtils : : drawRect ( bbox * ti - > getSubsampling ( ) , TPixel32 ( 200 , 200 , 200 ) , 0x5555 ) ;
} else if ( vi ) {
bbox = vi - > getBBox ( ) ;
aff = columnAff ;
} else {
bbox = TRectD ( ) ;
aff = TAffine ( ) ;
}
}
//-------------------------------------------------------------------
void SkeletonTool : : drawLevelBoundingBox ( int frame , int columnIndex )
{
TAffine affine = getCurrentColumnMatrix ( ) ;
TXshCell cell = getXsheet ( ) - > getCell ( frame , columnIndex ) ;
TImageP image = cell . getImage ( false ) ;
TToonzImageP ti = image ;
TVectorImageP vi = image ;
glPushMatrix ( ) ;
if ( affine ! = getMatrix ( ) )
tglMultMatrix ( getMatrix ( ) . inv ( ) * affine ) ;
if ( ti ) {
TPointD dpiScale = getViewer ( ) - > getDpiScale ( ) ;
glScaled ( dpiScale . x , dpiScale . y , 1 ) ;
TRectD bbox = ToonzImageUtils : : convertRasterToWorld ( convert ( ti - > getBBox ( ) ) , ti ) ;
ToolUtils : : drawRect ( bbox * ti - > getSubsampling ( ) , TPixel32 ( 200 , 200 , 200 ) , 0x5555 ) ;
}
if ( vi ) {
TRectD bbox = vi - > getBBox ( ) ;
ToolUtils : : drawRect ( bbox , TPixel32 ( 200 , 200 , 200 ) , 0x5555 ) ;
}
glPopMatrix ( ) ;
}
//-------------------------------------------------------------------
void SkeletonTool : : drawIKJoint ( const Skeleton : : Bone * bone )
{
TPointD pos = bone - > getCenter ( ) ;
const double r0 = 6 * getPixelSize ( ) , r1 = r0 / 3 ;
int code = TD_LockStageObject + bone - > getColumnIndex ( ) ;
glPushName ( code ) ;
glColor3d ( 0.8 , 0.5 , 0.05 ) ;
if ( bone - > getPinnedStatus ( ) ! = Skeleton : : Bone : : FREE ) {
if ( bone - > getPinnedStatus ( ) = = Skeleton : : Bone : : TEMP_PINNED ) {
double r1 = r0 * 0.60 ;
glColor3d ( 60.0 / 255.0 , 250.0 / 255.0 , 1.0 ) ;
glRectd ( pos . x - r0 , pos . y - r0 , pos . x + r0 , pos . y + r0 ) ;
glColor3d ( 0.78 , 0.62 , 0 ) ;
glRectd ( pos . x - r1 , pos . y - r1 , pos . x + r1 , pos . y + r1 ) ;
glColor3d ( 0.2 , 0.1 , 0.05 ) ;
tglDrawRect ( pos . x - r0 , pos . y - r0 , pos . x + r0 , pos . y + r0 ) ;
tglDrawRect ( pos . x - r1 , pos . y - r1 , pos . x + r1 , pos . y + r1 ) ;
} else {
glColor3d ( 0 , 175.0 / 255.0 , 1.0 ) ;
glRectd ( pos . x - r0 , pos . y - r0 , pos . x + r0 , pos . y + r0 ) ;
glColor3d ( 0.2 , 0.1 , 0.05 ) ;
tglDrawRect ( pos . x - r0 , pos . y - r0 , pos . x + r0 , pos . y + r0 ) ;
}
} else {
if ( bone - > isSelected ( ) )
glColor3d ( 1 , 0.78 , 0.19 ) ;
else
glColor3d ( 0.78 , 0.62 , 0 ) ;
tglDrawDisk ( pos , r0 ) ;
glColor3d ( 0.2 , 0.1 , 0.05 ) ;
tglDrawCircle ( pos , r0 ) ;
}
if ( m_device = = code ) {
glColor3d ( 0.9 , 0.1 , 0.1 ) ;
tglFillRect ( pos . x - r1 , pos . y - r1 , pos . x + r1 , pos . y + r1 ) ;
} else {
glColor3d ( 0.2 , 0.1 , 0.05 ) ;
const double r3 = 2 * getPixelSize ( ) ;
tglDrawCircle ( pos , r3 ) ;
}
glPopName ( ) ;
}
//-------------------------------------------------------------------
void SkeletonTool : : drawJoint ( const TPointD & pos , bool current )
{
const double alpha = 0.8 , ialpha = 1 - alpha ;
double r0 = 4 * getPixelSize ( ) ;
if ( current ) {
glPushName ( TD_Center ) ;
if ( m_device = = TD_Center ) {
glColor4d ( 0.9 * alpha , 0.8 * alpha , 0.2 * alpha , alpha ) ;
r0 * = 1.5 ;
} else {
glColor4d ( ( ( 255.0 / 255.0 ) - ialpha ) / alpha , ( ( 200.0 / 255.0 ) - ialpha ) / alpha , ( ( 48.0 / 255.0 ) - ialpha ) / alpha , alpha ) ;
}
tglDrawDisk ( pos , r0 ) ;
glColor3d ( 0.2 , 0.1 , 0.05 ) ;
tglDrawCircle ( pos , r0 ) ;
glPopName ( ) ;
} else {
// in build skeleton center is clickable, but only the current one
if ( m_mode . getValue ( ) = = BUILD_SKELETON )
glColor4d ( 0.60 * alpha , 0.60 * alpha , 0.60 * alpha , alpha ) ;
else
glColor4d ( 0.78 * alpha , 0.62 * alpha , 0 * alpha , alpha ) ;
tglDrawDisk ( pos , r0 ) ;
glColor3d ( 0.2 , 0.1 , 0.05 ) ;
tglDrawCircle ( pos , r0 ) ;
}
}
//-------------------------------------------------------------------
void SkeletonTool : : drawBone ( const TPointD & a , const TPointD & b , bool selected )
{
const double alpha = 0.8 ;
// se sono troppo vicini niente da fare
TPointD delta = b - a ;
if ( norm2 ( delta ) < 0.001 )
return ;
TPointD u = getPixelSize ( ) * 2.5 * normalize ( rotate90 ( delta ) ) ;
if ( selected )
glColor4d ( 0.9 * alpha , 0.9 * alpha , 0.9 * alpha , alpha ) ;
else
glColor4d ( 0.58 * alpha , 0.58 * alpha , 0.58 * alpha , alpha ) ;
glBegin ( GL_POLYGON ) ;
tglVertex ( a + u ) ;
tglVertex ( b ) ;
tglVertex ( a - u ) ;
glEnd ( ) ;
glColor3d ( 0.2 , 0.3 , 0.35 ) ;
glBegin ( GL_LINE_STRIP ) ;
tglVertex ( a + u ) ;
tglVertex ( b ) ;
tglVertex ( a - u ) ;
glEnd ( ) ;
}
//-------------------------------------------------------------------
void SkeletonTool : : drawIKBone ( const TPointD & a , const TPointD & b )
{
// se sono troppo vicini niente da fare
TPointD delta = b - a ;
if ( norm2 ( delta ) < 0.001 )
return ;
TPointD u = getPixelSize ( ) * 2.5 * normalize ( rotate90 ( delta ) ) ;
glColor3d ( 0.58 , 0.58 , 0.58 ) ;
glBegin ( GL_POLYGON ) ;
tglVertex ( a + u ) ;
tglVertex ( b + u ) ;
tglVertex ( b - u ) ;
tglVertex ( a - u ) ;
glEnd ( ) ;
glColor3d ( 0.2 , 0.3 , 0.35 ) ;
glBegin ( GL_LINES ) ;
tglVertex ( a + u ) ;
tglVertex ( b + u ) ;
tglVertex ( a - u ) ;
tglVertex ( b - u ) ;
glEnd ( ) ;
}
//-------------------------------------------------------------------
void SkeletonTool : : computeMagicLinks ( )
{
//TODO: spostare qui il calcolo dei magic link
}
//-------------------------------------------------------------------
void SkeletonTool : : drawHooks ( )
{
// camera stand reference system
//glColor3d(0,0,1);
//tglDrawRect(3,3,97,97);
//glColor3d(0,1,1);
//tglDrawRect(0,100,Stage::inch,110);
QTime time ;
time . start ( ) ;
m_magicLinks . clear ( ) ;
computeMagicLinks ( ) ;
TTool : : Application * app = TTool : : getApplication ( ) ;
TXsheet * xsh = app - > getCurrentXsheet ( ) - > getXsheet ( ) ;
int row = app - > getCurrentFrame ( ) - > getFrame ( ) ;
int col = app - > getCurrentColumn ( ) - > getColumnIndex ( ) ;
TPointD dpiScale = getViewer ( ) - > getDpiScale ( ) ;
// glColor3d(1,0,1);
// tglDrawRect(-100*dpiScale.x, -100*dpiScale.y, 0,0);
// I should not show hooks of columns already connected with the current one
// ("linking" to those hooks would create evil loops in the hierarchy)
std : : set < int > connectedColumns ;
getConnectedColumns ( connectedColumns , xsh , col ) ;
std : : vector < HookData > currentColumnHooks ;
std : : vector < HookData > otherColumnsHooks ;
// fill currentColumnHooks
// detect otherColumn (i.e. the active column during a click&drag operator
int otherColumn = - 1 ;
if ( m_parentProbeEnabled ) {
// qDebug(" parent probe enabled");
// currentColumnHooks <- current column & current handle
int hookId = 0 ;
std : : string handle = xsh - > getStageObject ( TStageObjectId : : ColumnId ( col ) ) - > getHandle ( ) ;
if ( handle . find ( " H " ) = = 0 ) {
int j = 1 ;
while ( j < ( int ) handle . size ( ) & & ' 0 ' < = handle [ j ] & & handle [ j ] < = ' 9 ' ) {
hookId = hookId * 10 + ( int ) handle [ j ] - ' 0 ' ;
j + + ;
}
}
currentColumnHooks . push_back ( HookData ( xsh , col , hookId , m_parentProbe ) ) ;
// otherColumn = "picked" column not connected
TPoint parentProbePos = getViewer ( ) - > worldToPos ( m_parentProbe ) ;
std : : vector < int > indexes ;
getViewer ( ) - > posToColumnIndexes ( parentProbePos , indexes , getPixelSize ( ) * 10 , false ) ;
for ( int i = ( int ) indexes . size ( ) - 1 ; i > = 0 ; i - - ) {
if ( connectedColumns . count ( indexes [ i ] ) = = 0 ) {
otherColumn = indexes [ i ] ;
break ;
}
}
// if the mouse is not on a stroke, I'm using the "old" m_otherColumn, if any.
// (this is needed because of the hooks put inside of unfilled regions)
if ( otherColumn < 0 & & m_otherColumn > = 0 ) {
if ( m_otherColumnBBox . contains ( m_otherColumnBBoxAff . inv ( ) * m_parentProbe ) )
otherColumn = m_otherColumn ;
else
m_otherColumn = - 1 ;
}
} else {
// parent probe not enabled: get all hooks of current column. other column = -1
getHooks ( currentColumnHooks , xsh , row , col , TPointD ( 1 , 1 ) ) ; // dpiScale);
}
// other columns hooks <- all hooks of all unlinked columns
for ( int i = 0 ; i < xsh - > getColumnCount ( ) ; i + + )
if ( xsh - > getColumn ( i ) - > isCamstandVisible ( ) )
if ( connectedColumns . count ( i ) = = 0 )
getHooks ( otherColumnsHooks , xsh , row , i , TPointD ( 1 , 1 ) ) ; // dpiScale);
/*
qDebug ( " time=%dms " , time . elapsed ( ) ) ;
qDebug ( " %d hooks (current column) " , currentColumnHooks . size ( ) ) ;
for ( int i = 0 ; i < ( int ) currentColumnHooks . size ( ) ; i + + )
qDebug ( " %d,%d " , currentColumnHooks [ i ] . m_columnIndex , currentColumnHooks [ i ] . m_hookId ) ;
qDebug ( " %d hooks (other columns) " , otherColumnsHooks . size ( ) ) ;
for ( int i = 0 ; i < ( int ) otherColumnsHooks . size ( ) ; i + + )
qDebug ( " %d,%d " , otherColumnsHooks [ i ] . m_columnIndex , otherColumnsHooks [ i ] . m_hookId ) ;
*/
std : : vector < TRectD > balloons ;
// draw current column hooks
for ( int i = 0 ; i < ( int ) currentColumnHooks . size ( ) ; i + + ) {
const HookData & hook = currentColumnHooks [ i ] ;
if ( hook . m_name = = " " )
continue ; // should not happen
int code = TD_Hook + hook . m_hookId ;
TPointD pos = hook . m_pos ;
ToolUtils : : drawHook ( pos , ToolUtils : : OtherLevelHook ) ;
glPushName ( code ) ;
TPixel32 color ( 200 , 220 , 205 , 200 ) ;
if ( hook . m_isPivot )
color = TPixel32 ( 200 , 200 , 10 , 200 ) ;
else if ( code = = m_device )
color = TPixel32 ( 185 , 255 , 255 ) ;
ToolUtils : : drawBalloon ( pos , hook . m_name , color , TPoint ( 20 , 20 ) , isPicking ( ) , & balloons ) ;
glPopName ( ) ;
}
if ( m_parentProbeEnabled ) {
for ( int i = 0 ; i < ( int ) otherColumnsHooks . size ( ) ; i + + )
ToolUtils : : drawHook ( otherColumnsHooks [ i ] . m_pos , ToolUtils : : OtherLevelHook ) ;
}
// search for magic links
double minDist2 = 0 ;
double snapRadius2 = 100 * getPixelSize ( ) * getPixelSize ( ) ;
double snapRadius2bis = 100 ;
if ( ! m_parentProbeEnabled ) {
// "static" magic links: no parent probe
for ( int i = 0 ; i < ( int ) currentColumnHooks . size ( ) ; i + + ) {
for ( int j = 0 ; j < ( int ) otherColumnsHooks . size ( ) ; j + + ) {
double dist2 = norm2 ( currentColumnHooks [ i ] . m_pos - otherColumnsHooks [ j ] . m_pos ) ;
if ( currentColumnHooks [ i ] . m_hookId = = 0 | | otherColumnsHooks [ j ] . m_hookId = = 0 )
continue ;
if ( dist2 < snapRadius2bis ) {
m_magicLinks . push_back ( MagicLink ( currentColumnHooks [ i ] , otherColumnsHooks [ j ] , dist2 ) ) ;
qDebug ( " magic link_a %d (%d,%d) %d (%d,%d); dist=%f " ,
i ,
currentColumnHooks [ i ] . m_columnIndex ,
currentColumnHooks [ i ] . m_hookId ,
j ,
otherColumnsHooks [ j ] . m_columnIndex ,
otherColumnsHooks [ j ] . m_hookId ,
dist2 ) ;
}
}
}
}
if ( m_parentProbeEnabled ) {
// search for the closest hook of the picked column
int i = - 1 , j = - 1 ;
double minDist2 = snapRadius2 ;
for ( i = 0 ; i < ( int ) otherColumnsHooks . size ( ) ; i + + ) {
double dist2 = tdistance2 ( otherColumnsHooks [ i ] . m_pos , m_parentProbe ) ;
if ( dist2 < minDist2 ) {
j = i ;
minDist2 = dist2 ;
otherColumn = otherColumnsHooks [ i ] . m_columnIndex ;
}
}
}
if ( m_parentProbeEnabled & & otherColumn > = 0 ) // && m_magicLinks.empty()
{
// "dynamic" magic links: probing and picking a column
// show image bounding box
m_otherColumn = otherColumn ;
getImageBoundingBox ( m_otherColumnBBox , m_otherColumnBBoxAff , row , otherColumn ) ;
if ( ! m_otherColumnBBox . isEmpty ( ) ) {
glPushMatrix ( ) ;
tglMultMatrix ( m_otherColumnBBoxAff ) ;
ToolUtils : : drawRect ( m_otherColumnBBox , TPixel32 ( 188 , 202 , 191 ) , 0xF0F0 ) ;
//tglDrawRect(img->getBBox());
glPopMatrix ( ) ;
}
/*
TXshCell cell = xsh - > getCell ( row , otherColumn ) ;
//TAffine aff = xsh->getPlacement(TStageObjectId::ColumnId(otherColumn),row);
//m_otherColumnAff = aff;
TImageP img = cell . getImage ( false ) ;
if ( img )
{
getImageBoundingBox ( m_otherColumnBBox , m_otherColumnBBoxAff , row , otherColumn ) ;
//glColor3d(188.0/255.0, 202.0/255.0, 191.0/255.0);
glPushMatrix ( ) ;
tglMultMatrix ( aff * imageDpiAff ) ;
ToolUtils : : drawRect ( img - > getBBox ( ) , TPixel32 ( 188 , 202 , 191 ) , 0xF0F0 ) ;
//tglDrawRect(img->getBBox());
glPopMatrix ( ) ;
}
*/
// search for the closest hook of the picked column
int i = - 1 , j = - 1 ;
double minDist2 = snapRadius2 ;
for ( i = 0 ; i < ( int ) otherColumnsHooks . size ( ) ; i + + )
if ( otherColumnsHooks [ i ] . m_columnIndex = = otherColumn ) {
double dist2 = tdistance2 ( otherColumnsHooks [ i ] . m_pos , m_parentProbe ) ;
if ( j < 0 )
j = i ;
else if ( dist2 < minDist2 | | otherColumnsHooks [ i ] . m_hookId = = 0 ) {
j = i ;
minDist2 = dist2 ;
}
}
// visualize a balloon for the closest hook
if ( 0 < = j & & j < ( int ) otherColumnsHooks . size ( ) ) {
// I want to get a specific color when overlaying the label on white
int alfa = 100 , ialfa = 255 - alfa ;
TPixel32 color ( 255 * ( 188 - ialfa ) / alfa , 255 * ( 202 - ialfa ) / alfa , 255 * ( 191 - ialfa ) / alfa , alfa ) ;
ToolUtils : : drawBalloon (
otherColumnsHooks [ j ] . m_pos ,
otherColumnsHooks [ j ] . m_name , // getHandle(),
color ,
TPoint ( 20 , 20 ) ,
false ,
& balloons ) ;
HookData baseHook = currentColumnHooks [ 0 ] ;
baseHook . m_pos = otherColumnsHooks [ j ] . m_pos ;
// this is also a magic link
m_magicLinks . push_back ( MagicLink ( baseHook , otherColumnsHooks [ j ] , 10000 ) ) ;
}
}
// visualize all the magic links
for ( int i = 0 ; i < ( int ) m_magicLinks . size ( ) ; i + + ) {
const MagicLink & magicLink = m_magicLinks [ i ] ;
const HookData & h1 = magicLink . m_h1 ;
std : : string name ;
name = ( m_parentProbeEnabled ? " Linking " : " Link " ) + removeTrailingH ( magicLink . m_h0 . getHandle ( ) ) +
" to Col " + toString ( h1 . m_columnIndex + 1 ) + " / " + removeTrailingH ( h1 . getHandle ( ) ) ;
int code = TD_MagicLink + i ;
glPushName ( code ) ;
TPixel32 color ( 100 , 255 , 100 , 100 ) ;
if ( code = = m_device )
color = TPixel32 ( 185 , 255 , 255 ) ;
ToolUtils : : drawBalloon ( magicLink . m_h0 . m_pos , name , color , TPoint ( 20 , - 20 ) , isPicking ( ) , & balloons ) ;
glPopName ( ) ;
}
}
//-------------------------------------------------------------------
void SkeletonTool : : drawDrawingBrowser ( const TXshCell & cell , const TPointD & center )
{
if ( ! cell . m_level | | cell . m_level - > getFrameCount ( ) < = 1 )
return ;
double pixelSize = getPixelSize ( ) ;
2016-04-19 19:32:17 +12:00
std : : string name = toString ( cell . m_level - > getName ( ) ) + " . " + toString ( cell . m_frameId . getNumber ( ) ) ;
2016-03-19 06:57:51 +13:00
QString qText = QString : : fromStdString ( name ) ;
QFont font ( " Arial " , 10 ) ; // ,QFont::Bold);
QFontMetrics fm ( font ) ;
QSize textSize = fm . boundingRect ( qText ) . size ( ) ;
int arrowHeight = 10 ;
int minTextWidth = 2 * arrowHeight + 5 ;
if ( textSize . width ( ) < minTextWidth )
textSize . setWidth ( minTextWidth ) ;
QSize totalSize ( textSize . width ( ) , textSize . height ( ) + 2 * arrowHeight ) ;
TPointD p = center + TPointD ( 30 , - arrowHeight ) * pixelSize ;
QRect textRect ( 0 , arrowHeight , textSize . width ( ) , textSize . height ( ) ) ;
assert ( glGetError ( ) = = 0 ) ;
if ( isPicking ( ) ) {
double x0 = p . x , x1 = p . x + totalSize . width ( ) * pixelSize ;
double y0 = p . y , y3 = p . y + totalSize . height ( ) * pixelSize ;
double y1 = y0 + arrowHeight * pixelSize ;
double y2 = y3 - arrowHeight * pixelSize ;
double x = ( x0 + x1 ) * 0.5 ;
double d = arrowHeight * pixelSize ;
glColor3d ( 0 , 1 , 0 ) ;
glPushName ( TD_ChangeDrawing ) ;
glRectd ( x0 , y1 , x1 , y2 ) ;
glPopName ( ) ;
glPushName ( TD_IncrementDrawing ) ;
glBegin ( GL_POLYGON ) ;
glVertex2d ( x , y0 ) ;
glVertex2d ( x + d , y0 + d ) ;
glVertex2d ( x - d , y0 + d ) ;
glEnd ( ) ;
glPopName ( ) ;
glPushName ( TD_DecrementDrawing ) ;
glBegin ( GL_POLYGON ) ;
glVertex2d ( x , y3 ) ;
glVertex2d ( x + d , y3 - d ) ;
glVertex2d ( x - d , y3 - d ) ;
glEnd ( ) ;
glPopName ( ) ;
return ;
} else {
assert ( glGetError ( ) = = 0 ) ;
bool active = m_device = = TD_ChangeDrawing | | m_device = = TD_IncrementDrawing | | m_device = = TD_DecrementDrawing ;
QImage img ( totalSize . width ( ) , totalSize . height ( ) , QImage : : Format_ARGB32 ) ;
img . fill ( Qt : : transparent ) ;
QPainter imgPainter ( & img ) ;
imgPainter . setRenderHints ( QPainter : : Antialiasing | QPainter : : TextAntialiasing ) ;
//imgPainter.setPen(Qt::black);
//imgPainter.drawRect(0,0,totalSize.width(),totalSize.height());
imgPainter . setPen ( Qt : : NoPen ) ;
imgPainter . setBrush ( QColor ( 200 , 200 , 200 , 200 ) ) ;
imgPainter . drawRect ( textRect ) ;
imgPainter . setPen ( active ? Qt : : red : Qt : : black ) ;
imgPainter . setBrush ( Qt : : NoBrush ) ;
imgPainter . setFont ( font ) ;
imgPainter . drawText ( textRect , Qt : : AlignCenter , qText ) ;
if ( active ) {
int x = textRect . center ( ) . x ( ) ;
int d = arrowHeight - 4 ;
int y = 0 ;
QPainterPath upArrow ;
upArrow . moveTo ( x , y ) ;
upArrow . lineTo ( x + d , y + d ) ;
upArrow . lineTo ( x - d , y + d ) ;
upArrow . lineTo ( x , y ) ;
y = totalSize . height ( ) - 1 ;
QPainterPath dnArrow ;
dnArrow . moveTo ( x , y ) ;
dnArrow . lineTo ( x + d , y - d ) ;
dnArrow . lineTo ( x - d , y - d ) ;
dnArrow . lineTo ( x , y ) ;
imgPainter . setPen ( Qt : : NoPen ) ;
imgPainter . setBrush ( m_device = = TD_DecrementDrawing ? QColor ( 255 , 0 , 0 ) : QColor ( 200 , 100 , 100 ) ) ;
imgPainter . drawPath ( upArrow ) ;
imgPainter . setBrush ( m_device = = TD_IncrementDrawing ? QColor ( 255 , 0 , 0 ) : QColor ( 200 , 100 , 100 ) ) ;
imgPainter . drawPath ( dnArrow ) ;
}
QImage texture = QGLWidget : : convertToGLFormat ( img ) ;
glRasterPos2f ( p . x , p . y ) ;
// glBitmap(0,0,0,0, 0,-size.height()+(y+delta.y), NULL); //
glEnable ( GL_BLEND ) ;
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
glDrawPixels ( texture . width ( ) , texture . height ( ) , GL_RGBA , GL_UNSIGNED_BYTE , texture . bits ( ) ) ;
glDisable ( GL_BLEND ) ;
glColor3d ( 0 , 0 , 0 ) ;
assert ( glGetError ( ) = = 0 ) ;
}
}
//-------------------------------------------------------------------
void SkeletonTool : : drawMainGadget ( const TPointD & center )
{
assert ( glGetError ( ) = = GL_NO_ERROR ) ;
double r = 10 * getPixelSize ( ) ;
double cx = center . x + r * 1.1 ;
double cy = center . y - r * 1.1 ;
glColor3d ( 1 , 0 , 0 ) ;
if ( isPicking ( ) ) {
glPushName ( TD_Translation ) ;
tglDrawDisk ( TPointD ( cx , cy ) , getPixelSize ( ) * 9 ) ;
glPopName ( ) ;
return ;
}
QImage img ( 19 , 19 , QImage : : Format_ARGB32 ) ;
img . fill ( Qt : : transparent ) ;
QPainter p ( & img ) ;
// p.setRenderHints(QPainter::Antialiasing|QPainter::TextAntialiasing);
QPainterPath pp ;
int dx = 1 , dy = 0 ;
for ( int i = 0 ; i < 4 ; i + + ) {
int x = 9 + dx * 8 ;
int y = 9 + dy * 8 ;
pp . moveTo ( 9 , 9 ) ;
pp . lineTo ( x , y ) ;
pp . lineTo ( x - 2 * dx - 2 * dy , y - 2 * dy + 2 * dx ) ;
pp . moveTo ( x , y ) ;
pp . lineTo ( x - 2 * dx + 2 * dy , y - 2 * dy - 2 * dx ) ;
int d = dx ;
dx = - dy ;
dy = d ;
}
p . setPen ( QPen ( Qt : : white , 3 ) ) ;
p . drawPath ( pp ) ;
p . setPen ( Qt : : black ) ;
p . drawPath ( pp ) ;
p . setBrush ( QColor ( 54 , 213 , 54 ) ) ;
p . drawRect ( 6 , 6 , 6 , 6 ) ;
QImage texture = QGLWidget : : convertToGLFormat ( img ) ;
// texture.save("c:\\urka.png");
glRasterPos2f ( center . x + r * 1.1 , center . y - r * 1.1 ) ;
glBitmap ( 0 , 0 , 0 , 0 , - 9 , - 9 , NULL ) ;
glEnable ( GL_BLEND ) ;
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
glDrawPixels ( texture . width ( ) , texture . height ( ) , GL_RGBA , GL_UNSIGNED_BYTE , texture . bits ( ) ) ;
glDisable ( GL_BLEND ) ;
glColor3d ( 0 , 0 , 0 ) ;
assert ( glGetError ( ) = = GL_NO_ERROR ) ;
}
//-------------------------------------------------------------------
void SkeletonTool : : draw ( )
{
// parent object reference system
//glColor3d(1,0,0);
//tglDrawRect(0,0,100,100);
if ( m_label ! = " " )
ToolUtils : : drawBalloon ( m_labelPos , m_label , TPixel32 : : Red , TPoint ( 20 , - 20 ) , false ) ;
bool ikEnabled = m_mode . getValue ( ) = = INVERSE_KINEMATICS ;
assert ( glGetError ( ) = = GL_NO_ERROR ) ;
// l'xsheet, oggetto (e relativo placement), frame corrente
TTool : : Application * app = TTool : : getApplication ( ) ;
TXsheet * xsh = getXsheet ( ) ;
assert ( xsh ) ;
TStageObjectId objId = app - > getCurrentObject ( ) - > getObjectId ( ) ;
// se l'oggetto corrente non e' una colonna non disegno nulla
if ( ! objId . isColumn ( ) )
return ;
TStageObject * pegbar = xsh - > getStageObject ( objId ) ;
int col = objId . getIndex ( ) ;
int frame = app - > getCurrentFrame ( ) - > getFrame ( ) ;
if ( m_currentFrame ! = frame )
m_temporaryPinnedColumns . clear ( ) ;
TAffine aff = getMatrix ( ) ;
// puo' suggere che il placement degeneri (es.: c'e' uno h-scale = 0%)
if ( fabs ( aff . det ( ) ) < 0.00001 )
return ;
// m_unit = getPixelSize() * sqrt(fabs(aff.det()));
if ( ! ikEnabled )
drawLevelBoundingBox ( frame , col ) ;
glPushMatrix ( ) ;
tglMultMatrix ( aff . inv ( ) ) ;
// camera stand reference system
//glColor3d(0,1,0);
//tglDrawRect(0,0,100,100);
bool changingParent = dynamic_cast < ParentChangeTool * > ( m_dragTool ) ! = 0 ;
// !changingParent &&
if ( m_mode . getValue ( ) = = BUILD_SKELETON & & ! xsh - > getStageObjectParent ( objId ) . isColumn ( ) ) {
if ( ! changingParent )
drawHooks ( ) ;
}
Skeleton skeleton ;
buildSkeleton ( skeleton , col ) ;
glEnable ( GL_BLEND ) ;
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
drawSkeleton ( skeleton , frame ) ;
glDisable ( GL_BLEND ) ;
TXshCell cell = xsh - > getCell ( frame , objId . getIndex ( ) ) ;
Skeleton : : Bone * rootBone = skeleton . getRootBone ( ) ;
for ( int i = 0 ; i < skeleton . getBoneCount ( ) ; i + + ) {
Skeleton : : Bone * bone = skeleton . getBone ( i ) ;
TStageObjectId currentId = bone - > getStageObject ( ) - > getId ( ) ;
bool isCurrent = ( currentId = = objId ) ;
TPointD pos = bone - > getCenter ( ) ;
if ( isCurrent & & m_mode . getValue ( ) ! = BUILD_SKELETON ) {
drawDrawingBrowser ( cell , pos ) ;
}
bool isActiveChain = bone - > isSelected ( ) ;
glColor3d ( 0 , 1 , 0 ) ;
if ( ikEnabled ) {
drawIKJoint ( bone ) ;
} else {
TPointD pos = bone - > getCenter ( ) ;
if ( isCurrent & & m_mode . getValue ( ) = = ANIMATE ) {
drawMainGadget ( pos ) ;
}
}
}
m_currentFrame = frame ;
if ( m_dragTool )
m_dragTool - > draw ( ) ;
glPopMatrix ( ) ;
}
//===================================================================
void SkeletonTool : : onActivate ( )
{
TTool : : Application * app = TTool : : getApplication ( ) ;
if ( m_firstTime ) {
m_globalKeyframes . setValue ( SkeletonGlobalKeyFrame ? 1 : 0 ) ;
m_mode . setValue ( BUILD_SKELETON ) ;
// m_ikEnabled.setValue(SkeletonInverseKinematics ? 1 : 0);
m_firstTime = false ;
}
TStageObjectId objId = app - > getCurrentObject ( ) - > getObjectId ( ) ;
if ( objId = = TStageObjectId : : NoneId ) {
int index = app - > getCurrentColumn ( ) - > getColumnIndex ( ) ;
objId = TStageObjectId : : ColumnId ( index ) ;
}
// app->editStageObject(objId);
}
//===================================================================
void SkeletonTool : : onDeactivate ( )
{
//m_selection.selectNone();
//TSelection::setCurrent(0);
}
//-------------------------------------------------------------------
SkeletonSubtools : : MagicLink SkeletonTool : : getMagicLink ( int index ) const
{
assert ( 0 < = index & & index < ( int ) m_magicLinks . size ( ) ) ;
return m_magicLinks [ index ] ;
}
//-------------------------------------------------------------------
void SkeletonTool : : magicLink ( int index )
{
if ( index < 0 | | index > = ( int ) m_magicLinks . size ( ) )
return ;
HookData h0 = m_magicLinks [ index ] . m_h0 ;
HookData h1 = m_magicLinks [ index ] . m_h1 ;
TTool : : Application * app = TTool : : getApplication ( ) ;
TXsheet * xsh = app - > getCurrentXsheet ( ) - > getXsheet ( ) ;
int columnIndex = app - > getCurrentColumn ( ) - > getColumnIndex ( ) ;
TStageObjectId id = TStageObjectId : : ColumnId ( columnIndex ) ;
TStageObject * obj = xsh - > getStageObject ( id ) ;
int parentColumnIndex = h1 . m_columnIndex ;
TStageObjectId parentId = TStageObjectId : : ColumnId ( parentColumnIndex ) ;
std : : string parentHandle = h1 . getHandle ( ) ;
std : : string handle = " " ;
if ( h0 . m_columnIndex < 0 ) {
handle = obj - > getHandle ( ) ;
} else {
handle = h0 . getHandle ( ) ;
}
//TUndoManager *undoManager = TUndoManager::manager();
//undoManager->beginBlock();
TStageObjectCmd : : setHandle ( id , handle , app - > getCurrentXsheet ( ) ) ;
TStageObjectCmd : : setParent ( id , parentId , parentHandle , app - > getCurrentXsheet ( ) ) ;
//undoManager->endBlock();
}
//-------------------------------------------------------------------
int SkeletonTool : : getCursorId ( ) const
{
switch ( m_device ) {
case TD_None :
if ( m_mode . getValue ( ) = = BUILD_SKELETON )
break ;
else
return ToolCursor : : RotCursor ;
case TD_Translation :
return ToolCursor : : MoveCursor ;
case TD_Rotation :
return ToolCursor : : RotCursor ;
default :
return ToolCursor : : StrokeSelectCursor ;
}
return ToolCursor : : StrokeSelectCursor ;
}
//-------------------------------------------------------------------
void SkeletonTool : : addContextMenuItems ( QMenu * menu )
{
bool ikEnabled = m_mode . getValue ( ) = = INVERSE_KINEMATICS ;
if ( ikEnabled ) {
Skeleton * skeleton = new Skeleton ( ) ;
buildSkeleton ( * skeleton , TTool : : getApplication ( ) - > getCurrentColumn ( ) - > getColumnIndex ( ) ) ;
if ( skeleton - > hasPinnedRanges ( ) | | skeleton - > isIKEnabled ( ) ) {
m_commandHandler - > setSkeleton ( skeleton ) ;
QAction * rp = menu - > addAction ( tr ( " Reset Pinned Center " ) ) ;
menu - > addSeparator ( ) ;
bool ret = QObject : : connect (
rp , SIGNAL ( triggered ( ) ) ,
m_commandHandler , SLOT ( clearPinnedRanges ( ) ) ) ;
assert ( ret ) ;
} else
delete skeleton ;
}
}
//-------------------------------------------------------------------
void SkeletonTool : : buildSkeleton ( Skeleton & skeleton , int columnIndex )
{
int frame = TTool : : getApplication ( ) - > getCurrentFrame ( ) - > getFrame ( ) ;
skeleton . build ( getXsheet ( ) , frame , columnIndex , m_temporaryPinnedColumns ) ;
}