2016-03-19 06:57:51 +13:00
# include "brushtool.h"
// TnzTools includes
# include "tools/toolhandle.h"
# include "tools/toolutils.h"
# include "tools/tooloptions.h"
# include "bluredbrush.h"
// TnzQt includes
# include "toonzqt/dvdialog.h"
# include "toonzqt/imageutils.h"
// TnzLib includes
# include "toonz/tobjecthandle.h"
# include "toonz/txsheethandle.h"
# include "toonz/txshlevelhandle.h"
# include "toonz/tframehandle.h"
# include "toonz/tcolumnhandle.h"
# include "toonz/txsheet.h"
# include "toonz/tstageobject.h"
# include "toonz/tstageobjectspline.h"
# include "toonz/rasterstrokegenerator.h"
# include "toonz/ttileset.h"
# include "toonz/txshsimplelevel.h"
# include "toonz/toonzimageutils.h"
# include "toonz/palettecontroller.h"
# include "toonz/stage2.h"
// TnzCore includes
# include "tstream.h"
# include "tcolorstyles.h"
# include "tvectorimage.h"
# include "tenv.h"
# include "tregion.h"
# include "tstroke.h"
# include "tgl.h"
# include "trop.h"
// Qt includes
# include <QPainter>
using namespace ToolUtils ;
TEnv : : DoubleVar VectorBrushMinSize ( " InknpaintVectorBrushMinSize " , 1 ) ;
TEnv : : DoubleVar VectorBrushMaxSize ( " InknpaintVectorBrushMaxSize " , 5 ) ;
TEnv : : IntVar VectorCapStyle ( " InknpaintVectorCapStyle " , 0 ) ;
TEnv : : IntVar VectorJoinStyle ( " InknpaintVectorJoinStyle " , 0 ) ;
TEnv : : IntVar VectorMiterValue ( " InknpaintVectorMiterValue " , 4 ) ;
TEnv : : DoubleVar RasterBrushMinSize ( " InknpaintRasterBrushMinSize " , 1 ) ;
TEnv : : DoubleVar RasterBrushMaxSize ( " InknpaintRasterBrushMaxSize " , 5 ) ;
TEnv : : DoubleVar BrushAccuracy ( " InknpaintBrushAccuracy " , 20 ) ;
TEnv : : IntVar BrushSelective ( " InknpaintBrushSelective " , 0 ) ;
TEnv : : IntVar BrushBreakSharpAngles ( " InknpaintBrushBreakSharpAngles " , 0 ) ;
TEnv : : IntVar RasterBrushPencilMode ( " InknpaintRasterBrushPencilMode " , 0 ) ;
TEnv : : IntVar BrushPressureSensibility ( " InknpaintBrushPressureSensibility " , 1 ) ;
TEnv : : DoubleVar RasterBrushHardness ( " RasterBrushHardness " , 100 ) ;
//-------------------------------------------------------------------
# define ROUNDC_WSTR L"round_cap"
# define BUTT_WSTR L"butt_cap"
# define PROJECTING_WSTR L"projecting_cap"
# define ROUNDJ_WSTR L"round_join"
# define BEVEL_WSTR L"bevel_join"
# define MITER_WSTR L"miter_join"
# define CUSTOM_WSTR L"<custom>"
//-------------------------------------------------------------------
//
// (Da mettere in libreria) : funzioni che spezzano una stroke
// nei suoi punti angolosi. Lo facciamo specialmente per limitare
// i problemi di fill.
//
//-------------------------------------------------------------------
//
// Split a stroke in n+1 parts, according to n parameter values
// Input:
// stroke = stroke to split
// parameterValues[] = vector of parameters where I want to split the stroke
// assert: 0<a[0]<a[1]<...<a[n-1]<1
// Output:
// strokes[] = the split strokes
//
// note: stroke is unchanged
//
void split (
TStroke * stroke ,
2016-04-19 19:32:17 +12:00
const std : : vector < double > & parameterValues ,
std : : vector < TStroke * > & strokes )
2016-03-19 06:57:51 +13:00
{
TThickPoint p2 ;
std : : vector < TThickPoint > points ;
TThickPoint lastPoint = stroke - > getControlPoint ( 0 ) ;
int n = parameterValues . size ( ) ;
int chunk ;
double t ;
int last_chunk = - 1 , startPoint = 0 ;
double lastLocT = 0 ;
for ( int i = 0 ; i < n ; i + + ) {
points . push_back ( lastPoint ) ; // Add first point of the stroke
double w = parameterValues [ i ] ; // Global parameter. along the stroke 0<=w<=1
stroke - > getChunkAndT ( w , chunk , t ) ; // t: local parameter in the chunk-th quadratic
if ( i = = 0 )
startPoint = 1 ;
else {
int indexAfterLastT =
stroke - > getControlPointIndexAfterParameter ( parameterValues [ i - 1 ] ) ;
startPoint = indexAfterLastT ;
if ( ( indexAfterLastT & 1 ) & & lastLocT ! = 1 )
startPoint + + ;
}
int endPoint = 2 * chunk + 1 ;
if ( lastLocT ! = 1 & & i > 0 ) {
if ( last_chunk ! = chunk | | t = = 1 )
points . push_back ( p2 ) ; // If the last local t is not an extreme
// add the point p2
}
for ( int j = startPoint ; j < endPoint ; j + + )
points . push_back ( stroke - > getControlPoint ( j ) ) ;
TThickPoint p , A , B , C ;
p = stroke - > getPoint ( w ) ;
C = stroke - > getControlPoint ( 2 * chunk + 2 ) ;
B = stroke - > getControlPoint ( 2 * chunk + 1 ) ;
A = stroke - > getControlPoint ( 2 * chunk ) ;
p . thick = A . thick ;
if ( last_chunk ! = chunk ) {
TThickPoint p1 = ( 1 - t ) * A + t * B ;
points . push_back ( p1 ) ;
p . thick = p1 . thick ;
} else {
if ( t ! = 1 ) {
// If the i-th cut point belong to the same chunk of the (i-1)-th cut point.
double tInters = lastLocT / t ;
TThickPoint p11 = ( 1 - t ) * A + t * B ;
TThickPoint p1 = ( 1 - tInters ) * p11 + tInters * p ;
points . push_back ( p1 ) ;
p . thick = p1 . thick ;
}
}
points . push_back ( p ) ;
if ( t ! = 1 )
p2 = ( 1 - t ) * B + t * C ;
assert ( points . size ( ) & 1 ) ;
// Add new stroke
TStroke * strokeAdd = new TStroke ( points ) ;
strokeAdd - > setStyle ( stroke - > getStyle ( ) ) ;
strokeAdd - > outlineOptions ( ) = stroke - > outlineOptions ( ) ;
strokes . push_back ( strokeAdd ) ;
lastPoint = p ;
last_chunk = chunk ;
lastLocT = t ;
points . clear ( ) ;
}
// Add end stroke
points . push_back ( lastPoint ) ;
if ( lastLocT ! = 1 )
points . push_back ( p2 ) ;
startPoint = stroke - > getControlPointIndexAfterParameter ( parameterValues [ n - 1 ] ) ;
if ( ( stroke - > getControlPointIndexAfterParameter ( parameterValues [ n - 1 ] ) & 1 ) & & lastLocT ! = 1 )
startPoint + + ;
for ( int j = startPoint ; j < stroke - > getControlPointCount ( ) ; j + + )
points . push_back ( stroke - > getControlPoint ( j ) ) ;
assert ( points . size ( ) & 1 ) ;
TStroke * strokeAdd = new TStroke ( points ) ;
strokeAdd - > setStyle ( stroke - > getStyle ( ) ) ;
strokeAdd - > outlineOptions ( ) = stroke - > outlineOptions ( ) ;
strokes . push_back ( strokeAdd ) ;
points . clear ( ) ;
}
//Compute Parametric Curve Curvature
//By Formula:
// k(t)=(|p'(t) x p''(t)|)/Norm2(p')^3
// p(t) is parametric curve
// Input:
// dp = First Derivate.
// ddp = Second Derivate
// Output:
// return curvature value.
// Note: if the curve is a single point (that's dp=0) or it is a straight line (that's ddp=0) return 0
double curvature ( TPointD dp , TPointD ddp )
{
if ( dp = = TPointD ( 0 , 0 ) )
return 0 ;
else
return fabs ( cross ( dp , ddp ) / pow ( norm2 ( dp ) , 1.5 ) ) ;
}
// Find the max curvature points of a stroke.
// Input:
// stroke.
// angoloLim = Value (radians) of the Corner between two tangent vector.
// Up this value the two corner can be considered angular.
// curvMaxLim = Value of the max curvature.
// Up this value the point can be considered a max curvature point.
// Output:
// parameterValues = vector of max curvature parameter points
void findMaxCurvPoints (
TStroke * stroke ,
const float & angoloLim ,
const float & curvMaxLim ,
2016-04-19 19:32:17 +12:00
std : : vector < double > & parameterValues )
2016-03-19 06:57:51 +13:00
{
TPointD tg1 , tg2 ; // Tangent vectors
TPointD dp , ddp ; // First and Second derivate.
parameterValues . clear ( ) ;
int cpn = stroke ? stroke - > getControlPointCount ( ) : 0 ;
for ( int j = 2 ; j < cpn ; j + = 2 ) {
TPointD p0 = stroke - > getControlPoint ( j - 2 ) ;
TPointD p1 = stroke - > getControlPoint ( j - 1 ) ;
TPointD p2 = stroke - > getControlPoint ( j ) ;
TPointD q = p1 - ( p0 + p2 ) * 0.5 ;
// Search corner point
if ( j > 2 ) {
tg2 = - p0 + p2 + 2 * q ; // Tangent vector to this chunk at t=0
double prod_scal = tg2 * tg1 ; // Inner product between tangent vectors at t=0.
assert ( tg1 ! = TPointD ( 0 , 0 ) | | tg2 ! = TPointD ( 0 , 0 ) ) ;
// Compute corner between two tangent vectors
double angolo = acos ( prod_scal / ( pow ( norm2 ( tg2 ) , 0.5 ) * pow ( norm2 ( tg1 ) , 0.5 ) ) ) ;
//Add corner point
if ( angolo > angoloLim ) {
double w = getWfromChunkAndT ( stroke , ( UINT ) ( 0.5 * ( j - 2 ) ) , 0 ) ; // transform lacal t to global t
parameterValues . push_back ( w ) ;
}
}
tg1 = - p0 + p2 - 2 * q ; // Tangent vector to this chunk at t=1
// End search corner point
// Search max curvature point
// Value of t where the curvature function has got an extreme.
// (Point where first derivate is null)
double estremo_int = 0 ;
double t = - 1 ;
if ( q ! = TPointD ( 0 , 0 ) ) {
t = 0.25 * ( 2 * q . x * q . x + 2 * q . y * q . y - q . x * p0 . x + q . x * p2 . x - q . y * p0 . y + q . y * p2 . y ) / ( q . x * q . x + q . y * q . y ) ;
dp = - p0 + p2 + 2 * q - 4 * t * q ; // First derivate of the curve
ddp = - 4 * q ; // Second derivate of the curve
estremo_int = curvature ( dp , ddp ) ;
double h = 0.01 ;
dp = - p0 + p2 + 2 * q - 4 * ( t + h ) * q ;
double c_dx = curvature ( dp , ddp ) ;
dp = - p0 + p2 + 2 * q - 4 * ( t - h ) * q ;
double c_sx = curvature ( dp , ddp ) ;
// Check the point is a max and not a minimum
if ( estremo_int < c_dx & & estremo_int < c_sx ) {
estremo_int = 0 ;
}
}
double curv_max = estremo_int ;
//Compute curvature at the extreme of interval [0,1]
//Compute curvature at t=0 (Left extreme)
dp = - p0 + p2 + 2 * q ;
double estremo_sx = curvature ( dp , ddp ) ;
//Compute curvature at t=1 (Right extreme)
dp = - p0 + p2 - 2 * q ;
double estremo_dx = curvature ( dp , ddp ) ;
// Compare curvature at the extreme of interval [0,1] with the internal value
double t_ext ;
if ( estremo_sx > = estremo_dx )
t_ext = 0 ;
else
t_ext = 1 ;
double maxEstremi = tmax ( estremo_dx , estremo_sx ) ;
if ( maxEstremi > estremo_int ) {
t = t_ext ;
curv_max = maxEstremi ;
}
// Add max curvature point
if ( t > = 0 & & t < = 1 & & curv_max > curvMaxLim ) {
double w = getWfromChunkAndT ( stroke , ( UINT ) ( 0.5 * ( j - 2 ) ) , t ) ; // transform local t to global t
parameterValues . push_back ( w ) ;
}
// End search max curvature point
}
// Delete duplicate of parameterValues
// Because some max cuvature point can coincide with the corner point
if ( ( int ) parameterValues . size ( ) > 1 ) {
std : : sort ( parameterValues . begin ( ) , parameterValues . end ( ) ) ;
parameterValues . erase ( std : : unique ( parameterValues . begin ( ) , parameterValues . end ( ) ) , parameterValues . end ( ) ) ;
}
}
void addStroke ( TTool : : Application * application , const TVectorImageP & vi , TStroke * stroke , bool breakAngles ,
bool frameCreated , bool levelCreated )
{
QMutexLocker lock ( vi - > getMutex ( ) ) ;
if ( application - > getCurrentObject ( ) - > isSpline ( ) ) {
application - > getCurrentXsheet ( ) - > notifyXsheetChanged ( ) ;
return ;
}
std : : vector < double > corners ;
std : : vector < TStroke * > strokes ;
const float angoloLim = 1 ; // Value (radians) of the Corner between two tangent vector.
// Up this value the two corner can be considered angular.
const float curvMaxLim = 0.8 ; // Value of the max curvature.
// Up this value the point can be considered a max curvature point.
findMaxCurvPoints ( stroke , angoloLim , curvMaxLim , corners ) ;
TXshSimpleLevel * sl = application - > getCurrentLevel ( ) - > getSimpleLevel ( ) ;
TFrameId id = application - > getCurrentTool ( ) - > getTool ( ) - > getCurrentFid ( ) ;
if ( ! corners . empty ( ) ) {
if ( breakAngles )
split ( stroke , corners , strokes ) ;
else
strokes . push_back ( new TStroke ( * stroke ) ) ;
int n = strokes . size ( ) ;
TUndoManager : : manager ( ) - > beginBlock ( ) ;
for ( int i = 0 ; i < n ; i + + ) {
2016-04-19 19:32:17 +12:00
std : : vector < TFilledRegionInf > * fillInformation = new std : : vector < TFilledRegionInf > ;
2016-03-19 06:57:51 +13:00
ImageUtils : : getFillingInformationOverlappingArea ( vi , * fillInformation , stroke - > getBBox ( ) ) ;
TStroke * str = new TStroke ( * strokes [ i ] ) ;
vi - > addStroke ( str ) ;
TUndoManager : : manager ( ) - > add ( new UndoPencil ( str , fillInformation , sl , id , frameCreated , levelCreated ) ) ;
}
TUndoManager : : manager ( ) - > endBlock ( ) ;
} else {
2016-04-19 19:32:17 +12:00
std : : vector < TFilledRegionInf > * fillInformation = new std : : vector < TFilledRegionInf > ;
2016-03-19 06:57:51 +13:00
ImageUtils : : getFillingInformationOverlappingArea ( vi , * fillInformation , stroke - > getBBox ( ) ) ;
TStroke * str = new TStroke ( * stroke ) ;
vi - > addStroke ( str ) ;
TUndoManager : : manager ( ) - > add ( new UndoPencil ( str , fillInformation , sl , id , frameCreated , levelCreated ) ) ;
}
for ( int k = 0 ; k < ( int ) strokes . size ( ) ; k + + )
delete strokes [ k ] ;
strokes . clear ( ) ;
application - > getCurrentTool ( ) - > getTool ( ) - > notifyImageChanged ( ) ;
}
//-------------------------------------------------------------------
//
// Gennaro: end
//
//-------------------------------------------------------------------
//===================================================================
//
// Helper functions and classes
//
//-------------------------------------------------------------------
namespace
{
//-------------------------------------------------------------------
void addStrokeToImage ( TTool : : Application * application , const TVectorImageP & vi , TStroke * stroke , bool breakAngles ,
bool frameCreated , bool levelCreated )
{
QMutexLocker lock ( vi - > getMutex ( ) ) ;
addStroke ( application , vi . getPointer ( ) , stroke , breakAngles , frameCreated , levelCreated ) ;
//la notifica viene gia fatta da addStroke!
//getApplication()->getCurrentTool()->getTool()->notifyImageChanged();
}
//=========================================================================================================
class RasterBrushUndo : public TRasterUndo
{
2016-04-19 19:32:17 +12:00
std : : vector < TThickPoint > m_points ;
2016-03-19 06:57:51 +13:00
int m_styleId ;
bool m_selective ;
bool m_isPencil ;
public :
RasterBrushUndo ( TTileSetCM32 * tileSet ,
2016-04-19 19:32:17 +12:00
const std : : vector < TThickPoint > & points ,
2016-03-19 06:57:51 +13:00
int styleId , bool selective ,
TXshSimpleLevel * level , const TFrameId & frameId , bool isPencil ,
bool isFrameCreated , bool isLevelCreated )
: TRasterUndo ( tileSet , level , frameId , isFrameCreated , isLevelCreated , 0 ) , m_points ( points ) , m_styleId ( styleId ) , m_selective ( selective ) , m_isPencil ( isPencil )
{
}
void redo ( ) const
{
insertLevelAndFrameIfNeeded ( ) ;
TToonzImageP image = getImage ( ) ;
TRasterCM32P ras = image - > getRaster ( ) ;
RasterStrokeGenerator m_rasterTrack ( ras , BRUSH , NONE , m_styleId , m_points [ 0 ] , m_selective , 0 , ! m_isPencil ) ;
m_rasterTrack . setPointsSequence ( m_points ) ;
m_rasterTrack . generateStroke ( m_isPencil ) ;
image - > setSavebox ( image - > getSavebox ( ) + m_rasterTrack . getBBox ( m_rasterTrack . getPointsSequence ( ) ) ) ;
ToolUtils : : updateSaveBox ( ) ;
TTool : : getApplication ( ) - > getCurrentXsheet ( ) - > notifyXsheetChanged ( ) ;
notifyImageChanged ( ) ;
}
int getSize ( ) const
{
return sizeof ( * this ) + TRasterUndo : : getSize ( ) ;
}
QString getToolName ( )
{
return QString ( " Brush Tool " ) ;
}
int getHistoryType ( )
{
return HistoryType : : BrushTool ;
}
} ;
//=========================================================================================================
class RasterBluredBrushUndo : public TRasterUndo
{
2016-04-19 19:32:17 +12:00
std : : vector < TThickPoint > m_points ;
2016-03-19 06:57:51 +13:00
int m_styleId ;
bool m_selective ;
int m_maxThick ;
double m_hardness ;
public :
2016-04-19 19:32:17 +12:00
RasterBluredBrushUndo ( TTileSetCM32 * tileSet , const std : : vector < TThickPoint > & points ,
2016-03-19 06:57:51 +13:00
int styleId , bool selective , TXshSimpleLevel * level , const TFrameId & frameId ,
int maxThick , double hardness , bool isFrameCreated , bool isLevelCreated )
: TRasterUndo ( tileSet , level , frameId , isFrameCreated , isLevelCreated , 0 ) , m_points ( points ) , m_styleId ( styleId ) , m_selective ( selective ) , m_maxThick ( maxThick ) , m_hardness ( hardness )
{
}
void redo ( ) const
{
if ( m_points . size ( ) = = 0 )
return ;
insertLevelAndFrameIfNeeded ( ) ;
TToonzImageP image = getImage ( ) ;
TRasterCM32P ras = image - > getRaster ( ) ;
TRasterCM32P backupRas = ras - > clone ( ) ;
TRaster32P workRaster ( ras - > getSize ( ) ) ;
QRadialGradient brushPad = ToolUtils : : getBrushPad ( m_maxThick , m_hardness ) ;
workRaster - > clear ( ) ;
BluredBrush brush ( workRaster , m_maxThick , brushPad , false ) ;
2016-04-19 19:32:17 +12:00
std : : vector < TThickPoint > points ;
2016-03-19 06:57:51 +13:00
points . push_back ( m_points [ 0 ] ) ;
TRect bbox = brush . getBoundFromPoints ( points ) ;
brush . addPoint ( m_points [ 0 ] , 1 ) ;
brush . updateDrawing ( ras , ras , bbox , m_styleId , m_selective ) ;
if ( m_points . size ( ) > 1 ) {
points . clear ( ) ;
points . push_back ( m_points [ 0 ] ) ;
points . push_back ( m_points [ 1 ] ) ;
bbox = brush . getBoundFromPoints ( points ) ;
brush . addArc ( m_points [ 0 ] , ( m_points [ 1 ] + m_points [ 0 ] ) * 0.5 , m_points [ 1 ] , 1 , 1 ) ;
brush . updateDrawing ( ras , backupRas , bbox , m_styleId , m_selective ) ;
int i ;
for ( i = 1 ; i + 2 < ( int ) m_points . size ( ) ; i = i + 2 ) {
points . clear ( ) ;
points . push_back ( m_points [ i ] ) ;
points . push_back ( m_points [ i + 1 ] ) ;
points . push_back ( m_points [ i + 2 ] ) ;
bbox = brush . getBoundFromPoints ( points ) ;
brush . addArc ( m_points [ i ] , m_points [ i + 1 ] , m_points [ i + 2 ] , 1 , 1 ) ;
brush . updateDrawing ( ras , backupRas , bbox , m_styleId , m_selective ) ;
}
}
ToolUtils : : updateSaveBox ( ) ;
TTool : : getApplication ( ) - > getCurrentXsheet ( ) - > notifyXsheetChanged ( ) ;
notifyImageChanged ( ) ;
}
int getSize ( ) const
{
return sizeof ( * this ) + TRasterUndo : : getSize ( ) ;
}
virtual QString getToolName ( )
{
return QString ( " Brush Tool " ) ;
}
int getHistoryType ( )
{
return HistoryType : : BrushTool ;
}
} ;
//=========================================================================================================
double computeThickness ( int pressure , const TDoublePairProperty & property , bool isPath )
{
if ( isPath )
return 0.0 ;
double p = pressure / 255.0 ;
double t = p * p * p ;
double thick0 = property . getValue ( ) . first ;
double thick1 = property . getValue ( ) . second ;
if ( thick1 < 0.0001 )
thick0 = thick1 = 0.0 ;
return ( thick0 + ( thick1 - thick0 ) * t ) * 0.5 ;
}
//---------------------------------------------------------------------------------------------------------
int computeThickness ( int pressure , const TIntPairProperty & property , bool isPath )
{
if ( isPath )
return 0.0 ;
double p = pressure / 255.0 ;
double t = p * p * p ;
int thick0 = property . getValue ( ) . first ;
int thick1 = property . getValue ( ) . second ;
return tround ( thick0 + ( thick1 - thick0 ) * t ) ;
}
} // namespace
//===================================================================
//
// BrushTool
//
//-----------------------------------------------------------------------------
2016-04-19 19:32:17 +12:00
BrushTool : : BrushTool ( std : : string name , int targetType )
2016-03-19 06:57:51 +13:00
: TTool ( name ) , m_thickness ( " Size " , 0 , 100 , 0 , 5 ) , m_rasThickness ( " Size " , 1 , 100 , 1 , 5 ) , m_accuracy ( " Accuracy: " , 1 , 100 , 20 ) , m_hardness ( " Hardness: " , 0 , 100 , 100 ) , m_preset ( " Preset: " ) , m_selective ( " Selective " , false ) , m_breakAngles ( " Break " , true ) , m_pencil ( " Pencil " , false ) , m_pressure ( " Pressure " , true ) , m_capStyle ( " Cap " ) , m_joinStyle ( " Join " ) , m_miterJoinLimit ( " Miter: " , 0 , 100 , 4 ) , m_rasterTrack ( 0 ) , m_styleId ( 0 ) , m_modifiedRegion ( ) , m_bluredBrush ( 0 ) , m_active ( false ) , m_enabled ( false ) , m_isPrompting ( false ) , m_firstTime ( true ) , m_presetsLoaded ( false ) , m_workingFrameId ( TFrameId ( ) )
{
bind ( targetType ) ;
if ( targetType & TTool : : Vectors ) {
m_prop [ 0 ] . bind ( m_thickness ) ;
m_prop [ 0 ] . bind ( m_accuracy ) ;
m_prop [ 0 ] . bind ( m_breakAngles ) ;
m_breakAngles . setId ( " BreakSharpAngles " ) ;
}
if ( targetType & TTool : : ToonzImage ) {
m_prop [ 0 ] . bind ( m_rasThickness ) ;
m_prop [ 0 ] . bind ( m_hardness ) ;
m_prop [ 0 ] . bind ( m_selective ) ;
m_prop [ 0 ] . bind ( m_pencil ) ;
m_pencil . setId ( " PencilMode " ) ;
m_selective . setId ( " Selective " ) ;
}
m_prop [ 0 ] . bind ( m_pressure ) ;
# ifndef STUDENT
m_prop [ 0 ] . bind ( m_preset ) ;
m_preset . setId ( " BrushPreset " ) ;
2016-04-18 23:24:03 +12:00
m_preset . addValue ( CUSTOM_WSTR ) ;
2016-03-19 06:57:51 +13:00
# endif
m_pressure . setId ( " PressureSensibility " ) ;
m_capStyle . addValue ( BUTT_WSTR ) ;
m_capStyle . addValue ( ROUNDC_WSTR ) ;
m_capStyle . addValue ( PROJECTING_WSTR ) ;
m_capStyle . setId ( " Cap " ) ;
m_joinStyle . addValue ( MITER_WSTR ) ;
m_joinStyle . addValue ( ROUNDJ_WSTR ) ;
m_joinStyle . addValue ( BEVEL_WSTR ) ;
m_joinStyle . setId ( " Join " ) ;
m_miterJoinLimit . setId ( " Miter " ) ;
if ( targetType & TTool : : Vectors ) {
m_prop [ 1 ] . bind ( m_capStyle ) ;
m_prop [ 1 ] . bind ( m_joinStyle ) ;
m_prop [ 1 ] . bind ( m_miterJoinLimit ) ;
}
}
//-------------------------------------------------------------------------------------------------------
ToolOptionsBox * BrushTool : : createOptionsBox ( )
{
TPaletteHandle * currPalette = TTool : : getApplication ( ) - > getPaletteController ( ) - > getCurrentLevelPalette ( ) ;
ToolHandle * currTool = TTool : : getApplication ( ) - > getCurrentTool ( ) ;
return new BrushToolOptionsBox ( 0 , this , currPalette , currTool ) ;
}
//-------------------------------------------------------------------------------------------------------
void BrushTool : : drawLine ( const TPointD & point , const TPointD & centre , bool horizontal , bool isDecimal )
{
if ( ! isDecimal ) {
if ( horizontal ) {
tglDrawSegment ( TPointD ( point . x - 1.5 , point . y + 0.5 ) + centre , TPointD ( point . x - 0.5 , point . y + 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( point . y - 0.5 , - point . x + 1.5 ) + centre , TPointD ( point . y - 0.5 , - point . x + 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( - point . x + 0.5 , - point . y + 0.5 ) + centre , TPointD ( - point . x - 0.5 , - point . y + 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( - point . y - 0.5 , point . x - 0.5 ) + centre , TPointD ( - point . y - 0.5 , point . x + 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( point . y - 0.5 , point . x + 0.5 ) + centre , TPointD ( point . y - 0.5 , point . x - 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( point . x - 0.5 , - point . y + 0.5 ) + centre , TPointD ( point . x - 1.5 , - point . y + 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( - point . y - 0.5 , - point . x + 0.5 ) + centre , TPointD ( - point . y - 0.5 , - point . x + 1.5 ) + centre ) ;
tglDrawSegment ( TPointD ( - point . x - 0.5 , point . y + 0.5 ) + centre , TPointD ( - point . x + 0.5 , point . y + 0.5 ) + centre ) ;
} else {
tglDrawSegment ( TPointD ( point . x - 1.5 , point . y + 1.5 ) + centre , TPointD ( point . x - 1.5 , point . y + 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( point . x - 1.5 , point . y + 0.5 ) + centre , TPointD ( point . x - 0.5 , point . y + 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( point . y + 0.5 , - point . x + 1.5 ) + centre , TPointD ( point . y - 0.5 , - point . x + 1.5 ) + centre ) ;
tglDrawSegment ( TPointD ( point . y - 0.5 , - point . x + 1.5 ) + centre , TPointD ( point . y - 0.5 , - point . x + 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( - point . x + 0.5 , - point . y - 0.5 ) + centre , TPointD ( - point . x + 0.5 , - point . y + 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( - point . x + 0.5 , - point . y + 0.5 ) + centre , TPointD ( - point . x - 0.5 , - point . y + 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( - point . y - 1.5 , point . x - 0.5 ) + centre , TPointD ( - point . y - 0.5 , point . x - 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( - point . y - 0.5 , point . x - 0.5 ) + centre , TPointD ( - point . y - 0.5 , point . x + 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( point . y + 0.5 , point . x - 0.5 ) + centre , TPointD ( point . y - 0.5 , point . x - 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( point . y - 0.5 , point . x - 0.5 ) + centre , TPointD ( point . y - 0.5 , point . x + 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( point . x - 1.5 , - point . y - 0.5 ) + centre , TPointD ( point . x - 1.5 , - point . y + 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( point . x - 1.5 , - point . y + 0.5 ) + centre , TPointD ( point . x - 0.5 , - point . y + 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( - point . y - 1.5 , - point . x + 1.5 ) + centre , TPointD ( - point . y - 0.5 , - point . x + 1.5 ) + centre ) ;
tglDrawSegment ( TPointD ( - point . y - 0.5 , - point . x + 1.5 ) + centre , TPointD ( - point . y - 0.5 , - point . x + 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( - point . x + 0.5 , point . y + 1.5 ) + centre , TPointD ( - point . x + 0.5 , point . y + 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( - point . x + 0.5 , point . y + 0.5 ) + centre , TPointD ( - point . x - 0.5 , point . y + 0.5 ) + centre ) ;
}
} else {
if ( horizontal ) {
tglDrawSegment ( TPointD ( point . x - 0.5 , point . y + 0.5 ) + centre , TPointD ( point . x + 0.5 , point . y + 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( point . y + 0.5 , point . x - 0.5 ) + centre , TPointD ( point . y + 0.5 , point . x + 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( point . y + 0.5 , - point . x + 0.5 ) + centre , TPointD ( point . y + 0.5 , - point . x - 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( point . x + 0.5 , - point . y - 0.5 ) + centre , TPointD ( point . x - 0.5 , - point . y - 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( - point . x - 0.5 , - point . y - 0.5 ) + centre , TPointD ( - point . x + 0.5 , - point . y - 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( - point . y - 0.5 , - point . x + 0.5 ) + centre , TPointD ( - point . y - 0.5 , - point . x - 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( - point . y - 0.5 , point . x - 0.5 ) + centre , TPointD ( - point . y - 0.5 , point . x + 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( - point . x + 0.5 , point . y + 0.5 ) + centre , TPointD ( - point . x - 0.5 , point . y + 0.5 ) + centre ) ;
} else {
tglDrawSegment ( TPointD ( point . x - 0.5 , point . y + 1.5 ) + centre , TPointD ( point . x - 0.5 , point . y + 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( point . x - 0.5 , point . y + 0.5 ) + centre , TPointD ( point . x + 0.5 , point . y + 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( point . y + 1.5 , point . x - 0.5 ) + centre , TPointD ( point . y + 0.5 , point . x - 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( point . y + 0.5 , point . x - 0.5 ) + centre , TPointD ( point . y + 0.5 , point . x + 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( point . y + 1.5 , - point . x + 0.5 ) + centre , TPointD ( point . y + 0.5 , - point . x + 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( point . y + 0.5 , - point . x + 0.5 ) + centre , TPointD ( point . y + 0.5 , - point . x - 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( point . x - 0.5 , - point . y - 1.5 ) + centre , TPointD ( point . x - 0.5 , - point . y - 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( point . x - 0.5 , - point . y - 0.5 ) + centre , TPointD ( point . x + 0.5 , - point . y - 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( - point . x + 0.5 , - point . y - 1.5 ) + centre , TPointD ( - point . x + 0.5 , - point . y - 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( - point . x + 0.5 , - point . y - 0.5 ) + centre , TPointD ( - point . x - 0.5 , - point . y - 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( - point . y - 1.5 , - point . x + 0.5 ) + centre , TPointD ( - point . y - 0.5 , - point . x + 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( - point . y - 0.5 , - point . x + 0.5 ) + centre , TPointD ( - point . y - 0.5 , - point . x - 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( - point . y - 1.5 , point . x - 0.5 ) + centre , TPointD ( - point . y - 0.5 , point . x - 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( - point . y - 0.5 , point . x - 0.5 ) + centre , TPointD ( - point . y - 0.5 , point . x + 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( - point . x + 0.5 , point . y + 1.5 ) + centre , TPointD ( - point . x + 0.5 , point . y + 0.5 ) + centre ) ;
tglDrawSegment ( TPointD ( - point . x + 0.5 , point . y + 0.5 ) + centre , TPointD ( - point . x - 0.5 , point . y + 0.5 ) + centre ) ;
}
}
}
//-------------------------------------------------------------------------------------------------------
void BrushTool : : drawEmptyCircle ( TPointD pos , int thick , bool isLxEven , bool isLyEven , bool isPencil )
{
if ( isLxEven )
pos . x + = 0.5 ;
if ( isLyEven )
pos . y + = 0.5 ;
if ( ! isPencil )
tglDrawCircle ( pos , ( thick + 1 ) * 0.5 ) ;
else {
int x = 0 , y = tround ( ( thick * 0.5 ) - 0.5 ) ;
int d = 3 - 2 * ( int ) ( thick * 0.5 ) ;
bool horizontal = true , isDecimal = thick % 2 ! = 0 ;
drawLine ( TPointD ( x , y ) , pos , horizontal , isDecimal ) ;
while ( y > x ) {
if ( d < 0 ) {
d = d + 4 * x + 6 ;
horizontal = true ;
} else {
d = d + 4 * ( x - y ) + 10 ;
horizontal = false ;
y - - ;
}
x + + ;
drawLine ( TPointD ( x , y ) , pos , horizontal , isDecimal ) ;
}
}
}
//-------------------------------------------------------------------------------------------------------
void BrushTool : : updateTranslation ( )
{
m_thickness . setQStringName ( tr ( " Size " ) ) ;
m_rasThickness . setQStringName ( tr ( " Size " ) ) ;
m_hardness . setQStringName ( tr ( " Hardness: " ) ) ;
m_accuracy . setQStringName ( tr ( " Accuracy: " ) ) ;
m_selective . setQStringName ( tr ( " Selective " ) ) ;
//m_filled.setQStringName(tr("Filled"));
m_preset . setQStringName ( tr ( " Preset: " ) ) ;
m_breakAngles . setQStringName ( tr ( " Break " ) ) ;
m_pencil . setQStringName ( tr ( " Pencil " ) ) ;
m_pressure . setQStringName ( tr ( " Pressure " ) ) ;
m_capStyle . setQStringName ( tr ( " Cap " ) ) ;
m_joinStyle . setQStringName ( tr ( " Join " ) ) ;
m_miterJoinLimit . setQStringName ( tr ( " Miter: " ) ) ;
}
//---------------------------------------------------------------------------------------------------
void BrushTool : : updateWorkAndBackupRasters ( const TRect & rect )
{
TToonzImageP ti = TImageP ( getImage ( false , 1 ) ) ;
if ( ! ti )
return ;
TRasterCM32P ras = ti - > getRaster ( ) ;
TRect _rect = rect * ras - > getBounds ( ) ;
TRect _lastRect = m_lastRect * ras - > getBounds ( ) ;
if ( _rect . isEmpty ( ) )
return ;
if ( m_lastRect . isEmpty ( ) ) {
m_workRas - > extract ( _rect ) - > clear ( ) ;
m_backupRas - > extract ( _rect ) - > copy ( ras - > extract ( _rect ) ) ;
return ;
}
QList < TRect > rects = ToolUtils : : splitRect ( _rect , _lastRect ) ;
for ( int i = 0 ; i < rects . size ( ) ; i + + ) {
m_workRas - > extract ( rects [ i ] ) - > clear ( ) ;
m_backupRas - > extract ( rects [ i ] ) - > copy ( ras - > extract ( rects [ i ] ) ) ;
}
}
//---------------------------------------------------------------------------------------------------
void BrushTool : : onActivate ( )
{
if ( m_firstTime ) {
m_thickness . setValue ( TDoublePairProperty : : Value ( VectorBrushMinSize , VectorBrushMaxSize ) ) ;
m_rasThickness . setValue ( TDoublePairProperty : : Value ( RasterBrushMinSize , RasterBrushMaxSize ) ) ;
m_capStyle . setIndex ( VectorCapStyle ) ;
m_joinStyle . setIndex ( VectorJoinStyle ) ;
m_miterJoinLimit . setValue ( VectorMiterValue ) ;
m_selective . setValue ( BrushSelective ? 1 : 0 ) ;
m_breakAngles . setValue ( BrushBreakSharpAngles ? 1 : 0 ) ;
m_pencil . setValue ( RasterBrushPencilMode ? 1 : 0 ) ;
m_pressure . setValue ( BrushPressureSensibility ? 1 : 0 ) ;
m_firstTime = false ;
m_accuracy . setValue ( BrushAccuracy ) ;
m_hardness . setValue ( RasterBrushHardness ) ;
}
if ( m_targetType & TTool : : ToonzImage ) {
m_brushPad = ToolUtils : : getBrushPad ( m_rasThickness . getValue ( ) . second , m_hardness . getValue ( ) * 0.01 ) ;
setWorkAndBackupImages ( ) ;
}
//TODO:app->editImageOrSpline();
}
//--------------------------------------------------------------------------------------------------
void BrushTool : : onDeactivate ( )
{
/*--- ドラッグ中にツールが切り替わった場合に備え、onDeactivateにもMouseReleaseと同じ処理を行う ---*/
if ( m_tileSaver & & ! m_isPath ) {
bool isValid = m_enabled & & m_active ;
m_enabled = false ;
if ( isValid ) {
TImageP image = getImage ( true ) ;
if ( TToonzImageP ti = image )
finishRasterBrush ( m_mousePos , 1 ) ; /*-- 最後のストロークの筆圧は1とする --*/
}
}
m_workRas = TRaster32P ( ) ;
m_backupRas = TRasterCM32P ( ) ;
}
//--------------------------------------------------------------------------------------------------
bool BrushTool : : preLeftButtonDown ( )
{
touchImage ( ) ;
if ( m_isFrameCreated )
setWorkAndBackupImages ( ) ;
return true ;
}
//--------------------------------------------------------------------------------------------------
void BrushTool : : leftButtonDown ( const TPointD & pos , const TMouseEvent & e )
{
TTool : : Application * app = TTool : : getApplication ( ) ;
if ( ! app )
return ;
int col = app - > getCurrentColumn ( ) - > getColumnIndex ( ) ;
m_isPath = app - > getCurrentObject ( ) - > isSpline ( ) ;
m_enabled = col > = 0 | | m_isPath ;
// todo: gestire autoenable
if ( ! m_enabled )
return ;
if ( ! m_isPath ) {
m_currentColor = TPixel32 : : Black ;
m_active = ! ! getImage ( true ) ;
if ( ! m_active ) {
m_active = ! ! touchImage ( ) ;
}
if ( ! m_active )
return ;
if ( m_active ) {
// nel caso che il colore corrente sia un cleanup/studiopalette color
// oppure il colore di un colorfield
m_styleId = app - > getCurrentLevelStyleIndex ( ) ;
TColorStyle * cs = app - > getCurrentLevelStyle ( ) ;
if ( cs ) {
TRasterStyleFx * rfx = cs ? cs - > getRasterStyleFx ( ) : 0 ;
m_active = cs ! = 0 & & ( cs - > isStrokeStyle ( ) | | ( rfx & & rfx - > isInkStyle ( ) ) ) ;
m_currentColor = cs - > getAverageColor ( ) ;
m_currentColor . m = 255 ;
} else {
m_styleId = 1 ;
m_currentColor = TPixel32 : : Black ;
}
}
} else {
m_currentColor = TPixel32 : : Red ;
m_active = true ;
}
//assert(0<=m_styleId && m_styleId<2);
TImageP img = getImage ( true ) ;
TToonzImageP ri ( img ) ;
if ( ri ) {
TRasterCM32P ras = ri - > getRaster ( ) ;
if ( ras ) {
TPointD rasCenter = ras - > getCenterD ( ) ;
m_tileSet = new TTileSetCM32 ( ras - > getSize ( ) ) ;
m_tileSaver = new TTileSaverCM32 ( ras , m_tileSet ) ;
double maxThick = m_rasThickness . getValue ( ) . second ;
double thickness = ( m_pressure . getValue ( ) | | m_isPath ) ? computeThickness ( e . m_pressure , m_rasThickness , m_isPath ) * 2 : maxThick ;
/*--- ストロークの最初にMaxサイズの円が描かれてしまう不具合を防止する ---*/
if ( m_pressure . getValue ( ) & & e . m_pressure = = 255 )
thickness = m_rasThickness . getValue ( ) . first ;
TPointD halfThick ( maxThick * 0.5 , maxThick * 0.5 ) ;
TRectD invalidateRect ( pos - halfThick , pos + halfThick ) ;
if ( m_hardness . getValue ( ) = = 100 | | m_pencil . getValue ( ) ) {
/*-- Pencilモードでなく、Hardness=100 の場合のブラシサイズを1段階下げる --*/
if ( ! m_pencil . getValue ( ) )
thickness - = 1.0 ;
m_rasterTrack = new RasterStrokeGenerator ( ras , BRUSH , NONE , m_styleId ,
TThickPoint ( pos + convert ( ras - > getCenter ( ) ) , thickness ) ,
m_selective . getValue ( ) , 0 , ! m_pencil . getValue ( ) ) ;
m_tileSaver - > save ( m_rasterTrack - > getLastRect ( ) ) ;
m_rasterTrack - > generateLastPieceOfStroke ( m_pencil . getValue ( ) ) ;
} else {
m_points . clear ( ) ;
TThickPoint point ( pos + rasCenter , thickness ) ;
m_points . push_back ( point ) ;
m_bluredBrush = new BluredBrush ( m_workRas , maxThick , m_brushPad , false ) ;
m_strokeRect = m_bluredBrush - > getBoundFromPoints ( m_points ) ;
updateWorkAndBackupRasters ( m_strokeRect ) ;
m_tileSaver - > save ( m_strokeRect ) ;
m_bluredBrush - > addPoint ( point , 1 ) ;
m_bluredBrush - > updateDrawing ( ri - > getRaster ( ) , m_backupRas , m_strokeRect , m_styleId , m_selective . getValue ( ) ) ;
m_lastRect = m_strokeRect ;
}
/*-- 作業中のFidを登録 --*/
m_workingFrameId = getFrameId ( ) ;
invalidate ( invalidateRect ) ;
}
} else {
m_track . clear ( ) ;
double thickness = ( m_pressure . getValue ( ) | | m_isPath ) ? computeThickness ( e . m_pressure , m_thickness , m_isPath ) : m_thickness . getValue ( ) . second * 0.5 ;
/*--- ストロークの最初にMaxサイズの円が描かれてしまう不具合を防止する ---*/
if ( m_pressure . getValue ( ) & & e . m_pressure = = 255 )
thickness = m_rasThickness . getValue ( ) . first ;
m_track . add ( TThickPoint ( pos , thickness ) , getPixelSize ( ) * getPixelSize ( ) ) ;
}
}
//-------------------------------------------------------------------------------------------------------------
void BrushTool : : leftButtonDrag ( const TPointD & pos , const TMouseEvent & e )
{
m_brushPos = m_mousePos = pos ;
if ( ! m_enabled | | ! m_active )
return ;
bool isAdded ;
if ( TToonzImageP ti = TImageP ( getImage ( true ) ) ) {
TPointD rasCenter = ti - > getRaster ( ) - > getCenterD ( ) ;
int maxThickness = m_rasThickness . getValue ( ) . second ;
double thickness = ( m_pressure . getValue ( ) | | m_isPath ) ? computeThickness ( e . m_pressure , m_rasThickness , m_isPath ) * 2 : maxThickness ;
TRectD invalidateRect ;
if ( m_rasterTrack & & ( m_hardness . getValue ( ) = = 100 | | m_pencil . getValue ( ) ) ) {
/*-- Pencilモードでなく、Hardness=100 の場合のブラシサイズを1段階下げる --*/
if ( ! m_pencil . getValue ( ) )
thickness - = 1.0 ;
isAdded = m_rasterTrack - > add ( TThickPoint ( pos + rasCenter , thickness ) ) ;
if ( isAdded ) {
m_tileSaver - > save ( m_rasterTrack - > getLastRect ( ) ) ;
m_rasterTrack - > generateLastPieceOfStroke ( m_pencil . getValue ( ) ) ;
2016-04-19 19:32:17 +12:00
std : : vector < TThickPoint > brushPoints = m_rasterTrack - > getPointsSequence ( ) ;
2016-03-19 06:57:51 +13:00
int m = ( int ) brushPoints . size ( ) ;
2016-04-19 19:32:17 +12:00
std : : vector < TThickPoint > points ;
2016-03-19 06:57:51 +13:00
if ( m = = 3 ) {
points . push_back ( brushPoints [ 0 ] ) ;
points . push_back ( brushPoints [ 1 ] ) ;
} else {
points . push_back ( brushPoints [ m - 4 ] ) ;
points . push_back ( brushPoints [ m - 3 ] ) ;
points . push_back ( brushPoints [ m - 2 ] ) ;
}
invalidateRect = ToolUtils : : getBounds ( points , maxThickness ) - rasCenter ;
}
} else {
//antialiased brush
assert ( m_workRas . getPointer ( ) & & m_backupRas . getPointer ( ) ) ;
TThickPoint old = m_points . back ( ) ;
if ( norm2 ( pos - old ) < 4 )
return ;
TThickPoint point ( pos + rasCenter , thickness ) ;
TThickPoint mid ( ( old + point ) * 0.5 , ( point . thick + old . thick ) * 0.5 ) ;
m_points . push_back ( mid ) ;
m_points . push_back ( point ) ;
TRect bbox ;
int m = ( int ) m_points . size ( ) ;
2016-04-19 19:32:17 +12:00
std : : vector < TThickPoint > points ;
2016-03-19 06:57:51 +13:00
if ( m = = 3 ) {
// ho appena cominciato. devo disegnare un segmento
TThickPoint pa = m_points . front ( ) ;
points . push_back ( pa ) ;
points . push_back ( mid ) ;
bbox = m_bluredBrush - > getBoundFromPoints ( points ) ;
updateWorkAndBackupRasters ( bbox + m_lastRect ) ;
m_tileSaver - > save ( bbox ) ;
m_bluredBrush - > addArc ( pa , ( mid + pa ) * 0.5 , mid , 1 , 1 ) ;
m_lastRect + = bbox ;
} else {
points . push_back ( m_points [ m - 4 ] ) ;
points . push_back ( old ) ;
points . push_back ( mid ) ;
bbox = m_bluredBrush - > getBoundFromPoints ( points ) ;
updateWorkAndBackupRasters ( bbox + m_lastRect ) ;
m_tileSaver - > save ( bbox ) ;
m_bluredBrush - > addArc ( m_points [ m - 4 ] , old , mid , 1 , 1 ) ;
m_lastRect + = bbox ;
}
invalidateRect = ToolUtils : : getBounds ( points , maxThickness ) - rasCenter ;
m_bluredBrush - > updateDrawing ( ti - > getRaster ( ) , m_backupRas , bbox , m_styleId , m_selective . getValue ( ) ) ;
m_strokeRect + = bbox ;
}
invalidate ( invalidateRect . enlarge ( 2 ) ) ;
} else {
double thickness = ( m_pressure . getValue ( ) | | m_isPath ) ? computeThickness ( e . m_pressure , m_thickness , m_isPath ) : m_thickness . getValue ( ) . second * 0.5 ;
m_track . add ( TThickPoint ( pos , thickness ) , getPixelSize ( ) * getPixelSize ( ) ) ;
invalidate ( ) ;
}
}
//---------------------------------------------------------------------------------------------------------------
void BrushTool : : leftButtonUp ( const TPointD & pos , const TMouseEvent & e )
{
bool isValid = m_enabled & & m_active ;
m_enabled = false ;
if ( ! isValid )
return ;
if ( m_isPath ) {
double error = 20.0 * getPixelSize ( ) ;
TStroke * stroke = m_track . makeStroke ( error ) ;
int points = stroke - > getControlPointCount ( ) ;
if ( TVectorImageP vi = getImage ( true ) ) {
struct Cleanup {
BrushTool * m_this ;
~ Cleanup ( ) { m_this - > m_track . clear ( ) , m_this - > invalidate ( ) ; }
} cleanup = { this } ;
if ( ! isJustCreatedSpline ( vi . getPointer ( ) ) ) {
m_isPrompting = true ;
QString question ( " Are you sure you want to replace the motion path? " ) ;
int ret = DVGui : : MsgBox ( question , QObject : : tr ( " Yes " ) , QObject : : tr ( " No " ) , 0 ) ;
m_isPrompting = false ;
if ( ret = = 2 | | ret = = 0 )
return ;
}
QMutexLocker lock ( vi - > getMutex ( ) ) ;
TUndo * undo = new UndoPath ( getXsheet ( ) - > getStageObject ( getObjectId ( ) ) - > getSpline ( ) ) ;
while ( vi - > getStrokeCount ( ) > 0 )
vi - > deleteStroke ( 0 ) ;
vi - > addStroke ( stroke , false ) ;
notifyImageChanged ( ) ;
TUndoManager : : manager ( ) - > add ( undo ) ;
}
return ;
}
TImageP image = getImage ( true ) ;
if ( TVectorImageP vi = image ) {
if ( m_track . isEmpty ( ) ) {
m_styleId = 0 ;
m_track . clear ( ) ;
return ;
}
m_track . filterPoints ( ) ;
double error = 30.0 / ( 1 + 0.5 * m_accuracy . getValue ( ) ) ;
error * = getPixelSize ( ) ;
TStroke * stroke = m_track . makeStroke ( error ) ;
stroke - > setStyle ( m_styleId ) ;
{
TStroke : : OutlineOptions & options = stroke - > outlineOptions ( ) ;
options . m_capStyle = m_capStyle . getIndex ( ) ;
options . m_joinStyle = m_joinStyle . getIndex ( ) ;
options . m_miterUpper = m_miterJoinLimit . getValue ( ) ;
}
m_styleId = 0 ;
QMutexLocker lock ( vi - > getMutex ( ) ) ;
if ( stroke - > getControlPointCount ( ) = = 3 & & stroke - > getControlPoint ( 0 ) ! = stroke - > getControlPoint ( 2 ) ) // gli stroke con solo 1 chunk vengono fatti dal tape tool...e devono venir riconosciuti come speciali di autoclose proprio dal fatto che hanno 1 solo chunk.
stroke - > insertControlPoints ( 0.5 ) ;
addStrokeToImage ( getApplication ( ) , vi , stroke , m_breakAngles . getValue ( ) , m_isFrameCreated , m_isLevelCreated ) ;
TRectD bbox = stroke - > getBBox ( ) . enlarge ( 2 ) + m_track . getModifiedRegion ( ) ;
invalidate ( ) ;
assert ( stroke ) ;
m_track . clear ( ) ;
} else if ( TToonzImageP ti = image ) {
finishRasterBrush ( pos , e . m_pressure ) ;
}
}
//---------------------------------------------------------------------------------------------------------------
/*! ドラッグ中にツールが切り替わった場合に備え、onDeactivate時とMouseRelease時にと同じ終了処理を行う
*/
void BrushTool : : finishRasterBrush ( const TPointD & pos , int pressureVal )
{
TImageP image = getImage ( true ) ;
TToonzImageP ti = image ;
if ( ! ti )
return ;
TPointD rasCenter = ti - > getRaster ( ) - > getCenterD ( ) ;
TTool : : Application * app = TTool : : getApplication ( ) ;
TXshLevel * level = app - > getCurrentLevel ( ) - > getLevel ( ) ;
TXshSimpleLevelP simLevel = level - > getSimpleLevel ( ) ;
/*-- 描画中にカレントフレームが変わっても、描画開始時のFidに対してUndoを記録する --*/
TFrameId frameId = m_workingFrameId . isEmptyFrame ( ) ? getCurrentFid ( ) : m_workingFrameId ;
if ( m_rasterTrack & & ( m_hardness . getValue ( ) = = 100 | | m_pencil . getValue ( ) ) ) {
double thickness = m_pressure . getValue ( ) ? computeThickness ( pressureVal , m_rasThickness , m_isPath ) : m_rasThickness . getValue ( ) . second ;
/*--- ストロークの最初にMaxサイズの円が描かれてしまう不具合を防止する ---*/
if ( m_pressure . getValue ( ) & & pressureVal = = 255 )
thickness = m_rasThickness . getValue ( ) . first ;
/*-- Pencilモードでなく、Hardness=100 の場合のブラシサイズを1段階下げる --*/
if ( ! m_pencil . getValue ( ) )
thickness - = 1.0 ;
bool isAdded = m_rasterTrack - > add ( TThickPoint ( pos + convert ( ti - > getRaster ( ) - > getCenter ( ) ) , thickness ) ) ;
if ( isAdded ) {
m_tileSaver - > save ( m_rasterTrack - > getLastRect ( ) ) ;
m_rasterTrack - > generateLastPieceOfStroke ( m_pencil . getValue ( ) , true ) ;
2016-04-19 19:32:17 +12:00
std : : vector < TThickPoint > brushPoints = m_rasterTrack - > getPointsSequence ( ) ;
2016-03-19 06:57:51 +13:00
int m = ( int ) brushPoints . size ( ) ;
2016-04-19 19:32:17 +12:00
std : : vector < TThickPoint > points ;
2016-03-19 06:57:51 +13:00
if ( m = = 3 ) {
points . push_back ( brushPoints [ 0 ] ) ;
points . push_back ( brushPoints [ 1 ] ) ;
} else {
points . push_back ( brushPoints [ m - 4 ] ) ;
points . push_back ( brushPoints [ m - 3 ] ) ;
points . push_back ( brushPoints [ m - 2 ] ) ;
}
int maxThickness = m_rasThickness . getValue ( ) . second ;
invalidate ( ToolUtils : : getBounds ( points , maxThickness ) . enlarge ( 2 ) - rasCenter ) ;
}
if ( m_tileSet - > getTileCount ( ) > 0 ) {
TUndoManager : : manager ( ) - > add ( new RasterBrushUndo ( m_tileSet ,
m_rasterTrack - > getPointsSequence ( ) ,
m_rasterTrack - > getStyleId ( ) ,
m_rasterTrack - > isSelective ( ) ,
simLevel . getPointer ( ) ,
frameId , m_pencil . getValue ( ) ,
m_isFrameCreated ,
m_isLevelCreated ) ) ;
}
delete m_rasterTrack ;
m_rasterTrack = 0 ;
} else {
if ( m_points . size ( ) ! = 1 ) {
double maxThickness = m_rasThickness . getValue ( ) . second ;
double thickness = ( m_pressure . getValue ( ) | | m_isPath ) ? computeThickness ( pressureVal , m_rasThickness , m_isPath )
: maxThickness ;
TPointD rasCenter = ti - > getRaster ( ) - > getCenterD ( ) ;
TThickPoint point ( pos + rasCenter , thickness ) ;
m_points . push_back ( point ) ;
int m = m_points . size ( ) ;
2016-04-19 19:32:17 +12:00
std : : vector < TThickPoint > points ;
2016-03-19 06:57:51 +13:00
points . push_back ( m_points [ m - 3 ] ) ;
points . push_back ( m_points [ m - 2 ] ) ;
points . push_back ( m_points [ m - 1 ] ) ;
TRect bbox = m_bluredBrush - > getBoundFromPoints ( points ) ;
updateWorkAndBackupRasters ( bbox ) ;
m_tileSaver - > save ( bbox ) ;
m_bluredBrush - > addArc ( points [ 0 ] , points [ 1 ] , points [ 2 ] , 1 , 1 ) ;
m_bluredBrush - > updateDrawing ( ti - > getRaster ( ) , m_backupRas , bbox , m_styleId , m_selective . getValue ( ) ) ;
TRectD invalidateRect = ToolUtils : : getBounds ( points , maxThickness ) ;
invalidate ( invalidateRect . enlarge ( 2 ) - rasCenter ) ;
m_strokeRect + = bbox ;
m_lastRect . empty ( ) ;
}
delete m_bluredBrush ;
m_bluredBrush = 0 ;
if ( m_tileSet - > getTileCount ( ) > 0 ) {
TUndoManager : : manager ( ) - > add ( new RasterBluredBrushUndo ( m_tileSet ,
m_points ,
m_styleId ,
m_selective . getValue ( ) ,
simLevel . getPointer ( ) ,
frameId ,
m_rasThickness . getValue ( ) . second ,
m_hardness . getValue ( ) * 0.01 ,
m_isFrameCreated ,
m_isLevelCreated ) ) ;
}
}
delete m_tileSaver ;
m_tileSaver = 0 ;
/*-- FIdを指定して、描画中にフレームが動いても、
描 画 開 始 時 の Fidのサムネイルが更新されるようにする 。 - - */
notifyImageChanged ( frameId ) ;
m_strokeRect . empty ( ) ;
ToolUtils : : updateSaveBox ( ) ;
/*-- 作業中のフレームをリセット --*/
m_workingFrameId = TFrameId ( ) ;
}
//---------------------------------------------------------------------------------------------------------------
void BrushTool : : mouseMove ( const TPointD & pos , const TMouseEvent & e )
{
qApp - > processEvents ( QEventLoop : : ExcludeUserInputEvents ) ;
struct Locals {
BrushTool * m_this ;
void setValue ( TDoublePairProperty & prop , const TDoublePairProperty : : Value & value )
{
prop . setValue ( value ) ;
m_this - > onPropertyChanged ( prop . getName ( ) ) ;
TTool : : getApplication ( ) - > getCurrentTool ( ) - > notifyToolChanged ( ) ;
}
void addMinMax ( TDoublePairProperty & prop , double add )
{
2016-04-18 23:24:03 +12:00
if ( add = = 0.0 )
return ;
2016-03-19 06:57:51 +13:00
const TDoublePairProperty : : Range & range = prop . getRange ( ) ;
TDoublePairProperty : : Value value = prop . getValue ( ) ;
value . first = tcrop ( value . first + add , range . first , range . second ) ;
value . second = tcrop ( value . second + add , range . first , range . second ) ;
setValue ( prop , value ) ;
}
} locals = { this } ;
switch ( e . getModifiersMask ( ) ) {
/*-- Altキー+マウス移動で、ブラシサイズ( Min/Maxとも) を変える( CtrlやShiftでは誤操作の恐れがある) --*/
case TMouseEvent : : ALT_KEY : {
// User wants to alter the minimum brush size
const TPointD & diff = pos - m_mousePos ;
double add = ( fabs ( diff . x ) > fabs ( diff . y ) ) ? diff . x : diff . y ;
locals . addMinMax ( TToonzImageP ( getImage ( false , 1 ) ) ? m_rasThickness : m_thickness , add ) ;
}
DEFAULT :
m_brushPos = pos ;
}
m_mousePos = pos ;
invalidate ( ) ;
if ( m_minThick = = 0 & & m_maxThick = = 0 ) {
if ( m_targetType & TTool : : ToonzImage ) {
m_minThick = m_rasThickness . getValue ( ) . first ;
m_maxThick = m_rasThickness . getValue ( ) . second ;
} else {
m_minThick = m_thickness . getValue ( ) . first ;
m_maxThick = m_thickness . getValue ( ) . second ;
}
}
}
//-------------------------------------------------------------------------------------------------------------
void BrushTool : : draw ( )
{
/*--ショートカットでのツール切り替え時に赤点が描かれるのを防止する--*/
if ( m_minThick = = 0 & & m_maxThick = = 0 )
return ;
TImageP img = getImage ( false , 1 ) ;
// Draw track
tglColor ( m_isPrompting ? TPixel32 : : Green : m_currentColor ) ;
m_track . drawAllFragments ( ) ;
if ( getApplication ( ) - > getCurrentObject ( ) - > isSpline ( ) )
return ;
// Draw the brush outline - change color when the Ink / Paint check is activated
if ( ( ToonzCheck : : instance ( ) - > getChecks ( ) & ToonzCheck : : eInk ) | | ( ToonzCheck : : instance ( ) - > getChecks ( ) & ToonzCheck : : ePaint ) | | ( ToonzCheck : : instance ( ) - > getChecks ( ) & ToonzCheck : : eInk1 ) )
glColor3d ( 0.5 , 0.8 , 0.8 ) ;
//normally draw in red
else
glColor3d ( 1.0 , 0.0 , 0.0 ) ;
if ( TToonzImageP ti = img ) {
TRasterP ras = ti - > getRaster ( ) ;
int lx = ras - > getLx ( ) ;
int ly = ras - > getLy ( ) ;
drawEmptyCircle ( m_brushPos , tround ( m_minThick ) , lx % 2 = = 0 , ly % 2 = = 0 , m_pencil . getValue ( ) ) ;
drawEmptyCircle ( m_brushPos , tround ( m_maxThick ) , lx % 2 = = 0 , ly % 2 = = 0 , m_pencil . getValue ( ) ) ;
} else {
tglDrawCircle ( m_brushPos , 0.5 * m_minThick ) ;
tglDrawCircle ( m_brushPos , 0.5 * m_maxThick ) ;
}
}
//--------------------------------------------------------------------------------------------------------------
void BrushTool : : onEnter ( )
{
TImageP img = getImage ( false ) ;
if ( TToonzImageP ( img ) ) {
m_minThick = m_rasThickness . getValue ( ) . first ;
m_maxThick = m_rasThickness . getValue ( ) . second ;
} else {
m_minThick = m_thickness . getValue ( ) . first ;
m_maxThick = m_thickness . getValue ( ) . second ;
}
Application * app = getApplication ( ) ;
m_styleId = app - > getCurrentLevelStyleIndex ( ) ;
TColorStyle * cs = app - > getCurrentLevelStyle ( ) ;
if ( cs ) {
TRasterStyleFx * rfx = cs - > getRasterStyleFx ( ) ;
m_active = cs - > isStrokeStyle ( ) | | ( rfx & & rfx - > isInkStyle ( ) ) ;
m_currentColor = cs - > getAverageColor ( ) ;
m_currentColor . m = 255 ;
} else {
m_currentColor = TPixel32 : : Black ;
}
m_active = img ;
}
//----------------------------------------------------------------------------------------------------------
void BrushTool : : onLeave ( )
{
m_minThick = 0 ;
m_maxThick = 0 ;
}
//----------------------------------------------------------------------------------------------------------
TPropertyGroup * BrushTool : : getProperties ( int idx )
{
if ( ! m_presetsLoaded )
initPresets ( ) ;
return & m_prop [ idx ] ;
}
//----------------------------------------------------------------------------------------------------------
void BrushTool : : onImageChanged ( )
{
TToonzImageP ti = ( TToonzImageP ) getImage ( false , 1 ) ;
if ( ! ti | | ! isEnabled ( ) )
return ;
setWorkAndBackupImages ( ) ;
}
//----------------------------------------------------------------------------------------------------------
void BrushTool : : setWorkAndBackupImages ( )
{
TToonzImageP ti = ( TToonzImageP ) getImage ( false , 1 ) ;
if ( ! ti )
return ;
TRasterP ras = ti - > getRaster ( ) ;
TDimension dim = ras - > getSize ( ) ;
double hardness = m_hardness . getValue ( ) * 0.01 ;
if ( hardness = = 1.0 & & ras - > getPixelSize ( ) = = 4 ) {
m_workRas = TRaster32P ( ) ;
m_backupRas = TRasterCM32P ( ) ;
} else {
if ( ! m_workRas | | m_workRas - > getLx ( ) > dim . lx | | m_workRas - > getLy ( ) > dim . ly )
m_workRas = TRaster32P ( dim ) ;
if ( ! m_backupRas | | m_backupRas - > getLx ( ) > dim . lx | | m_backupRas - > getLy ( ) > dim . ly )
m_backupRas = TRasterCM32P ( dim ) ;
m_strokeRect . empty ( ) ;
m_lastRect . empty ( ) ;
}
}
//------------------------------------------------------------------
2016-04-19 19:32:17 +12:00
bool BrushTool : : onPropertyChanged ( std : : string propertyName )
2016-03-19 06:57:51 +13:00
{
//Set the following to true whenever a different piece of interface must
//be refreshed - done once at the end.
bool notifyTool = false ;
/*--- 変更されたPropertyに合わせて処理を分ける ---*/
/*--- m_thicknessとm_rasThicknessは同じName(="Size:")なので、
扱 っ て い る 画 像 が ラ ス タ か ど う か で 区 別 す る - - - */
if ( propertyName = = m_thickness . getName ( ) ) {
TImageP img = getImage ( false ) ;
if ( TToonzImageP ( img ) ) //raster
{
RasterBrushMinSize = m_rasThickness . getValue ( ) . first ;
RasterBrushMaxSize = m_rasThickness . getValue ( ) . second ;
m_minThick = m_rasThickness . getValue ( ) . first ;
m_maxThick = m_rasThickness . getValue ( ) . second ;
} else //vector
{
VectorBrushMinSize = m_thickness . getValue ( ) . first ;
VectorBrushMaxSize = m_thickness . getValue ( ) . second ;
m_minThick = m_thickness . getValue ( ) . first ;
m_maxThick = m_thickness . getValue ( ) . second ;
2016-04-19 21:14:52 +12:00
}
2016-03-19 06:57:51 +13:00
} else if ( propertyName = = m_accuracy . getName ( ) ) {
BrushAccuracy = m_accuracy . getValue ( ) ;
} else if ( propertyName = = m_preset . getName ( ) ) {
loadPreset ( ) ;
notifyTool = true ;
} else if ( propertyName = = m_selective . getName ( ) ) {
BrushSelective = m_selective . getValue ( ) ;
} else if ( propertyName = = m_breakAngles . getName ( ) ) {
BrushBreakSharpAngles = m_breakAngles . getValue ( ) ;
} else if ( propertyName = = m_pencil . getName ( ) ) {
RasterBrushPencilMode = m_pencil . getValue ( ) ;
} else if ( propertyName = = m_pressure . getName ( ) ) {
BrushPressureSensibility = m_pressure . getValue ( ) ;
} else if ( propertyName = = m_capStyle . getName ( ) ) {
VectorCapStyle = m_capStyle . getIndex ( ) ;
} else if ( propertyName = = m_joinStyle . getName ( ) ) {
VectorJoinStyle = m_joinStyle . getIndex ( ) ;
} else if ( propertyName = = m_miterJoinLimit . getName ( ) ) {
VectorMiterValue = m_miterJoinLimit . getValue ( ) ;
}
if ( m_targetType & TTool : : Vectors ) {
if ( propertyName = = m_joinStyle . getName ( ) )
notifyTool = true ;
}
if ( m_targetType & TTool : : ToonzImage ) {
if ( propertyName = = m_hardness . getName ( ) )
setWorkAndBackupImages ( ) ;
if ( propertyName = = m_hardness . getName ( ) | | propertyName = = m_thickness . getName ( ) ) {
m_brushPad = getBrushPad ( m_rasThickness . getValue ( ) . second , m_hardness . getValue ( ) * 0.01 ) ;
TRectD rect ( m_mousePos - TPointD ( m_maxThick + 2 , m_maxThick + 2 ) ,
m_mousePos + TPointD ( m_maxThick + 2 , m_maxThick + 2 ) ) ;
invalidate ( rect ) ;
}
}
2016-04-19 21:14:52 +12:00
if ( propertyName ! = m_preset . getName ( ) & & m_preset . getValue ( ) ! = CUSTOM_WSTR ) {
2016-03-19 06:57:51 +13:00
m_preset . setValue ( CUSTOM_WSTR ) ;
notifyTool = true ;
}
if ( notifyTool )
getApplication ( ) - > getCurrentTool ( ) - > notifyToolChanged ( ) ;
return true ;
}
//------------------------------------------------------------------
void BrushTool : : initPresets ( )
{
if ( ! m_presetsLoaded ) {
//If necessary, load the presets from file
m_presetsLoaded = true ;
if ( getTargetType ( ) & TTool : : Vectors )
m_presetsManager . load ( TEnv : : getConfigDir ( ) + " brush_vector.txt " ) ;
else
m_presetsManager . load ( TEnv : : getConfigDir ( ) + " brush_toonzraster.txt " ) ;
}
//Rebuild the presets property entries
const std : : set < BrushData > & presets = m_presetsManager . presets ( ) ;
m_preset . deleteAllValues ( ) ;
m_preset . addValue ( CUSTOM_WSTR ) ;
std : : set < BrushData > : : const_iterator it , end = presets . end ( ) ;
for ( it = presets . begin ( ) ; it ! = end ; + + it )
m_preset . addValue ( it - > m_name ) ;
}
//----------------------------------------------------------------------------------------------------------
void BrushTool : : loadPreset ( )
{
const std : : set < BrushData > & presets = m_presetsManager . presets ( ) ;
std : : set < BrushData > : : const_iterator it ;
it = presets . find ( BrushData ( m_preset . getValue ( ) ) ) ;
if ( it = = presets . end ( ) )
return ;
const BrushData & preset = * it ;
try //Don't bother with RangeErrors
{
if ( getTargetType ( ) & TTool : : Vectors ) {
m_thickness . setValue ( TDoublePairProperty : : Value ( preset . m_min , preset . m_max ) ) ;
m_accuracy . setValue ( preset . m_acc , true ) ;
m_breakAngles . setValue ( preset . m_breakAngles ) ;
m_pressure . setValue ( preset . m_pressure ) ;
m_capStyle . setIndex ( preset . m_cap ) ;
m_joinStyle . setIndex ( preset . m_join ) ;
m_miterJoinLimit . setValue ( preset . m_miter ) ;
} else {
m_rasThickness . setValue ( TDoublePairProperty : : Value ( tmax ( preset . m_min , 1.0 ) , preset . m_max ) ) ;
m_brushPad = ToolUtils : : getBrushPad ( preset . m_max , preset . m_hardness * 0.01 ) ;
m_hardness . setValue ( preset . m_hardness , true ) ;
m_selective . setValue ( preset . m_selective ) ;
m_pencil . setValue ( preset . m_pencil ) ;
m_pressure . setValue ( preset . m_pressure ) ;
}
} catch ( . . . ) {
}
}
//------------------------------------------------------------------
void BrushTool : : addPreset ( QString name )
{
//Build the preset
BrushData preset ( name . toStdWString ( ) ) ;
if ( getTargetType ( ) & TTool : : Vectors ) {
preset . m_min = m_thickness . getValue ( ) . first ;
preset . m_max = m_thickness . getValue ( ) . second ;
} else {
preset . m_min = m_rasThickness . getValue ( ) . first ;
preset . m_max = m_rasThickness . getValue ( ) . second ;
}
preset . m_acc = m_accuracy . getValue ( ) ;
preset . m_hardness = m_hardness . getValue ( ) ;
preset . m_selective = m_selective . getValue ( ) ;
preset . m_pencil = m_pencil . getValue ( ) ;
preset . m_breakAngles = m_breakAngles . getValue ( ) ;
preset . m_pressure = m_pressure . getValue ( ) ;
preset . m_cap = m_capStyle . getIndex ( ) ;
preset . m_join = m_joinStyle . getIndex ( ) ;
preset . m_miter = m_miterJoinLimit . getValue ( ) ;
//Pass the preset to the manager
m_presetsManager . addPreset ( preset ) ;
//Reinitialize the associated preset enum
initPresets ( ) ;
//Set the value to the specified one
m_preset . setValue ( preset . m_name ) ;
}
//------------------------------------------------------------------
void BrushTool : : removePreset ( )
{
2016-04-19 19:32:17 +12:00
std : : wstring name ( m_preset . getValue ( ) ) ;
2016-03-19 06:57:51 +13:00
if ( name = = CUSTOM_WSTR )
return ;
m_presetsManager . removePreset ( name ) ;
initPresets ( ) ;
//No parameter change, and set the preset value to custom
m_preset . setValue ( CUSTOM_WSTR ) ;
}
//------------------------------------------------------------------
/*! Brush、PaintBrush、EraserToolがPencilModeのときにTrueを返す
*/
bool BrushTool : : isPencilModeActive ( )
{
return getTargetType ( ) = = TTool : : ToonzImage & & m_pencil . getValue ( ) ;
}
//==========================================================================================================
// Tools instantiation
BrushTool vectorPencil ( " T_Brush " , TTool : : Vectors | TTool : : EmptyTarget ) ;
BrushTool toonzPencil ( " T_Brush " , TTool : : ToonzImage | TTool : : EmptyTarget ) ;
//*******************************************************************************
// Brush Data implementation
//*******************************************************************************
BrushData : : BrushData ( )
: m_name ( ) , m_min ( 0.0 ) , m_max ( 0.0 ) , m_acc ( 0.0 ) , m_hardness ( 0.0 ) , m_opacityMin ( 0.0 ) , m_opacityMax ( 0.0 ) , m_selective ( false ) , m_pencil ( false ) , m_breakAngles ( false ) , m_pressure ( false ) , m_cap ( 0 ) , m_join ( 0 ) , m_miter ( 0 )
{
}
//----------------------------------------------------------------------------------------------------------
BrushData : : BrushData ( const std : : wstring & name )
: m_name ( name ) , m_min ( 0.0 ) , m_max ( 0.0 ) , m_acc ( 0.0 ) , m_hardness ( 0.0 ) , m_opacityMin ( 0.0 ) , m_opacityMax ( 0.0 ) , m_selective ( false ) , m_pencil ( false ) , m_breakAngles ( false ) , m_pressure ( false ) , m_cap ( 0 ) , m_join ( 0 ) , m_miter ( 0 )
{
}
//----------------------------------------------------------------------------------------------------------
void BrushData : : saveData ( TOStream & os )
{
os . openChild ( " Name " ) ;
os < < m_name ;
os . closeChild ( ) ;
os . openChild ( " Thickness " ) ;
os < < m_min < < m_max ;
os . closeChild ( ) ;
os . openChild ( " Accuracy " ) ;
os < < m_acc ;
os . closeChild ( ) ;
os . openChild ( " Hardness " ) ;
os < < m_hardness ;
os . closeChild ( ) ;
os . openChild ( " Opacity " ) ;
os < < m_opacityMin < < m_opacityMax ;
os . closeChild ( ) ;
os . openChild ( " Selective " ) ;
os < < ( int ) m_selective ;
os . closeChild ( ) ;
os . openChild ( " Pencil " ) ;
os < < ( int ) m_pencil ;
os . closeChild ( ) ;
os . openChild ( " Break_Sharp_Angles " ) ;
os < < ( int ) m_breakAngles ;
os . closeChild ( ) ;
os . openChild ( " Pressure_Sensitivity " ) ;
os < < ( int ) m_pressure ;
os . closeChild ( ) ;
os . openChild ( " Cap " ) ;
os < < m_cap ;
os . closeChild ( ) ;
os . openChild ( " Join " ) ;
os < < m_join ;
os . closeChild ( ) ;
os . openChild ( " Miter " ) ;
os < < m_miter ;
os . closeChild ( ) ;
}
//----------------------------------------------------------------------------------------------------------
void BrushData : : loadData ( TIStream & is )
{
std : : string tagName ;
int val ;
while ( is . matchTag ( tagName ) ) {
if ( tagName = = " Name " )
is > > m_name , is . matchEndTag ( ) ;
else if ( tagName = = " Thickness " )
is > > m_min > > m_max , is . matchEndTag ( ) ;
else if ( tagName = = " Accuracy " )
is > > m_acc , is . matchEndTag ( ) ;
else if ( tagName = = " Hardness " )
is > > m_hardness , is . matchEndTag ( ) ;
else if ( tagName = = " Opacity " )
is > > m_opacityMin > > m_opacityMax , is . matchEndTag ( ) ;
else if ( tagName = = " Selective " )
is > > val , m_selective = val , is . matchEndTag ( ) ;
else if ( tagName = = " Pencil " )
is > > val , m_pencil = val , is . matchEndTag ( ) ;
else if ( tagName = = " Break_Sharp_Angles " )
is > > val , m_breakAngles = val , is . matchEndTag ( ) ;
else if ( tagName = = " Pressure_Sensitivity " )
is > > val , m_pressure = val , is . matchEndTag ( ) ;
else if ( tagName = = " Cap " )
is > > m_cap , is . matchEndTag ( ) ;
else if ( tagName = = " Join " )
is > > m_join , is . matchEndTag ( ) ;
else if ( tagName = = " Miter " )
is > > m_miter , is . matchEndTag ( ) ;
else
is . skipCurrentTag ( ) ;
}
}
//----------------------------------------------------------------------------------------------------------
PERSIST_IDENTIFIER ( BrushData , " BrushData " ) ;
//*******************************************************************************
// Brush Preset Manager implementation
//*******************************************************************************
void BrushPresetManager : : load ( const TFilePath & fp )
{
m_fp = fp ;
std : : string tagName ;
BrushData data ;
TIStream is ( m_fp ) ;
try {
while ( is . matchTag ( tagName ) ) {
if ( tagName = = " version " ) {
VersionNumber version ;
is > > version . first > > version . second ;
is . setVersion ( version ) ;
is . matchEndTag ( ) ;
} else if ( tagName = = " brushes " ) {
while ( is . matchTag ( tagName ) ) {
if ( tagName = = " brush " ) {
is > > data , m_presets . insert ( data ) ;
is . matchEndTag ( ) ;
} else
is . skipCurrentTag ( ) ;
}
is . matchEndTag ( ) ;
} else
is . skipCurrentTag ( ) ;
}
} catch ( . . . ) {
}
}
//------------------------------------------------------------------
void BrushPresetManager : : save ( )
{
TOStream os ( m_fp ) ;
os . openChild ( " version " ) ;
os < < 1 < < 19 ;
os . closeChild ( ) ;
os . openChild ( " brushes " ) ;
std : : set < BrushData > : : iterator it , end = m_presets . end ( ) ;
for ( it = m_presets . begin ( ) ; it ! = end ; + + it ) {
os . openChild ( " brush " ) ;
os < < ( TPersist & ) * it ;
os . closeChild ( ) ;
}
os . closeChild ( ) ;
}
//------------------------------------------------------------------
void BrushPresetManager : : addPreset ( const BrushData & data )
{
m_presets . erase ( data ) ; //Overwriting insertion
m_presets . insert ( data ) ;
save ( ) ;
}
//------------------------------------------------------------------
2016-04-19 19:32:17 +12:00
void BrushPresetManager : : removePreset ( const std : : wstring & name )
2016-03-19 06:57:51 +13:00
{
m_presets . erase ( BrushData ( name ) ) ;
save ( ) ;
}