2969 lines
62 KiB
C
2969 lines
62 KiB
C
/*
|
|
* $Id$
|
|
*
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*/
|
|
|
|
/** \file blender/editors/armature/editarmature_sketch.c
|
|
* \ingroup edarmature
|
|
*/
|
|
|
|
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <float.h>
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "DNA_object_types.h"
|
|
#include "DNA_scene_types.h"
|
|
#include "DNA_armature_types.h"
|
|
|
|
#include "RNA_define.h"
|
|
#include "RNA_access.h"
|
|
|
|
#include "BLI_blenlib.h"
|
|
#include "BLI_math.h"
|
|
#include "BLI_utildefines.h"
|
|
#include "BLI_graph.h"
|
|
#include "BLI_ghash.h"
|
|
|
|
#include "BKE_context.h"
|
|
#include "BKE_sketch.h"
|
|
|
|
#include "ED_view3d.h"
|
|
#include "ED_screen.h"
|
|
|
|
#include "BIF_gl.h"
|
|
//#include "BIF_screen.h"
|
|
//#include "BIF_space.h"
|
|
//#include "BIF_mywindow.h"
|
|
#include "ED_armature.h"
|
|
#include "armature_intern.h"
|
|
//#include "BIF_sketch.h"
|
|
#include "BIF_retarget.h"
|
|
#include "BIF_generate.h"
|
|
//#include "BIF_interface.h"
|
|
|
|
#include "ED_transform.h"
|
|
|
|
#include "WM_api.h"
|
|
#include "WM_types.h"
|
|
|
|
//#include "blendef.h"
|
|
//#include "mydevice.h"
|
|
#include "reeb.h"
|
|
|
|
|
|
|
|
typedef int (*GestureDetectFct)(bContext*, SK_Gesture*, SK_Sketch *);
|
|
typedef void (*GestureApplyFct)(bContext*, SK_Gesture*, SK_Sketch *);
|
|
|
|
typedef struct SK_GestureAction {
|
|
char name[64];
|
|
GestureDetectFct detect;
|
|
GestureApplyFct apply;
|
|
} SK_GestureAction;
|
|
|
|
#if 0 /* UNUSED 2.5 */
|
|
static SK_Point boneSnap;
|
|
#endif
|
|
|
|
static int LAST_SNAP_POINT_VALID = 0;
|
|
static float LAST_SNAP_POINT[3];
|
|
|
|
|
|
typedef struct SK_StrokeIterator {
|
|
HeadFct head;
|
|
TailFct tail;
|
|
PeekFct peek;
|
|
NextFct next;
|
|
NextNFct nextN;
|
|
PreviousFct previous;
|
|
StoppedFct stopped;
|
|
|
|
float *p, *no;
|
|
float size;
|
|
|
|
int length;
|
|
int index;
|
|
/*********************************/
|
|
SK_Stroke *stroke;
|
|
int start;
|
|
int end;
|
|
int stride;
|
|
} SK_StrokeIterator;
|
|
|
|
/******************** PROTOTYPES ******************************/
|
|
|
|
void initStrokeIterator(BArcIterator *iter, SK_Stroke *stk, int start, int end);
|
|
|
|
int sk_detectCutGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
|
|
void sk_applyCutGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
|
|
int sk_detectTrimGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
|
|
void sk_applyTrimGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
|
|
int sk_detectCommandGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
|
|
void sk_applyCommandGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
|
|
int sk_detectDeleteGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
|
|
void sk_applyDeleteGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
|
|
int sk_detectMergeGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
|
|
void sk_applyMergeGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
|
|
int sk_detectReverseGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
|
|
void sk_applyReverseGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
|
|
int sk_detectConvertGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
|
|
void sk_applyConvertGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch);
|
|
|
|
SK_Sketch* contextSketch(const bContext *c, int create);
|
|
SK_Sketch* viewcontextSketch(ViewContext *vc, int create);
|
|
|
|
void sk_resetOverdraw(SK_Sketch *sketch);
|
|
int sk_hasOverdraw(SK_Sketch *sketch, SK_Stroke *stk);
|
|
|
|
/******************** GESTURE ACTIONS ******************************/
|
|
|
|
static SK_GestureAction GESTURE_ACTIONS[] =
|
|
{
|
|
{"Cut", sk_detectCutGesture, sk_applyCutGesture},
|
|
{"Trim", sk_detectTrimGesture, sk_applyTrimGesture},
|
|
{"Command", sk_detectCommandGesture, sk_applyCommandGesture},
|
|
{"Delete", sk_detectDeleteGesture, sk_applyDeleteGesture},
|
|
{"Merge", sk_detectMergeGesture, sk_applyMergeGesture},
|
|
{"Reverse", sk_detectReverseGesture, sk_applyReverseGesture},
|
|
{"Convert", sk_detectConvertGesture, sk_applyConvertGesture},
|
|
{"", NULL, NULL}
|
|
};
|
|
|
|
/******************** TEMPLATES UTILS *************************/
|
|
|
|
static char *TEMPLATES_MENU = NULL;
|
|
static int TEMPLATES_CURRENT = 0;
|
|
static GHash *TEMPLATES_HASH = NULL;
|
|
static RigGraph *TEMPLATE_RIGG = NULL;
|
|
|
|
void BIF_makeListTemplates(const bContext *C)
|
|
{
|
|
Object *obedit = CTX_data_edit_object(C);
|
|
Scene *scene = CTX_data_scene(C);
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
|
Base *base;
|
|
int index = 0;
|
|
|
|
if (TEMPLATES_HASH != NULL)
|
|
{
|
|
BLI_ghash_free(TEMPLATES_HASH, NULL, NULL);
|
|
}
|
|
|
|
TEMPLATES_HASH = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "makeListTemplates gh");
|
|
TEMPLATES_CURRENT = 0;
|
|
|
|
for ( base = FIRSTBASE; base; base = base->next )
|
|
{
|
|
Object *ob = base->object;
|
|
|
|
if (ob != obedit && ob->type == OB_ARMATURE)
|
|
{
|
|
index++;
|
|
BLI_ghash_insert(TEMPLATES_HASH, SET_INT_IN_POINTER(index), ob);
|
|
|
|
if (ob == ts->skgen_template)
|
|
{
|
|
TEMPLATES_CURRENT = index;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
char *BIF_listTemplates(const bContext *UNUSED(C))
|
|
{
|
|
GHashIterator ghi;
|
|
char menu_header[] = "Template%t|None%x0|";
|
|
char *p;
|
|
|
|
if (TEMPLATES_MENU != NULL)
|
|
{
|
|
MEM_freeN(TEMPLATES_MENU);
|
|
}
|
|
|
|
TEMPLATES_MENU = MEM_callocN(sizeof(char) * (BLI_ghash_size(TEMPLATES_HASH) * 32 + 30), "skeleton template menu");
|
|
|
|
p = TEMPLATES_MENU;
|
|
|
|
p += sprintf(TEMPLATES_MENU, "%s", menu_header);
|
|
|
|
BLI_ghashIterator_init(&ghi, TEMPLATES_HASH);
|
|
|
|
while (!BLI_ghashIterator_isDone(&ghi))
|
|
{
|
|
Object *ob = BLI_ghashIterator_getValue(&ghi);
|
|
int key = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&ghi));
|
|
|
|
p += sprintf(p, "|%s%%x%i", ob->id.name+2, key);
|
|
|
|
BLI_ghashIterator_step(&ghi);
|
|
}
|
|
|
|
return TEMPLATES_MENU;
|
|
}
|
|
|
|
int BIF_currentTemplate(const bContext *C)
|
|
{
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
|
|
|
if (TEMPLATES_CURRENT == 0 && ts->skgen_template != NULL)
|
|
{
|
|
GHashIterator ghi;
|
|
BLI_ghashIterator_init(&ghi, TEMPLATES_HASH);
|
|
|
|
while (!BLI_ghashIterator_isDone(&ghi))
|
|
{
|
|
Object *ob = BLI_ghashIterator_getValue(&ghi);
|
|
int key = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&ghi));
|
|
|
|
if (ob == ts->skgen_template)
|
|
{
|
|
TEMPLATES_CURRENT = key;
|
|
break;
|
|
}
|
|
|
|
BLI_ghashIterator_step(&ghi);
|
|
}
|
|
}
|
|
|
|
return TEMPLATES_CURRENT;
|
|
}
|
|
|
|
static RigGraph* sk_makeTemplateGraph(const bContext *C, Object *ob)
|
|
{
|
|
Object *obedit = CTX_data_edit_object(C);
|
|
if (ob == obedit)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (ob != NULL)
|
|
{
|
|
if (TEMPLATE_RIGG && TEMPLATE_RIGG->ob != ob)
|
|
{
|
|
RIG_freeRigGraph((BGraph*)TEMPLATE_RIGG);
|
|
TEMPLATE_RIGG = NULL;
|
|
}
|
|
|
|
if (TEMPLATE_RIGG == NULL)
|
|
{
|
|
bArmature *arm;
|
|
|
|
arm = ob->data;
|
|
|
|
TEMPLATE_RIGG = RIG_graphFromArmature(C, ob, arm);
|
|
}
|
|
}
|
|
|
|
return TEMPLATE_RIGG;
|
|
}
|
|
|
|
int BIF_nbJointsTemplate(const bContext *C)
|
|
{
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
|
RigGraph *rg = sk_makeTemplateGraph(C, ts->skgen_template);
|
|
|
|
if (rg)
|
|
{
|
|
return RIG_nbJoints(rg);
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
const char * BIF_nameBoneTemplate(const bContext *C)
|
|
{
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
|
SK_Sketch *stk = contextSketch(C, 1);
|
|
RigGraph *rg;
|
|
int index = 0;
|
|
|
|
if (stk && stk->active_stroke != NULL)
|
|
{
|
|
index = stk->active_stroke->nb_points;
|
|
}
|
|
|
|
rg = sk_makeTemplateGraph(C, ts->skgen_template);
|
|
|
|
if (rg == NULL)
|
|
{
|
|
return "";
|
|
}
|
|
|
|
return RIG_nameBone(rg, 0, index);
|
|
}
|
|
|
|
void BIF_freeTemplates(bContext *UNUSED(C))
|
|
{
|
|
if (TEMPLATES_MENU != NULL)
|
|
{
|
|
MEM_freeN(TEMPLATES_MENU);
|
|
TEMPLATES_MENU = NULL;
|
|
}
|
|
|
|
if (TEMPLATES_HASH != NULL)
|
|
{
|
|
BLI_ghash_free(TEMPLATES_HASH, NULL, NULL);
|
|
TEMPLATES_HASH = NULL;
|
|
}
|
|
|
|
if (TEMPLATE_RIGG != NULL)
|
|
{
|
|
RIG_freeRigGraph((BGraph*)TEMPLATE_RIGG);
|
|
TEMPLATE_RIGG = NULL;
|
|
}
|
|
}
|
|
|
|
void BIF_setTemplate(bContext *C, int index)
|
|
{
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
|
if (index > 0)
|
|
{
|
|
ts->skgen_template = BLI_ghash_lookup(TEMPLATES_HASH, SET_INT_IN_POINTER(index));
|
|
}
|
|
else
|
|
{
|
|
ts->skgen_template = NULL;
|
|
|
|
if (TEMPLATE_RIGG != NULL)
|
|
{
|
|
RIG_freeRigGraph((BGraph*)TEMPLATE_RIGG);
|
|
}
|
|
TEMPLATE_RIGG = NULL;
|
|
}
|
|
}
|
|
|
|
/*********************** CONVERSION ***************************/
|
|
|
|
static void sk_autoname(bContext *C, ReebArc *arc)
|
|
{
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
|
if (ts->skgen_retarget_options & SK_RETARGET_AUTONAME)
|
|
{
|
|
if (arc == NULL)
|
|
{
|
|
char *num = ts->skgen_num_string;
|
|
int i = atoi(num);
|
|
i++;
|
|
BLI_snprintf(num, 8, "%i", i);
|
|
}
|
|
else
|
|
{
|
|
char *side = ts->skgen_side_string;
|
|
int valid = 0;
|
|
int caps = 0;
|
|
|
|
if (BLI_streq(side, ""))
|
|
{
|
|
valid = 1;
|
|
}
|
|
else if (BLI_streq(side, "R") || BLI_streq(side, "L"))
|
|
{
|
|
valid = 1;
|
|
caps = 1;
|
|
}
|
|
else if (BLI_streq(side, "r") || BLI_streq(side, "l"))
|
|
{
|
|
valid = 1;
|
|
caps = 0;
|
|
}
|
|
|
|
if (valid)
|
|
{
|
|
if (arc->head->p[0] < 0)
|
|
{
|
|
BLI_snprintf(side, 8, caps?"R":"r");
|
|
}
|
|
else
|
|
{
|
|
BLI_snprintf(side, 8, caps?"L":"l");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static ReebNode *sk_pointToNode(SK_Point *pt, float imat[][4], float tmat[][3])
|
|
{
|
|
ReebNode *node;
|
|
|
|
node = MEM_callocN(sizeof(ReebNode), "reeb node");
|
|
VECCOPY(node->p, pt->p);
|
|
mul_m4_v3(imat, node->p);
|
|
|
|
VECCOPY(node->no, pt->no);
|
|
mul_m3_v3(tmat, node->no);
|
|
|
|
return node;
|
|
}
|
|
|
|
static ReebArc *sk_strokeToArc(SK_Stroke *stk, float imat[][4], float tmat[][3])
|
|
{
|
|
ReebArc *arc;
|
|
int i;
|
|
|
|
arc = MEM_callocN(sizeof(ReebArc), "reeb arc");
|
|
arc->head = sk_pointToNode(stk->points, imat, tmat);
|
|
arc->tail = sk_pointToNode(sk_lastStrokePoint(stk), imat, tmat);
|
|
|
|
arc->bcount = stk->nb_points - 2; /* first and last are nodes, don't count */
|
|
arc->buckets = MEM_callocN(sizeof(EmbedBucket) * arc->bcount, "Buckets");
|
|
|
|
for (i = 0; i < arc->bcount; i++)
|
|
{
|
|
VECCOPY(arc->buckets[i].p, stk->points[i + 1].p);
|
|
mul_m4_v3(imat, arc->buckets[i].p);
|
|
|
|
VECCOPY(arc->buckets[i].no, stk->points[i + 1].no);
|
|
mul_m3_v3(tmat, arc->buckets[i].no);
|
|
}
|
|
|
|
return arc;
|
|
}
|
|
|
|
static void sk_retargetStroke(bContext *C, SK_Stroke *stk)
|
|
{
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
|
Object *obedit = CTX_data_edit_object(C);
|
|
float imat[4][4];
|
|
float tmat[3][3];
|
|
ReebArc *arc;
|
|
RigGraph *rg;
|
|
|
|
invert_m4_m4(imat, obedit->obmat);
|
|
|
|
copy_m3_m4(tmat, obedit->obmat);
|
|
transpose_m3(tmat);
|
|
|
|
arc = sk_strokeToArc(stk, imat, tmat);
|
|
|
|
sk_autoname(C, arc);
|
|
|
|
rg = sk_makeTemplateGraph(C, ts->skgen_template);
|
|
|
|
BIF_retargetArc(C, arc, rg);
|
|
|
|
sk_autoname(C, NULL);
|
|
|
|
MEM_freeN(arc->head);
|
|
MEM_freeN(arc->tail);
|
|
REEB_freeArc((BArc*)arc);
|
|
}
|
|
|
|
/**************************************************************/
|
|
|
|
static void sk_cancelStroke(SK_Sketch *sketch)
|
|
{
|
|
if (sketch->active_stroke != NULL)
|
|
{
|
|
sk_resetOverdraw(sketch);
|
|
sk_removeStroke(sketch, sketch->active_stroke);
|
|
}
|
|
}
|
|
|
|
|
|
static float sk_clampPointSize(SK_Point *pt, float size)
|
|
{
|
|
return MAX2(size * pt->size, size / 2);
|
|
}
|
|
|
|
static void sk_drawPoint(GLUquadric *quad, SK_Point *pt, float size)
|
|
{
|
|
glTranslatef(pt->p[0], pt->p[1], pt->p[2]);
|
|
gluSphere(quad, sk_clampPointSize(pt, size), 8, 8);
|
|
}
|
|
|
|
static void sk_drawEdge(GLUquadric *quad, SK_Point *pt0, SK_Point *pt1, float size)
|
|
{
|
|
float vec1[3], vec2[3] = {0, 0, 1}, axis[3];
|
|
float angle, length;
|
|
|
|
sub_v3_v3v3(vec1, pt1->p, pt0->p);
|
|
length = normalize_v3(vec1);
|
|
cross_v3_v3v3(axis, vec2, vec1);
|
|
|
|
if (is_zero_v3(axis))
|
|
{
|
|
axis[1] = 1;
|
|
}
|
|
|
|
angle = angle_normalized_v3v3(vec2, vec1);
|
|
|
|
glRotatef(angle * 180 / M_PI + 180, axis[0], axis[1], axis[2]);
|
|
|
|
gluCylinder(quad, sk_clampPointSize(pt1, size), sk_clampPointSize(pt0, size), length, 8, 8);
|
|
}
|
|
|
|
static void sk_drawNormal(GLUquadric *quad, SK_Point *pt, float size, float height)
|
|
{
|
|
float vec2[3] = {0, 0, 1}, axis[3];
|
|
float angle;
|
|
|
|
glPushMatrix();
|
|
|
|
cross_v3_v3v3(axis, vec2, pt->no);
|
|
|
|
if (is_zero_v3(axis))
|
|
{
|
|
axis[1] = 1;
|
|
}
|
|
|
|
angle = angle_normalized_v3v3(vec2, pt->no);
|
|
|
|
glRotatef(angle * 180 / M_PI, axis[0], axis[1], axis[2]);
|
|
|
|
glColor3f(0, 1, 1);
|
|
gluCylinder(quad, sk_clampPointSize(pt, size), 0, sk_clampPointSize(pt, height), 10, 2);
|
|
|
|
glPopMatrix();
|
|
}
|
|
|
|
static void sk_drawStroke(SK_Stroke *stk, int id, float color[3], int start, int end)
|
|
{
|
|
float rgb[3];
|
|
int i;
|
|
GLUquadric *quad = gluNewQuadric();
|
|
gluQuadricNormals(quad, GLU_SMOOTH);
|
|
|
|
if (id != -1)
|
|
{
|
|
glLoadName(id);
|
|
|
|
for (i = 0; i < stk->nb_points; i++)
|
|
{
|
|
glPushMatrix();
|
|
|
|
sk_drawPoint(quad, stk->points + i, 0.1);
|
|
|
|
if (i > 0)
|
|
{
|
|
sk_drawEdge(quad, stk->points + i - 1, stk->points + i, 0.1);
|
|
}
|
|
|
|
glPopMatrix();
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
float d_rgb[3] = {1, 1, 1};
|
|
|
|
copy_v3_v3(rgb, color);
|
|
sub_v3_v3(d_rgb, rgb);
|
|
mul_v3_fl(d_rgb, 1.0f / (float)stk->nb_points);
|
|
|
|
for (i = 0; i < stk->nb_points; i++)
|
|
{
|
|
SK_Point *pt = stk->points + i;
|
|
|
|
glPushMatrix();
|
|
|
|
if (pt->type == PT_EXACT)
|
|
{
|
|
glColor3f(0, 0, 0);
|
|
sk_drawPoint(quad, pt, 0.15);
|
|
sk_drawNormal(quad, pt, 0.05, 0.9);
|
|
}
|
|
|
|
if (i >= start && i <= end)
|
|
{
|
|
glColor3f(0.3, 0.3, 0.3);
|
|
}
|
|
else
|
|
{
|
|
glColor3fv(rgb);
|
|
}
|
|
|
|
if (pt->type != PT_EXACT)
|
|
{
|
|
|
|
sk_drawPoint(quad, pt, 0.1);
|
|
}
|
|
|
|
if (i > 0)
|
|
{
|
|
sk_drawEdge(quad, pt - 1, pt, 0.1);
|
|
}
|
|
|
|
glPopMatrix();
|
|
|
|
add_v3_v3(rgb, d_rgb);
|
|
}
|
|
}
|
|
|
|
gluDeleteQuadric(quad);
|
|
}
|
|
|
|
static void drawSubdividedStrokeBy(ToolSettings *toolsettings, BArcIterator *iter, NextSubdivisionFunc next_subdividion)
|
|
{
|
|
SK_Stroke *stk = ((SK_StrokeIterator*)iter)->stroke;
|
|
float head[3], tail[3];
|
|
int bone_start = 0;
|
|
int end = iter->length;
|
|
int index;
|
|
GLUquadric *quad = gluNewQuadric();
|
|
gluQuadricNormals(quad, GLU_SMOOTH);
|
|
|
|
iter->head(iter);
|
|
VECCOPY(head, iter->p);
|
|
|
|
index = next_subdividion(toolsettings, iter, bone_start, end, head, tail);
|
|
while (index != -1)
|
|
{
|
|
SK_Point *pt = stk->points + index;
|
|
|
|
glPushMatrix();
|
|
|
|
glColor3f(0, 1, 0);
|
|
sk_drawPoint(quad, pt, 0.15);
|
|
|
|
sk_drawNormal(quad, pt, 0.05, 0.9);
|
|
|
|
glPopMatrix();
|
|
|
|
VECCOPY(head, tail);
|
|
bone_start = index; // start next bone from current index
|
|
|
|
index = next_subdividion(toolsettings, iter, bone_start, end, head, tail);
|
|
}
|
|
|
|
gluDeleteQuadric(quad);
|
|
}
|
|
|
|
static void sk_drawStrokeSubdivision(ToolSettings *toolsettings, SK_Stroke *stk)
|
|
{
|
|
int head_index = -1;
|
|
int i;
|
|
|
|
if (toolsettings->bone_sketching_convert == SK_CONVERT_RETARGET)
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
for (i = 0; i < stk->nb_points; i++)
|
|
{
|
|
SK_Point *pt = stk->points + i;
|
|
|
|
if (pt->type == PT_EXACT || i == stk->nb_points - 1) /* stop on exact or on last point */
|
|
{
|
|
if (head_index == -1)
|
|
{
|
|
head_index = i;
|
|
}
|
|
else
|
|
{
|
|
if (i - head_index > 1)
|
|
{
|
|
SK_StrokeIterator sk_iter;
|
|
BArcIterator *iter = (BArcIterator*)&sk_iter;
|
|
|
|
initStrokeIterator(iter, stk, head_index, i);
|
|
|
|
if (toolsettings->bone_sketching_convert == SK_CONVERT_CUT_ADAPTATIVE)
|
|
{
|
|
drawSubdividedStrokeBy(toolsettings, iter, nextAdaptativeSubdivision);
|
|
}
|
|
else if (toolsettings->bone_sketching_convert == SK_CONVERT_CUT_LENGTH)
|
|
{
|
|
drawSubdividedStrokeBy(toolsettings, iter, nextLengthSubdivision);
|
|
}
|
|
else if (toolsettings->bone_sketching_convert == SK_CONVERT_CUT_FIXED)
|
|
{
|
|
drawSubdividedStrokeBy(toolsettings, iter, nextFixedSubdivision);
|
|
}
|
|
|
|
}
|
|
|
|
head_index = i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static SK_Point *sk_snapPointStroke(bContext *C, SK_Stroke *stk, short mval[2], int *dist, int *index, int all_pts)
|
|
{
|
|
ARegion *ar = CTX_wm_region(C);
|
|
SK_Point *pt = NULL;
|
|
int i;
|
|
|
|
for (i = 0; i < stk->nb_points; i++)
|
|
{
|
|
if (all_pts || stk->points[i].type == PT_EXACT)
|
|
{
|
|
short pval[2];
|
|
int pdist;
|
|
|
|
project_short_noclip(ar, stk->points[i].p, pval);
|
|
|
|
pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]);
|
|
|
|
if (pdist < *dist)
|
|
{
|
|
*dist = pdist;
|
|
pt = stk->points + i;
|
|
|
|
if (index != NULL)
|
|
{
|
|
*index = i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return pt;
|
|
}
|
|
|
|
#if 0 /* UNUSED 2.5 */
|
|
static SK_Point *sk_snapPointArmature(bContext *C, Object *ob, ListBase *ebones, short mval[2], int *dist)
|
|
{
|
|
ARegion *ar = CTX_wm_region(C);
|
|
SK_Point *pt = NULL;
|
|
EditBone *bone;
|
|
|
|
for (bone = ebones->first; bone; bone = bone->next)
|
|
{
|
|
float vec[3];
|
|
short pval[2];
|
|
int pdist;
|
|
|
|
if ((bone->flag & BONE_CONNECTED) == 0)
|
|
{
|
|
VECCOPY(vec, bone->head);
|
|
mul_m4_v3(ob->obmat, vec);
|
|
project_short_noclip(ar, vec, pval);
|
|
|
|
pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]);
|
|
|
|
if (pdist < *dist)
|
|
{
|
|
*dist = pdist;
|
|
pt = &boneSnap;
|
|
VECCOPY(pt->p, vec);
|
|
pt->type = PT_EXACT;
|
|
}
|
|
}
|
|
|
|
|
|
VECCOPY(vec, bone->tail);
|
|
mul_m4_v3(ob->obmat, vec);
|
|
project_short_noclip(ar, vec, pval);
|
|
|
|
pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]);
|
|
|
|
if (pdist < *dist)
|
|
{
|
|
*dist = pdist;
|
|
pt = &boneSnap;
|
|
VECCOPY(pt->p, vec);
|
|
pt->type = PT_EXACT;
|
|
}
|
|
}
|
|
|
|
return pt;
|
|
}
|
|
#endif
|
|
|
|
void sk_resetOverdraw(SK_Sketch *sketch)
|
|
{
|
|
sketch->over.target = NULL;
|
|
sketch->over.start = -1;
|
|
sketch->over.end = -1;
|
|
sketch->over.count = 0;
|
|
}
|
|
|
|
int sk_hasOverdraw(SK_Sketch *sketch, SK_Stroke *stk)
|
|
{
|
|
return sketch->over.target &&
|
|
sketch->over.count >= SK_OVERDRAW_LIMIT &&
|
|
(sketch->over.target == stk || stk == NULL) &&
|
|
(sketch->over.start != -1 || sketch->over.end != -1);
|
|
}
|
|
|
|
static void sk_updateOverdraw(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd)
|
|
{
|
|
if (sketch->over.target == NULL)
|
|
{
|
|
SK_Stroke *target;
|
|
int closest_index = -1;
|
|
int dist = SNAP_MIN_DISTANCE * 2;
|
|
|
|
for (target = sketch->strokes.first; target; target = target->next)
|
|
{
|
|
if (target != stk)
|
|
{
|
|
int index;
|
|
|
|
SK_Point *spt = sk_snapPointStroke(C, target, dd->mval, &dist, &index, 1);
|
|
|
|
if (spt != NULL)
|
|
{
|
|
sketch->over.target = target;
|
|
closest_index = index;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (sketch->over.target != NULL)
|
|
{
|
|
if (closest_index > -1)
|
|
{
|
|
if (sk_lastStrokePoint(stk)->type == PT_EXACT)
|
|
{
|
|
sketch->over.count = SK_OVERDRAW_LIMIT;
|
|
}
|
|
else
|
|
{
|
|
sketch->over.count++;
|
|
}
|
|
}
|
|
|
|
if (stk->nb_points == 1)
|
|
{
|
|
sketch->over.start = closest_index;
|
|
}
|
|
else
|
|
{
|
|
sketch->over.end = closest_index;
|
|
}
|
|
}
|
|
}
|
|
else if (sketch->over.target != NULL)
|
|
{
|
|
SK_Point *closest_pt = NULL;
|
|
int dist = SNAP_MIN_DISTANCE * 2;
|
|
int index;
|
|
|
|
closest_pt = sk_snapPointStroke(C, sketch->over.target, dd->mval, &dist, &index, 1);
|
|
|
|
if (closest_pt != NULL)
|
|
{
|
|
if (sk_lastStrokePoint(stk)->type == PT_EXACT)
|
|
{
|
|
sketch->over.count = SK_OVERDRAW_LIMIT;
|
|
}
|
|
else
|
|
{
|
|
sketch->over.count++;
|
|
}
|
|
|
|
sketch->over.end = index;
|
|
}
|
|
else
|
|
{
|
|
sketch->over.end = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* return 1 on reverse needed */
|
|
static int sk_adjustIndexes(SK_Sketch *sketch, int *start, int *end)
|
|
{
|
|
int retval = 0;
|
|
|
|
*start = sketch->over.start;
|
|
*end = sketch->over.end;
|
|
|
|
if (*start == -1)
|
|
{
|
|
*start = 0;
|
|
}
|
|
|
|
if (*end == -1)
|
|
{
|
|
*end = sketch->over.target->nb_points - 1;
|
|
}
|
|
|
|
if (*end < *start)
|
|
{
|
|
int tmp = *start;
|
|
*start = *end;
|
|
*end = tmp;
|
|
retval = 1;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
static void sk_endOverdraw(SK_Sketch *sketch)
|
|
{
|
|
SK_Stroke *stk = sketch->active_stroke;
|
|
|
|
if (sk_hasOverdraw(sketch, NULL))
|
|
{
|
|
int start;
|
|
int end;
|
|
|
|
if (sk_adjustIndexes(sketch, &start, &end))
|
|
{
|
|
sk_reverseStroke(stk);
|
|
}
|
|
|
|
if (stk->nb_points > 1)
|
|
{
|
|
stk->points->type = sketch->over.target->points[start].type;
|
|
sk_lastStrokePoint(stk)->type = sketch->over.target->points[end].type;
|
|
}
|
|
|
|
sk_insertStrokePoints(sketch->over.target, stk->points, stk->nb_points, start, end);
|
|
|
|
sk_removeStroke(sketch, stk);
|
|
|
|
sk_resetOverdraw(sketch);
|
|
}
|
|
}
|
|
|
|
|
|
static void sk_startStroke(SK_Sketch *sketch)
|
|
{
|
|
SK_Stroke *stk = sk_createStroke();
|
|
|
|
BLI_addtail(&sketch->strokes, stk);
|
|
sketch->active_stroke = stk;
|
|
|
|
sk_resetOverdraw(sketch);
|
|
}
|
|
|
|
static void sk_endStroke(bContext *C, SK_Sketch *sketch)
|
|
{
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
|
sk_shrinkStrokeBuffer(sketch->active_stroke);
|
|
|
|
if (ts->bone_sketching & BONE_SKETCHING_ADJUST)
|
|
{
|
|
sk_endOverdraw(sketch);
|
|
}
|
|
|
|
sketch->active_stroke = NULL;
|
|
}
|
|
|
|
static void sk_updateDrawData(SK_DrawData *dd)
|
|
{
|
|
dd->type = PT_CONTINUOUS;
|
|
|
|
dd->previous_mval[0] = dd->mval[0];
|
|
dd->previous_mval[1] = dd->mval[1];
|
|
}
|
|
|
|
static float sk_distanceDepth(bContext *C, float p1[3], float p2[3])
|
|
{
|
|
ARegion *ar = CTX_wm_region(C);
|
|
RegionView3D *rv3d = ar->regiondata;
|
|
float vec[3];
|
|
float distance;
|
|
|
|
sub_v3_v3v3(vec, p1, p2);
|
|
|
|
project_v3_v3v3(vec, vec, rv3d->viewinv[2]);
|
|
|
|
distance = len_v3(vec);
|
|
|
|
if (dot_v3v3(rv3d->viewinv[2], vec) > 0)
|
|
{
|
|
distance *= -1;
|
|
}
|
|
|
|
return distance;
|
|
}
|
|
|
|
static void sk_interpolateDepth(bContext *C, SK_Stroke *stk, int start, int end, float length, float distance)
|
|
{
|
|
ARegion *ar = CTX_wm_region(C);
|
|
ScrArea *sa = CTX_wm_area(C);
|
|
View3D *v3d = sa->spacedata.first;
|
|
|
|
float progress = 0;
|
|
int i;
|
|
|
|
progress = len_v3v3(stk->points[start].p, stk->points[start - 1].p);
|
|
|
|
for (i = start; i <= end; i++)
|
|
{
|
|
float ray_start[3], ray_normal[3];
|
|
float delta = len_v3v3(stk->points[i].p, stk->points[i + 1].p);
|
|
float pval[2];
|
|
|
|
project_float(ar, stk->points[i].p, pval);
|
|
viewray(ar, v3d, pval, ray_start, ray_normal);
|
|
|
|
mul_v3_fl(ray_normal, distance * progress / length);
|
|
add_v3_v3(stk->points[i].p, ray_normal);
|
|
|
|
progress += delta ;
|
|
}
|
|
}
|
|
|
|
static void sk_projectDrawPoint(bContext *C, float vec[3], SK_Stroke *stk, SK_DrawData *dd)
|
|
{
|
|
ARegion *ar = CTX_wm_region(C);
|
|
/* copied from grease pencil, need fixing */
|
|
SK_Point *last = sk_lastStrokePoint(stk);
|
|
short cval[2];
|
|
float fp[3] = {0, 0, 0};
|
|
float dvec[3];
|
|
|
|
if (last != NULL)
|
|
{
|
|
VECCOPY(fp, last->p);
|
|
}
|
|
|
|
initgrabz(ar->regiondata, fp[0], fp[1], fp[2]);
|
|
|
|
/* method taken from editview.c - mouse_cursor() */
|
|
project_short_noclip(ar, fp, cval);
|
|
window_to_3d_delta(ar, dvec, cval[0] - dd->mval[0], cval[1] - dd->mval[1]);
|
|
sub_v3_v3v3(vec, fp, dvec);
|
|
}
|
|
|
|
static int sk_getStrokeDrawPoint(bContext *C, SK_Point *pt, SK_Sketch *UNUSED(sketch), SK_Stroke *stk, SK_DrawData *dd)
|
|
{
|
|
pt->type = dd->type;
|
|
pt->mode = PT_PROJECT;
|
|
sk_projectDrawPoint(C, pt->p, stk, dd);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int sk_addStrokeDrawPoint(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd)
|
|
{
|
|
ARegion *ar = CTX_wm_region(C);
|
|
RegionView3D *rv3d = ar->regiondata;
|
|
SK_Point pt;
|
|
|
|
sk_initPoint(&pt, dd, rv3d->viewinv[2]);
|
|
|
|
sk_getStrokeDrawPoint(C, &pt, sketch, stk, dd);
|
|
|
|
sk_appendStrokePoint(stk, &pt);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd)
|
|
{
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
|
int point_added = 0;
|
|
|
|
if (ts->snap_mode == SCE_SNAP_MODE_VOLUME)
|
|
{
|
|
DepthPeel *p1, *p2;
|
|
float *last_p = NULL;
|
|
float dist = FLT_MAX;
|
|
float p[3] = {0};
|
|
float size = 0;
|
|
float mvalf[2];
|
|
|
|
BLI_freelistN(&sketch->depth_peels);
|
|
sketch->depth_peels.first = sketch->depth_peels.last = NULL;
|
|
|
|
mvalf[0]= dd->mval[0];
|
|
mvalf[1]= dd->mval[1];
|
|
peelObjectsContext(C, &sketch->depth_peels, mvalf);
|
|
|
|
if (stk->nb_points > 0 && stk->points[stk->nb_points - 1].type == PT_CONTINUOUS)
|
|
{
|
|
last_p = stk->points[stk->nb_points - 1].p;
|
|
}
|
|
else if (LAST_SNAP_POINT_VALID)
|
|
{
|
|
last_p = LAST_SNAP_POINT;
|
|
}
|
|
|
|
|
|
for (p1 = sketch->depth_peels.first; p1; p1 = p1->next)
|
|
{
|
|
if (p1->flag == 0)
|
|
{
|
|
float vec[3];
|
|
float new_dist;
|
|
float new_size = 0;
|
|
|
|
p2 = NULL;
|
|
p1->flag = 1;
|
|
|
|
/* if peeling objects, take the first and last from each object */
|
|
if (ts->snap_flag & SCE_SNAP_PEEL_OBJECT)
|
|
{
|
|
DepthPeel *peel;
|
|
for (peel = p1->next; peel; peel = peel->next)
|
|
{
|
|
if (peel->ob == p1->ob)
|
|
{
|
|
peel->flag = 1;
|
|
p2 = peel;
|
|
}
|
|
}
|
|
}
|
|
/* otherwise, pair first with second and so on */
|
|
else
|
|
{
|
|
for (p2 = p1->next; p2 && p2->ob != p1->ob; p2 = p2->next)
|
|
{
|
|
/* nothing to do here */
|
|
}
|
|
}
|
|
|
|
if (p2)
|
|
{
|
|
p2->flag = 1;
|
|
|
|
add_v3_v3v3(vec, p1->p, p2->p);
|
|
mul_v3_fl(vec, 0.5f);
|
|
new_size = len_v3v3(p1->p, p2->p);
|
|
}
|
|
else
|
|
{
|
|
VECCOPY(vec, p1->p);
|
|
}
|
|
|
|
if (last_p == NULL)
|
|
{
|
|
VECCOPY(p, vec);
|
|
size = new_size;
|
|
dist = 0;
|
|
break;
|
|
}
|
|
|
|
new_dist = len_v3v3(last_p, vec);
|
|
|
|
if (new_dist < dist)
|
|
{
|
|
VECCOPY(p, vec);
|
|
dist = new_dist;
|
|
size = new_size;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dist != FLT_MAX)
|
|
{
|
|
pt->type = dd->type;
|
|
pt->mode = PT_SNAP;
|
|
pt->size = size / 2;
|
|
VECCOPY(pt->p, p);
|
|
|
|
point_added = 1;
|
|
}
|
|
|
|
//BLI_freelistN(&depth_peels);
|
|
}
|
|
else
|
|
{
|
|
SK_Stroke *snap_stk;
|
|
float vec[3];
|
|
float no[3];
|
|
float mval[2];
|
|
int found = 0;
|
|
int dist = SNAP_MIN_DISTANCE; // Use a user defined value here
|
|
|
|
/* snap to strokes */
|
|
// if (ts->snap_mode == SCE_SNAP_MODE_VERTEX) /* snap all the time to strokes */
|
|
for (snap_stk = sketch->strokes.first; snap_stk; snap_stk = snap_stk->next)
|
|
{
|
|
SK_Point *spt = NULL;
|
|
if (snap_stk == stk)
|
|
{
|
|
spt = sk_snapPointStroke(C, snap_stk, dd->mval, &dist, NULL, 0);
|
|
}
|
|
else
|
|
{
|
|
spt = sk_snapPointStroke(C, snap_stk, dd->mval, &dist, NULL, 1);
|
|
}
|
|
|
|
if (spt != NULL)
|
|
{
|
|
VECCOPY(pt->p, spt->p);
|
|
point_added = 1;
|
|
}
|
|
}
|
|
|
|
mval[0] = dd->mval[0];
|
|
mval[1] = dd->mval[1];
|
|
|
|
/* try to snap to closer object */
|
|
found = snapObjectsContext(C, mval, &dist, vec, no, SNAP_NOT_SELECTED);
|
|
if (found == 1)
|
|
{
|
|
pt->type = dd->type;
|
|
pt->mode = PT_SNAP;
|
|
VECCOPY(pt->p, vec);
|
|
|
|
point_added = 1;
|
|
}
|
|
}
|
|
|
|
return point_added;
|
|
}
|
|
|
|
static int sk_addStrokeSnapPoint(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd)
|
|
{
|
|
int point_added;
|
|
ARegion *ar = CTX_wm_region(C);
|
|
RegionView3D *rv3d = ar->regiondata;
|
|
SK_Point pt;
|
|
|
|
sk_initPoint(&pt, dd, rv3d->viewinv[2]);
|
|
|
|
point_added = sk_getStrokeSnapPoint(C, &pt, sketch, stk, dd);
|
|
|
|
if (point_added)
|
|
{
|
|
float final_p[3];
|
|
float length, distance;
|
|
int total;
|
|
int i;
|
|
|
|
VECCOPY(final_p, pt.p);
|
|
|
|
sk_projectDrawPoint(C, pt.p, stk, dd);
|
|
sk_appendStrokePoint(stk, &pt);
|
|
|
|
/* update all previous point to give smooth Z progresion */
|
|
total = 0;
|
|
length = 0;
|
|
for (i = stk->nb_points - 2; i > 0; i--)
|
|
{
|
|
length += len_v3v3(stk->points[i].p, stk->points[i + 1].p);
|
|
total++;
|
|
if (stk->points[i].mode == PT_SNAP || stk->points[i].type == PT_EXACT)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (total > 1)
|
|
{
|
|
distance = sk_distanceDepth(C, final_p, stk->points[i].p);
|
|
|
|
sk_interpolateDepth(C, stk, i + 1, stk->nb_points - 2, length, distance);
|
|
}
|
|
|
|
VECCOPY(stk->points[stk->nb_points - 1].p, final_p);
|
|
|
|
point_added = 1;
|
|
}
|
|
|
|
return point_added;
|
|
}
|
|
|
|
static void sk_addStrokePoint(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd, short snap)
|
|
{
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
|
int point_added = 0;
|
|
|
|
if (snap)
|
|
{
|
|
point_added = sk_addStrokeSnapPoint(C, sketch, stk, dd);
|
|
}
|
|
|
|
if (point_added == 0)
|
|
{
|
|
point_added = sk_addStrokeDrawPoint(C, sketch, stk, dd);
|
|
}
|
|
|
|
if (stk == sketch->active_stroke && ts->bone_sketching & BONE_SKETCHING_ADJUST)
|
|
{
|
|
sk_updateOverdraw(C, sketch, stk, dd);
|
|
}
|
|
}
|
|
|
|
static void sk_getStrokePoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd, short snap)
|
|
{
|
|
int point_added = 0;
|
|
|
|
if (snap)
|
|
{
|
|
point_added = sk_getStrokeSnapPoint(C, pt, sketch, stk, dd);
|
|
LAST_SNAP_POINT_VALID = 1;
|
|
VECCOPY(LAST_SNAP_POINT, pt->p);
|
|
}
|
|
else
|
|
{
|
|
LAST_SNAP_POINT_VALID = 0;
|
|
}
|
|
|
|
if (point_added == 0)
|
|
{
|
|
point_added = sk_getStrokeDrawPoint(C, pt, sketch, stk, dd);
|
|
}
|
|
}
|
|
|
|
/********************************************/
|
|
|
|
static void* headPoint(void *arg);
|
|
static void* tailPoint(void *arg);
|
|
static void* nextPoint(void *arg);
|
|
static void* nextNPoint(void *arg, int n);
|
|
static void* peekPoint(void *arg, int n);
|
|
static void* previousPoint(void *arg);
|
|
static int iteratorStopped(void *arg);
|
|
|
|
static void initIteratorFct(SK_StrokeIterator *iter)
|
|
{
|
|
iter->head = headPoint;
|
|
iter->tail = tailPoint;
|
|
iter->peek = peekPoint;
|
|
iter->next = nextPoint;
|
|
iter->nextN = nextNPoint;
|
|
iter->previous = previousPoint;
|
|
iter->stopped = iteratorStopped;
|
|
}
|
|
|
|
static SK_Point* setIteratorValues(SK_StrokeIterator *iter, int index)
|
|
{
|
|
SK_Point *pt = NULL;
|
|
|
|
if (index >= 0 && index < iter->length)
|
|
{
|
|
pt = &(iter->stroke->points[iter->start + (iter->stride * index)]);
|
|
iter->p = pt->p;
|
|
iter->no = pt->no;
|
|
iter->size = pt->size;
|
|
}
|
|
else
|
|
{
|
|
iter->p = NULL;
|
|
iter->no = NULL;
|
|
iter->size = 0;
|
|
}
|
|
|
|
return pt;
|
|
}
|
|
|
|
void initStrokeIterator(BArcIterator *arg, SK_Stroke *stk, int start, int end)
|
|
{
|
|
SK_StrokeIterator *iter = (SK_StrokeIterator*)arg;
|
|
|
|
initIteratorFct(iter);
|
|
iter->stroke = stk;
|
|
|
|
if (start < end)
|
|
{
|
|
iter->start = start + 1;
|
|
iter->end = end - 1;
|
|
iter->stride = 1;
|
|
}
|
|
else
|
|
{
|
|
iter->start = start - 1;
|
|
iter->end = end + 1;
|
|
iter->stride = -1;
|
|
}
|
|
|
|
iter->length = iter->stride * (iter->end - iter->start + 1);
|
|
|
|
iter->index = -1;
|
|
}
|
|
|
|
|
|
static void* headPoint(void *arg)
|
|
{
|
|
SK_StrokeIterator *iter = (SK_StrokeIterator*)arg;
|
|
SK_Point *result = NULL;
|
|
|
|
result = &(iter->stroke->points[iter->start - iter->stride]);
|
|
iter->p = result->p;
|
|
iter->no = result->no;
|
|
iter->size = result->size;
|
|
|
|
return result;
|
|
}
|
|
|
|
static void* tailPoint(void *arg)
|
|
{
|
|
SK_StrokeIterator *iter = (SK_StrokeIterator*)arg;
|
|
SK_Point *result = NULL;
|
|
|
|
result = &(iter->stroke->points[iter->end + iter->stride]);
|
|
iter->p = result->p;
|
|
iter->no = result->no;
|
|
iter->size = result->size;
|
|
|
|
return result;
|
|
}
|
|
|
|
static void* nextPoint(void *arg)
|
|
{
|
|
SK_StrokeIterator *iter = (SK_StrokeIterator*)arg;
|
|
SK_Point *result = NULL;
|
|
|
|
iter->index++;
|
|
if (iter->index < iter->length)
|
|
{
|
|
result = setIteratorValues(iter, iter->index);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static void* nextNPoint(void *arg, int n)
|
|
{
|
|
SK_StrokeIterator *iter = (SK_StrokeIterator*)arg;
|
|
SK_Point *result = NULL;
|
|
|
|
iter->index += n;
|
|
|
|
/* check if passed end */
|
|
if (iter->index < iter->length)
|
|
{
|
|
result = setIteratorValues(iter, iter->index);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static void* peekPoint(void *arg, int n)
|
|
{
|
|
SK_StrokeIterator *iter = (SK_StrokeIterator*)arg;
|
|
SK_Point *result = NULL;
|
|
int index = iter->index + n;
|
|
|
|
/* check if passed end */
|
|
if (index < iter->length)
|
|
{
|
|
result = setIteratorValues(iter, index);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static void* previousPoint(void *arg)
|
|
{
|
|
SK_StrokeIterator *iter = (SK_StrokeIterator*)arg;
|
|
SK_Point *result = NULL;
|
|
|
|
if (iter->index > 0)
|
|
{
|
|
iter->index--;
|
|
result = setIteratorValues(iter, iter->index);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static int iteratorStopped(void *arg)
|
|
{
|
|
SK_StrokeIterator *iter = (SK_StrokeIterator*)arg;
|
|
|
|
if (iter->index >= iter->length)
|
|
{
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static void sk_convertStroke(bContext *C, SK_Stroke *stk)
|
|
{
|
|
Object *obedit = CTX_data_edit_object(C);
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
|
bArmature *arm = obedit->data;
|
|
SK_Point *head;
|
|
EditBone *parent = NULL;
|
|
float invmat[4][4]; /* move in caller function */
|
|
float tmat[3][3];
|
|
int head_index = 0;
|
|
int i;
|
|
|
|
head = NULL;
|
|
|
|
invert_m4_m4(invmat, obedit->obmat);
|
|
|
|
copy_m3_m4(tmat, obedit->obmat);
|
|
transpose_m3(tmat);
|
|
|
|
for (i = 0; i < stk->nb_points; i++)
|
|
{
|
|
SK_Point *pt = stk->points + i;
|
|
|
|
if (pt->type == PT_EXACT)
|
|
{
|
|
if (head == NULL)
|
|
{
|
|
head_index = i;
|
|
head = pt;
|
|
}
|
|
else
|
|
{
|
|
EditBone *bone = NULL;
|
|
EditBone *new_parent;
|
|
|
|
if (i - head_index > 1)
|
|
{
|
|
SK_StrokeIterator sk_iter;
|
|
BArcIterator *iter = (BArcIterator*)&sk_iter;
|
|
|
|
initStrokeIterator(iter, stk, head_index, i);
|
|
|
|
if (ts->bone_sketching_convert == SK_CONVERT_CUT_ADAPTATIVE)
|
|
{
|
|
bone = subdivideArcBy(ts, arm, arm->edbo, iter, invmat, tmat, nextAdaptativeSubdivision);
|
|
}
|
|
else if (ts->bone_sketching_convert == SK_CONVERT_CUT_LENGTH)
|
|
{
|
|
bone = subdivideArcBy(ts, arm, arm->edbo, iter, invmat, tmat, nextLengthSubdivision);
|
|
}
|
|
else if (ts->bone_sketching_convert == SK_CONVERT_CUT_FIXED)
|
|
{
|
|
bone = subdivideArcBy(ts, arm, arm->edbo, iter, invmat, tmat, nextFixedSubdivision);
|
|
}
|
|
}
|
|
|
|
if (bone == NULL)
|
|
{
|
|
bone = ED_armature_edit_bone_add(arm, "Bone");
|
|
|
|
VECCOPY(bone->head, head->p);
|
|
VECCOPY(bone->tail, pt->p);
|
|
|
|
mul_m4_v3(invmat, bone->head);
|
|
mul_m4_v3(invmat, bone->tail);
|
|
setBoneRollFromNormal(bone, head->no, invmat, tmat);
|
|
}
|
|
|
|
new_parent = bone;
|
|
bone->flag |= BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
|
|
|
|
/* move to end of chain */
|
|
while (bone->parent != NULL)
|
|
{
|
|
bone = bone->parent;
|
|
bone->flag |= BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
|
|
}
|
|
|
|
if (parent != NULL)
|
|
{
|
|
bone->parent = parent;
|
|
bone->flag |= BONE_CONNECTED;
|
|
}
|
|
|
|
parent = new_parent;
|
|
head_index = i;
|
|
head = pt;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void sk_convert(bContext *C, SK_Sketch *sketch)
|
|
{
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
|
SK_Stroke *stk;
|
|
|
|
for (stk = sketch->strokes.first; stk; stk = stk->next)
|
|
{
|
|
if (stk->selected == 1)
|
|
{
|
|
if (ts->bone_sketching_convert == SK_CONVERT_RETARGET)
|
|
{
|
|
sk_retargetStroke(C, stk);
|
|
}
|
|
else
|
|
{
|
|
sk_convertStroke(C, stk);
|
|
}
|
|
// XXX
|
|
// allqueue(REDRAWBUTSEDIT, 0);
|
|
}
|
|
}
|
|
}
|
|
/******************* GESTURE *************************/
|
|
|
|
|
|
/* returns the number of self intersections */
|
|
static int sk_getSelfIntersections(bContext *C, ListBase *list, SK_Stroke *gesture)
|
|
{
|
|
ARegion *ar = CTX_wm_region(C);
|
|
int added = 0;
|
|
int s_i;
|
|
|
|
for (s_i = 0; s_i < gesture->nb_points - 1; s_i++)
|
|
{
|
|
float s_p1[3] = {0, 0, 0};
|
|
float s_p2[3] = {0, 0, 0};
|
|
int g_i;
|
|
|
|
project_float(ar, gesture->points[s_i].p, s_p1);
|
|
project_float(ar, gesture->points[s_i + 1].p, s_p2);
|
|
|
|
/* start checking from second next, because two consecutive cannot intersect */
|
|
for (g_i = s_i + 2; g_i < gesture->nb_points - 1; g_i++)
|
|
{
|
|
float g_p1[3] = {0, 0, 0};
|
|
float g_p2[3] = {0, 0, 0};
|
|
float vi[3];
|
|
float lambda;
|
|
|
|
project_float(ar, gesture->points[g_i].p, g_p1);
|
|
project_float(ar, gesture->points[g_i + 1].p, g_p2);
|
|
|
|
if (isect_line_line_strict_v3(s_p1, s_p2, g_p1, g_p2, vi, &lambda))
|
|
{
|
|
SK_Intersection *isect = MEM_callocN(sizeof(SK_Intersection), "Intersection");
|
|
|
|
isect->gesture_index = g_i;
|
|
isect->before = s_i;
|
|
isect->after = s_i + 1;
|
|
isect->stroke = gesture;
|
|
|
|
sub_v3_v3v3(isect->p, gesture->points[s_i + 1].p, gesture->points[s_i].p);
|
|
mul_v3_fl(isect->p, lambda);
|
|
add_v3_v3(isect->p, gesture->points[s_i].p);
|
|
|
|
BLI_addtail(list, isect);
|
|
|
|
added++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return added;
|
|
}
|
|
|
|
static int cmpIntersections(void *i1, void *i2)
|
|
{
|
|
SK_Intersection *isect1 = i1, *isect2 = i2;
|
|
|
|
if (isect1->stroke == isect2->stroke)
|
|
{
|
|
if (isect1->before < isect2->before)
|
|
{
|
|
return -1;
|
|
}
|
|
else if (isect1->before > isect2->before)
|
|
{
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
if (isect1->lambda < isect2->lambda)
|
|
{
|
|
return -1;
|
|
}
|
|
else if (isect1->lambda > isect2->lambda)
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* returns the maximum number of intersections per stroke */
|
|
static int sk_getIntersections(bContext *C, ListBase *list, SK_Sketch *sketch, SK_Stroke *gesture)
|
|
{
|
|
ARegion *ar = CTX_wm_region(C);
|
|
ScrArea *sa = CTX_wm_area(C);
|
|
View3D *v3d = sa->spacedata.first;
|
|
SK_Stroke *stk;
|
|
int added = 0;
|
|
|
|
for (stk = sketch->strokes.first; stk; stk = stk->next)
|
|
{
|
|
int s_added = 0;
|
|
int s_i;
|
|
|
|
for (s_i = 0; s_i < stk->nb_points - 1; s_i++)
|
|
{
|
|
float s_p1[3] = {0, 0, 0};
|
|
float s_p2[3] = {0, 0, 0};
|
|
int g_i;
|
|
|
|
project_float(ar, stk->points[s_i].p, s_p1);
|
|
project_float(ar, stk->points[s_i + 1].p, s_p2);
|
|
|
|
for (g_i = 0; g_i < gesture->nb_points - 1; g_i++)
|
|
{
|
|
float g_p1[3] = {0, 0, 0};
|
|
float g_p2[3] = {0, 0, 0};
|
|
float vi[3];
|
|
float lambda;
|
|
|
|
project_float(ar, gesture->points[g_i].p, g_p1);
|
|
project_float(ar, gesture->points[g_i + 1].p, g_p2);
|
|
|
|
if (isect_line_line_strict_v3(s_p1, s_p2, g_p1, g_p2, vi, &lambda))
|
|
{
|
|
SK_Intersection *isect = MEM_callocN(sizeof(SK_Intersection), "Intersection");
|
|
float ray_start[3], ray_end[3];
|
|
float mval[2];
|
|
|
|
isect->gesture_index = g_i;
|
|
isect->before = s_i;
|
|
isect->after = s_i + 1;
|
|
isect->stroke = stk;
|
|
isect->lambda = lambda;
|
|
|
|
mval[0] = vi[0];
|
|
mval[1] = vi[1];
|
|
viewline(ar, v3d, mval, ray_start, ray_end);
|
|
|
|
isect_line_line_v3( stk->points[s_i].p,
|
|
stk->points[s_i + 1].p,
|
|
ray_start,
|
|
ray_end,
|
|
isect->p,
|
|
vi);
|
|
|
|
BLI_addtail(list, isect);
|
|
|
|
s_added++;
|
|
}
|
|
}
|
|
}
|
|
|
|
added = MAX2(s_added, added);
|
|
}
|
|
|
|
BLI_sortlist(list, cmpIntersections);
|
|
|
|
return added;
|
|
}
|
|
|
|
static int sk_getSegments(SK_Stroke *segments, SK_Stroke *gesture)
|
|
{
|
|
SK_StrokeIterator sk_iter;
|
|
BArcIterator *iter = (BArcIterator*)&sk_iter;
|
|
|
|
float CORRELATION_THRESHOLD = 0.99f;
|
|
float *vec;
|
|
int i, j;
|
|
|
|
sk_appendStrokePoint(segments, &gesture->points[0]);
|
|
vec = segments->points[segments->nb_points - 1].p;
|
|
|
|
initStrokeIterator(iter, gesture, 0, gesture->nb_points - 1);
|
|
|
|
for (i = 1, j = 0; i < gesture->nb_points; i++)
|
|
{
|
|
float n[3];
|
|
|
|
/* Calculate normal */
|
|
sub_v3_v3v3(n, gesture->points[i].p, vec);
|
|
|
|
if (calcArcCorrelation(iter, j, i, vec, n) < CORRELATION_THRESHOLD)
|
|
{
|
|
j = i - 1;
|
|
sk_appendStrokePoint(segments, &gesture->points[j]);
|
|
vec = segments->points[segments->nb_points - 1].p;
|
|
segments->points[segments->nb_points - 1].type = PT_EXACT;
|
|
}
|
|
}
|
|
|
|
sk_appendStrokePoint(segments, &gesture->points[gesture->nb_points - 1]);
|
|
|
|
return segments->nb_points - 1;
|
|
}
|
|
|
|
int sk_detectCutGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
|
|
{
|
|
if (gest->nb_segments == 1 && gest->nb_intersections == 1)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void sk_applyCutGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
|
|
{
|
|
SK_Intersection *isect;
|
|
|
|
for (isect = gest->intersections.first; isect; isect = isect->next)
|
|
{
|
|
SK_Point pt;
|
|
|
|
pt.type = PT_EXACT;
|
|
pt.mode = PT_PROJECT; /* take mode from neighbouring points */
|
|
VECCOPY(pt.p, isect->p);
|
|
VECCOPY(pt.no, isect->stroke->points[isect->before].no);
|
|
|
|
sk_insertStrokePoint(isect->stroke, &pt, isect->after);
|
|
}
|
|
}
|
|
|
|
int sk_detectTrimGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
|
|
{
|
|
if (gest->nb_segments == 2 && gest->nb_intersections == 1 && gest->nb_self_intersections == 0)
|
|
{
|
|
float s1[3], s2[3];
|
|
float angle;
|
|
|
|
sub_v3_v3v3(s1, gest->segments->points[1].p, gest->segments->points[0].p);
|
|
sub_v3_v3v3(s2, gest->segments->points[2].p, gest->segments->points[1].p);
|
|
|
|
angle = RAD2DEG(angle_v2v2(s1, s2));
|
|
|
|
if (angle > 60 && angle < 120)
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void sk_applyTrimGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
|
|
{
|
|
SK_Intersection *isect;
|
|
float trim_dir[3];
|
|
|
|
sub_v3_v3v3(trim_dir, gest->segments->points[2].p, gest->segments->points[1].p);
|
|
|
|
for (isect = gest->intersections.first; isect; isect = isect->next)
|
|
{
|
|
SK_Point pt;
|
|
float stroke_dir[3];
|
|
|
|
pt.type = PT_EXACT;
|
|
pt.mode = PT_PROJECT; /* take mode from neighbouring points */
|
|
VECCOPY(pt.p, isect->p);
|
|
VECCOPY(pt.no, isect->stroke->points[isect->before].no);
|
|
|
|
sub_v3_v3v3(stroke_dir, isect->stroke->points[isect->after].p, isect->stroke->points[isect->before].p);
|
|
|
|
/* same direction, trim end */
|
|
if (dot_v3v3(stroke_dir, trim_dir) > 0)
|
|
{
|
|
sk_replaceStrokePoint(isect->stroke, &pt, isect->after);
|
|
sk_trimStroke(isect->stroke, 0, isect->after);
|
|
}
|
|
/* else, trim start */
|
|
else
|
|
{
|
|
sk_replaceStrokePoint(isect->stroke, &pt, isect->before);
|
|
sk_trimStroke(isect->stroke, isect->before, isect->stroke->nb_points - 1);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
int sk_detectCommandGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
|
|
{
|
|
if (gest->nb_segments > 2 && gest->nb_intersections == 2 && gest->nb_self_intersections == 1)
|
|
{
|
|
SK_Intersection *isect, *self_isect;
|
|
|
|
/* get the the last intersection of the first pair */
|
|
for( isect = gest->intersections.first; isect; isect = isect->next )
|
|
{
|
|
if (isect->stroke == isect->next->stroke)
|
|
{
|
|
isect = isect->next;
|
|
break;
|
|
}
|
|
}
|
|
|
|
self_isect = gest->self_intersections.first;
|
|
|
|
if (isect && isect->gesture_index < self_isect->gesture_index)
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void sk_applyCommandGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
|
|
{
|
|
SK_Intersection *isect;
|
|
int command = 1;
|
|
|
|
// XXX
|
|
// command = pupmenu("Action %t|Flatten %x1|Straighten %x2|Polygonize %x3");
|
|
if(command < 1) return;
|
|
|
|
for (isect = gest->intersections.first; isect; isect = isect->next)
|
|
{
|
|
SK_Intersection *i2;
|
|
|
|
i2 = isect->next;
|
|
|
|
if (i2 && i2->stroke == isect->stroke)
|
|
{
|
|
switch (command)
|
|
{
|
|
case 1:
|
|
sk_flattenStroke(isect->stroke, isect->before, i2->after);
|
|
break;
|
|
case 2:
|
|
sk_straightenStroke(isect->stroke, isect->before, i2->after, isect->p, i2->p);
|
|
break;
|
|
case 3:
|
|
sk_polygonizeStroke(isect->stroke, isect->before, i2->after);
|
|
break;
|
|
}
|
|
|
|
isect = i2;
|
|
}
|
|
}
|
|
}
|
|
|
|
int sk_detectDeleteGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
|
|
{
|
|
if (gest->nb_segments == 2 && gest->nb_intersections == 2)
|
|
{
|
|
float s1[3], s2[3];
|
|
float angle;
|
|
|
|
sub_v3_v3v3(s1, gest->segments->points[1].p, gest->segments->points[0].p);
|
|
sub_v3_v3v3(s2, gest->segments->points[2].p, gest->segments->points[1].p);
|
|
|
|
angle = RAD2DEG(angle_v2v2(s1, s2));
|
|
|
|
if (angle > 120)
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void sk_applyDeleteGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *sketch)
|
|
{
|
|
SK_Intersection *isect;
|
|
|
|
for (isect = gest->intersections.first; isect; isect = isect->next)
|
|
{
|
|
/* only delete strokes that are crossed twice */
|
|
if (isect->next && isect->next->stroke == isect->stroke)
|
|
{
|
|
isect = isect->next;
|
|
|
|
sk_removeStroke(sketch, isect->stroke);
|
|
}
|
|
}
|
|
}
|
|
|
|
int sk_detectMergeGesture(bContext *C, SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
|
|
{
|
|
ARegion *ar = CTX_wm_region(C);
|
|
if (gest->nb_segments > 2 && gest->nb_intersections == 2)
|
|
{
|
|
short start_val[2], end_val[2];
|
|
short dist;
|
|
|
|
project_short_noclip(ar, gest->stk->points[0].p, start_val);
|
|
project_short_noclip(ar, sk_lastStrokePoint(gest->stk)->p, end_val);
|
|
|
|
dist = MAX2(ABS(start_val[0] - end_val[0]), ABS(start_val[1] - end_val[1]));
|
|
|
|
/* if gesture is a circle */
|
|
if ( dist <= 20 )
|
|
{
|
|
SK_Intersection *isect;
|
|
|
|
/* check if it circled around an exact point */
|
|
for (isect = gest->intersections.first; isect; isect = isect->next)
|
|
{
|
|
/* only delete strokes that are crossed twice */
|
|
if (isect->next && isect->next->stroke == isect->stroke)
|
|
{
|
|
int start_index, end_index;
|
|
int i;
|
|
|
|
start_index = MIN2(isect->after, isect->next->after);
|
|
end_index = MAX2(isect->before, isect->next->before);
|
|
|
|
for (i = start_index; i <= end_index; i++)
|
|
{
|
|
if (isect->stroke->points[i].type == PT_EXACT)
|
|
{
|
|
return 1; /* at least one exact point found, stop detect here */
|
|
}
|
|
}
|
|
|
|
/* skip next */
|
|
isect = isect->next;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void sk_applyMergeGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
|
|
{
|
|
SK_Intersection *isect;
|
|
|
|
/* check if it circled around an exact point */
|
|
for (isect = gest->intersections.first; isect; isect = isect->next)
|
|
{
|
|
/* only merge strokes that are crossed twice */
|
|
if (isect->next && isect->next->stroke == isect->stroke)
|
|
{
|
|
int start_index, end_index;
|
|
int i;
|
|
|
|
start_index = MIN2(isect->after, isect->next->after);
|
|
end_index = MAX2(isect->before, isect->next->before);
|
|
|
|
for (i = start_index; i <= end_index; i++)
|
|
{
|
|
/* if exact, switch to continuous */
|
|
if (isect->stroke->points[i].type == PT_EXACT)
|
|
{
|
|
isect->stroke->points[i].type = PT_CONTINUOUS;
|
|
}
|
|
}
|
|
|
|
/* skip next */
|
|
isect = isect->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
int sk_detectReverseGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
|
|
{
|
|
if (gest->nb_segments > 2 && gest->nb_intersections == 2 && gest->nb_self_intersections == 0)
|
|
{
|
|
SK_Intersection *isect;
|
|
|
|
/* check if it circled around an exact point */
|
|
for (isect = gest->intersections.first; isect; isect = isect->next)
|
|
{
|
|
/* only delete strokes that are crossed twice */
|
|
if (isect->next && isect->next->stroke == isect->stroke)
|
|
{
|
|
float start_v[3], end_v[3];
|
|
float angle;
|
|
|
|
if (isect->gesture_index < isect->next->gesture_index)
|
|
{
|
|
sub_v3_v3v3(start_v, isect->p, gest->stk->points[0].p);
|
|
sub_v3_v3v3(end_v, sk_lastStrokePoint(gest->stk)->p, isect->next->p);
|
|
}
|
|
else
|
|
{
|
|
sub_v3_v3v3(start_v, isect->next->p, gest->stk->points[0].p);
|
|
sub_v3_v3v3(end_v, sk_lastStrokePoint(gest->stk)->p, isect->p);
|
|
}
|
|
|
|
angle = RAD2DEG(angle_v2v2(start_v, end_v));
|
|
|
|
if (angle > 120)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
/* skip next */
|
|
isect = isect->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void sk_applyReverseGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
|
|
{
|
|
SK_Intersection *isect;
|
|
|
|
for (isect = gest->intersections.first; isect; isect = isect->next)
|
|
{
|
|
/* only reverse strokes that are crossed twice */
|
|
if (isect->next && isect->next->stroke == isect->stroke)
|
|
{
|
|
sk_reverseStroke(isect->stroke);
|
|
|
|
/* skip next */
|
|
isect = isect->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
int sk_detectConvertGesture(bContext *UNUSED(C), SK_Gesture *gest, SK_Sketch *UNUSED(sketch))
|
|
{
|
|
if (gest->nb_segments == 3 && gest->nb_self_intersections == 1)
|
|
{
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void sk_applyConvertGesture(bContext *C, SK_Gesture *UNUSED(gest), SK_Sketch *sketch)
|
|
{
|
|
sk_convert(C, sketch);
|
|
}
|
|
|
|
static void sk_initGesture(bContext *C, SK_Gesture *gest, SK_Sketch *sketch)
|
|
{
|
|
gest->intersections.first = gest->intersections.last = NULL;
|
|
gest->self_intersections.first = gest->self_intersections.last = NULL;
|
|
|
|
gest->segments = sk_createStroke();
|
|
gest->stk = sketch->gesture;
|
|
|
|
gest->nb_self_intersections = sk_getSelfIntersections(C, &gest->self_intersections, gest->stk);
|
|
gest->nb_intersections = sk_getIntersections(C, &gest->intersections, sketch, gest->stk);
|
|
gest->nb_segments = sk_getSegments(gest->segments, gest->stk);
|
|
}
|
|
|
|
static void sk_freeGesture(SK_Gesture *gest)
|
|
{
|
|
sk_freeStroke(gest->segments);
|
|
BLI_freelistN(&gest->intersections);
|
|
BLI_freelistN(&gest->self_intersections);
|
|
}
|
|
|
|
static void sk_applyGesture(bContext *C, SK_Sketch *sketch)
|
|
{
|
|
SK_Gesture gest;
|
|
SK_GestureAction *act;
|
|
|
|
sk_initGesture(C, &gest, sketch);
|
|
|
|
/* detect and apply */
|
|
for (act = GESTURE_ACTIONS; act->apply != NULL; act++)
|
|
{
|
|
if (act->detect(C, &gest, sketch))
|
|
{
|
|
act->apply(C, &gest, sketch);
|
|
break;
|
|
}
|
|
}
|
|
|
|
sk_freeGesture(&gest);
|
|
}
|
|
|
|
/********************************************/
|
|
|
|
|
|
static int sk_selectStroke(bContext *C, SK_Sketch *sketch, short mval[2], int extend)
|
|
{
|
|
ViewContext vc;
|
|
rcti rect;
|
|
unsigned int buffer[MAXPICKBUF];
|
|
short hits;
|
|
|
|
view3d_set_viewcontext(C, &vc);
|
|
|
|
rect.xmin= mval[0]-5;
|
|
rect.xmax= mval[0]+5;
|
|
rect.ymin= mval[1]-5;
|
|
rect.ymax= mval[1]+5;
|
|
|
|
hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
|
|
|
|
if (hits>0)
|
|
{
|
|
int besthitresult = -1;
|
|
|
|
if(hits == 1) {
|
|
besthitresult = buffer[3];
|
|
}
|
|
else {
|
|
besthitresult = buffer[3];
|
|
/* loop and get best hit */
|
|
}
|
|
|
|
if (besthitresult > 0)
|
|
{
|
|
SK_Stroke *selected_stk = BLI_findlink(&sketch->strokes, besthitresult - 1);
|
|
|
|
if (extend == 0)
|
|
{
|
|
sk_selectAllSketch(sketch, -1);
|
|
|
|
selected_stk->selected = 1;
|
|
}
|
|
else
|
|
{
|
|
selected_stk->selected ^= 1;
|
|
}
|
|
|
|
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if 0 /* UNUSED 2.5 */
|
|
static void sk_queueRedrawSketch(SK_Sketch *sketch)
|
|
{
|
|
if (sketch->active_stroke != NULL)
|
|
{
|
|
SK_Point *last = sk_lastStrokePoint(sketch->active_stroke);
|
|
|
|
if (last != NULL)
|
|
{
|
|
// XXX
|
|
// allqueue(REDRAWVIEW3D, 0);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static void sk_drawSketch(Scene *scene, View3D *UNUSED(v3d), SK_Sketch *sketch, int with_names)
|
|
{
|
|
ToolSettings *ts= scene->toolsettings;
|
|
SK_Stroke *stk;
|
|
|
|
glClear(GL_DEPTH_BUFFER_BIT);
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
if (with_names)
|
|
{
|
|
int id;
|
|
for (id = 1, stk = sketch->strokes.first; stk; id++, stk = stk->next)
|
|
{
|
|
sk_drawStroke(stk, id, NULL, -1, -1);
|
|
}
|
|
|
|
glLoadName(-1);
|
|
}
|
|
else
|
|
{
|
|
float selected_rgb[3] = {1, 0, 0};
|
|
float unselected_rgb[3] = {1, 0.5, 0};
|
|
|
|
for (stk = sketch->strokes.first; stk; stk = stk->next)
|
|
{
|
|
int start = -1;
|
|
int end = -1;
|
|
|
|
if (sk_hasOverdraw(sketch, stk))
|
|
{
|
|
sk_adjustIndexes(sketch, &start, &end);
|
|
}
|
|
|
|
sk_drawStroke(stk, -1, (stk->selected==1?selected_rgb:unselected_rgb), start, end);
|
|
|
|
if (stk->selected == 1)
|
|
{
|
|
sk_drawStrokeSubdivision(ts, stk);
|
|
}
|
|
}
|
|
|
|
if (sketch->active_stroke != NULL)
|
|
{
|
|
SK_Point *last = sk_lastStrokePoint(sketch->active_stroke);
|
|
|
|
if (ts->bone_sketching & BONE_SKETCHING_QUICK)
|
|
{
|
|
sk_drawStrokeSubdivision(ts, sketch->active_stroke);
|
|
}
|
|
|
|
if (last != NULL)
|
|
{
|
|
GLUquadric *quad = gluNewQuadric();
|
|
gluQuadricNormals(quad, GLU_SMOOTH);
|
|
|
|
glPushMatrix();
|
|
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
switch (sketch->next_point.mode)
|
|
{
|
|
case PT_SNAP:
|
|
glColor3f(0, 1, 0);
|
|
break;
|
|
case PT_PROJECT:
|
|
glColor3f(0, 0, 0);
|
|
break;
|
|
}
|
|
|
|
sk_drawPoint(quad, &sketch->next_point, 0.1);
|
|
|
|
glColor4f(selected_rgb[0], selected_rgb[1], selected_rgb[2], 0.3);
|
|
|
|
sk_drawEdge(quad, last, &sketch->next_point, 0.1);
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
glPopMatrix();
|
|
|
|
gluDeleteQuadric(quad);
|
|
}
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
if (sketch->depth_peels.first != NULL)
|
|
{
|
|
float colors[8][3] = {
|
|
{1, 0, 0},
|
|
{0, 1, 0},
|
|
{0, 0, 1},
|
|
{1, 1, 0},
|
|
{1, 0, 1},
|
|
{0, 1, 1},
|
|
{1, 1, 1},
|
|
{0, 0, 0}
|
|
};
|
|
DepthPeel *p;
|
|
GLUquadric *quad = gluNewQuadric();
|
|
gluQuadricNormals(quad, GLU_SMOOTH);
|
|
|
|
for (p = sketch->depth_peels.first; p; p = p->next)
|
|
{
|
|
int index = GET_INT_FROM_POINTER(p->ob);
|
|
index = (index >> 5) & 7;
|
|
|
|
glColor3fv(colors[index]);
|
|
glPushMatrix();
|
|
glTranslatef(p->p[0], p->p[1], p->p[2]);
|
|
gluSphere(quad, 0.02, 8, 8);
|
|
glPopMatrix();
|
|
}
|
|
|
|
gluDeleteQuadric(quad);
|
|
}
|
|
#endif
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
/* only draw gesture in active area */
|
|
if (sketch->gesture != NULL /*&& area_is_active_area(G.vd->area)*/)
|
|
{
|
|
float gesture_rgb[3] = {0, 0.5, 1};
|
|
sk_drawStroke(sketch->gesture, -1, gesture_rgb, -1, -1);
|
|
}
|
|
}
|
|
|
|
static int sk_finish_stroke(bContext *C, SK_Sketch *sketch)
|
|
{
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
|
|
|
if (sketch->active_stroke != NULL)
|
|
{
|
|
SK_Stroke *stk = sketch->active_stroke;
|
|
|
|
sk_endStroke(C, sketch);
|
|
|
|
if (ts->bone_sketching & BONE_SKETCHING_QUICK)
|
|
{
|
|
if (ts->bone_sketching_convert == SK_CONVERT_RETARGET)
|
|
{
|
|
sk_retargetStroke(C, stk);
|
|
}
|
|
else
|
|
{
|
|
sk_convertStroke(C, stk);
|
|
}
|
|
// XXX
|
|
// BIF_undo_push("Convert Sketch");
|
|
sk_removeStroke(sketch, stk);
|
|
// XXX
|
|
// allqueue(REDRAWBUTSEDIT, 0);
|
|
}
|
|
|
|
// XXX
|
|
// allqueue(REDRAWVIEW3D, 0);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void sk_start_draw_stroke(SK_Sketch *sketch)
|
|
{
|
|
if (sketch->active_stroke == NULL)
|
|
{
|
|
sk_startStroke(sketch);
|
|
sk_selectAllSketch(sketch, -1);
|
|
|
|
sketch->active_stroke->selected = 1;
|
|
}
|
|
}
|
|
|
|
static void sk_start_draw_gesture(SK_Sketch *sketch)
|
|
{
|
|
sketch->gesture = sk_createStroke();
|
|
}
|
|
|
|
static int sk_draw_stroke(bContext *C, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd, short snap)
|
|
{
|
|
if (sk_stroke_filtermval(dd))
|
|
{
|
|
sk_addStrokePoint(C, sketch, stk, dd, snap);
|
|
sk_updateDrawData(dd);
|
|
sk_updateNextPoint(sketch, stk);
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ValidSketchViewContext(ViewContext *vc)
|
|
{
|
|
Object *obedit = vc->obedit;
|
|
Scene *scene= vc->scene;
|
|
|
|
if (obedit &&
|
|
obedit->type == OB_ARMATURE &&
|
|
scene->toolsettings->bone_sketching & BONE_SKETCHING)
|
|
{
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int BDR_drawSketchNames(ViewContext *vc)
|
|
{
|
|
if (ValidSketchViewContext(vc))
|
|
{
|
|
SK_Sketch *sketch = viewcontextSketch(vc, 0);
|
|
if (sketch)
|
|
{
|
|
sk_drawSketch(vc->scene, vc->v3d, sketch, 1);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void BDR_drawSketch(const bContext *C)
|
|
{
|
|
if (ED_operator_sketch_mode(C))
|
|
{
|
|
SK_Sketch *sketch = contextSketch(C, 0);
|
|
if (sketch)
|
|
{
|
|
sk_drawSketch(CTX_data_scene(C), CTX_wm_view3d(C), sketch, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int sketch_delete(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
|
|
{
|
|
SK_Sketch *sketch = contextSketch(C, 0);
|
|
if (sketch)
|
|
{
|
|
sk_deleteSelectedStrokes(sketch);
|
|
// allqueue(REDRAWVIEW3D, 0);
|
|
}
|
|
WM_event_add_notifier(C, NC_SCREEN|ND_SKETCH|NA_REMOVED, NULL);
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void BIF_sk_selectStroke(bContext *C, short mval[2], short extend)
|
|
{
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
|
SK_Sketch *sketch = contextSketch(C, 0);
|
|
|
|
if (sketch != NULL && ts->bone_sketching & BONE_SKETCHING)
|
|
{
|
|
if (sk_selectStroke(C, sketch, mval, extend))
|
|
ED_area_tag_redraw(CTX_wm_area(C));
|
|
}
|
|
}
|
|
|
|
void BIF_convertSketch(bContext *C)
|
|
{
|
|
if (ED_operator_sketch_full_mode(C))
|
|
{
|
|
SK_Sketch *sketch = contextSketch(C, 0);
|
|
if (sketch)
|
|
{
|
|
sk_convert(C, sketch);
|
|
// BIF_undo_push("Convert Sketch");
|
|
// allqueue(REDRAWVIEW3D, 0);
|
|
// allqueue(REDRAWBUTSEDIT, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void BIF_deleteSketch(bContext *C)
|
|
{
|
|
if (ED_operator_sketch_full_mode(C))
|
|
{
|
|
SK_Sketch *sketch = contextSketch(C, 0);
|
|
if (sketch)
|
|
{
|
|
sk_deleteSelectedStrokes(sketch);
|
|
// BIF_undo_push("Convert Sketch");
|
|
// allqueue(REDRAWVIEW3D, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
void BIF_selectAllSketch(bContext *C, int mode)
|
|
{
|
|
if (BIF_validSketchMode(C))
|
|
{
|
|
SK_Sketch *sketch = contextSketch(C, 0);
|
|
if (sketch)
|
|
{
|
|
sk_selectAllSketch(sketch, mode);
|
|
// XXX
|
|
// allqueue(REDRAWVIEW3D, 0);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
SK_Sketch* contextSketch(const bContext *C, int create)
|
|
{
|
|
Object *obedit = CTX_data_edit_object(C);
|
|
SK_Sketch *sketch = NULL;
|
|
|
|
if (obedit && obedit->type == OB_ARMATURE)
|
|
{
|
|
bArmature *arm = obedit->data;
|
|
|
|
if (arm->sketch == NULL && create)
|
|
{
|
|
arm->sketch = createSketch();
|
|
}
|
|
sketch = arm->sketch;
|
|
}
|
|
|
|
return sketch;
|
|
}
|
|
|
|
SK_Sketch* viewcontextSketch(ViewContext *vc, int create)
|
|
{
|
|
Object *obedit = vc->obedit;
|
|
SK_Sketch *sketch = NULL;
|
|
|
|
if (obedit && obedit->type == OB_ARMATURE)
|
|
{
|
|
bArmature *arm = obedit->data;
|
|
|
|
if (arm->sketch == NULL && create)
|
|
{
|
|
arm->sketch = createSketch();
|
|
}
|
|
sketch = arm->sketch;
|
|
}
|
|
|
|
return sketch;
|
|
}
|
|
|
|
static int sketch_convert(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
|
|
{
|
|
SK_Sketch *sketch = contextSketch(C, 0);
|
|
if (sketch != NULL)
|
|
{
|
|
sk_convert(C, sketch);
|
|
ED_area_tag_redraw(CTX_wm_area(C));
|
|
}
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
static int sketch_cancel(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
|
|
{
|
|
SK_Sketch *sketch = contextSketch(C, 0);
|
|
if (sketch != NULL)
|
|
{
|
|
sk_cancelStroke(sketch);
|
|
ED_area_tag_redraw(CTX_wm_area(C));
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
return OPERATOR_PASS_THROUGH;
|
|
}
|
|
|
|
static int sketch_finish(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
|
|
{
|
|
SK_Sketch *sketch = contextSketch(C, 0);
|
|
if (sketch != NULL)
|
|
{
|
|
if (sk_finish_stroke(C, sketch))
|
|
{
|
|
ED_area_tag_redraw(CTX_wm_area(C));
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
}
|
|
return OPERATOR_PASS_THROUGH;
|
|
}
|
|
|
|
static int sketch_select(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
|
|
{
|
|
SK_Sketch *sketch = contextSketch(C, 0);
|
|
if (sketch)
|
|
{
|
|
short extend = 0;
|
|
if (sk_selectStroke(C, sketch, event->mval, extend))
|
|
ED_area_tag_redraw(CTX_wm_area(C));
|
|
}
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
static int sketch_draw_stroke_cancel(bContext *C, wmOperator *op)
|
|
{
|
|
SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */
|
|
sk_cancelStroke(sketch);
|
|
MEM_freeN(op->customdata);
|
|
return OPERATOR_CANCELLED;
|
|
}
|
|
|
|
static int sketch_draw_stroke(bContext *C, wmOperator *op, wmEvent *event)
|
|
{
|
|
short snap = RNA_boolean_get(op->ptr, "snap");
|
|
SK_DrawData *dd;
|
|
SK_Sketch *sketch = contextSketch(C, 1);
|
|
|
|
op->customdata = dd = MEM_callocN(sizeof("SK_DrawData"), "SketchDrawData");
|
|
sk_initDrawData(dd, event->mval);
|
|
|
|
sk_start_draw_stroke(sketch);
|
|
|
|
sk_draw_stroke(C, sketch, sketch->active_stroke, dd, snap);
|
|
|
|
WM_event_add_modal_handler(C, op);
|
|
|
|
return OPERATOR_RUNNING_MODAL;
|
|
}
|
|
|
|
static int sketch_draw_gesture_cancel(bContext *C, wmOperator *op)
|
|
{
|
|
SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */
|
|
sk_cancelStroke(sketch);
|
|
MEM_freeN(op->customdata);
|
|
return OPERATOR_CANCELLED;
|
|
}
|
|
|
|
static int sketch_draw_gesture(bContext *C, wmOperator *op, wmEvent *event)
|
|
{
|
|
short snap = RNA_boolean_get(op->ptr, "snap");
|
|
SK_DrawData *dd;
|
|
SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */
|
|
sk_cancelStroke(sketch);
|
|
|
|
op->customdata = dd = MEM_callocN(sizeof("SK_DrawData"), "SketchDrawData");
|
|
sk_initDrawData(dd, event->mval);
|
|
|
|
sk_start_draw_gesture(sketch);
|
|
sk_draw_stroke(C, sketch, sketch->gesture, dd, snap);
|
|
|
|
WM_event_add_modal_handler(C, op);
|
|
|
|
return OPERATOR_RUNNING_MODAL;
|
|
}
|
|
|
|
static int sketch_draw_modal(bContext *C, wmOperator *op, wmEvent *event, short gesture, SK_Stroke *stk)
|
|
{
|
|
short snap = RNA_boolean_get(op->ptr, "snap");
|
|
SK_DrawData *dd = op->customdata;
|
|
SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */
|
|
int retval = OPERATOR_RUNNING_MODAL;
|
|
|
|
switch (event->type)
|
|
{
|
|
case LEFTCTRLKEY:
|
|
case RIGHTCTRLKEY:
|
|
snap = event->ctrl;
|
|
RNA_boolean_set(op->ptr, "snap", snap);
|
|
break;
|
|
case MOUSEMOVE:
|
|
case INBETWEEN_MOUSEMOVE:
|
|
dd->mval[0] = event->mval[0];
|
|
dd->mval[1] = event->mval[1];
|
|
sk_draw_stroke(C, sketch, stk, dd, snap);
|
|
ED_area_tag_redraw(CTX_wm_area(C));
|
|
break;
|
|
case ESCKEY:
|
|
op->type->cancel(C, op);
|
|
ED_area_tag_redraw(CTX_wm_area(C));
|
|
retval = OPERATOR_CANCELLED;
|
|
break;
|
|
case LEFTMOUSE:
|
|
if (event->val == KM_RELEASE)
|
|
{
|
|
if (gesture == 0)
|
|
{
|
|
sk_endContinuousStroke(stk);
|
|
sk_filterLastContinuousStroke(stk);
|
|
sk_updateNextPoint(sketch, stk);
|
|
ED_area_tag_redraw(CTX_wm_area(C));
|
|
MEM_freeN(op->customdata);
|
|
retval = OPERATOR_FINISHED;
|
|
}
|
|
else
|
|
{
|
|
sk_endContinuousStroke(stk);
|
|
sk_filterLastContinuousStroke(stk);
|
|
|
|
if (stk->nb_points > 1)
|
|
{
|
|
/* apply gesture here */
|
|
sk_applyGesture(C, sketch);
|
|
}
|
|
|
|
sk_freeStroke(stk);
|
|
sketch->gesture = NULL;
|
|
|
|
ED_area_tag_redraw(CTX_wm_area(C));
|
|
MEM_freeN(op->customdata);
|
|
retval = OPERATOR_FINISHED;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
static int sketch_draw_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
|
|
{
|
|
SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */
|
|
return sketch_draw_modal(C, op, event, 0, sketch->active_stroke);
|
|
}
|
|
|
|
static int sketch_draw_gesture_modal(bContext *C, wmOperator *op, wmEvent *event)
|
|
{
|
|
SK_Sketch *sketch = contextSketch(C, 1); /* create just to be sure */
|
|
return sketch_draw_modal(C, op, event, 1, sketch->gesture);
|
|
}
|
|
|
|
static int sketch_draw_preview(bContext *C, wmOperator *op, wmEvent *event)
|
|
{
|
|
short snap = RNA_boolean_get(op->ptr, "snap");
|
|
SK_Sketch *sketch = contextSketch(C, 0);
|
|
|
|
if (sketch)
|
|
{
|
|
SK_DrawData dd;
|
|
|
|
sk_initDrawData(&dd, event->mval);
|
|
sk_getStrokePoint(C, &sketch->next_point, sketch, sketch->active_stroke, &dd, snap);
|
|
ED_area_tag_redraw(CTX_wm_area(C));
|
|
}
|
|
|
|
return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
|
|
}
|
|
|
|
/* ============================================== Poll Functions ============================================= */
|
|
|
|
int ED_operator_sketch_mode_active_stroke(bContext *C)
|
|
{
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
|
SK_Sketch *sketch = contextSketch(C, 0);
|
|
|
|
if (ts->bone_sketching & BONE_SKETCHING &&
|
|
sketch != NULL &&
|
|
sketch->active_stroke != NULL)
|
|
{
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int ED_operator_sketch_mode_gesture(bContext *C)
|
|
{
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
|
SK_Sketch *sketch = contextSketch(C, 0);
|
|
|
|
if (ts->bone_sketching & BONE_SKETCHING &&
|
|
(ts->bone_sketching & BONE_SKETCHING_QUICK) == 0 &&
|
|
sketch != NULL &&
|
|
sketch->active_stroke == NULL)
|
|
{
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int ED_operator_sketch_full_mode(bContext *C)
|
|
{
|
|
Object *obedit = CTX_data_edit_object(C);
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
|
|
|
if (obedit &&
|
|
obedit->type == OB_ARMATURE &&
|
|
ts->bone_sketching & BONE_SKETCHING &&
|
|
(ts->bone_sketching & BONE_SKETCHING_QUICK) == 0)
|
|
{
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int ED_operator_sketch_mode(const bContext *C)
|
|
{
|
|
Object *obedit = CTX_data_edit_object(C);
|
|
ToolSettings *ts = CTX_data_tool_settings(C);
|
|
|
|
if (obedit &&
|
|
obedit->type == OB_ARMATURE &&
|
|
ts->bone_sketching & BONE_SKETCHING)
|
|
{
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* ================================================ Operators ================================================ */
|
|
|
|
void SKETCH_OT_delete(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "delete";
|
|
ot->idname= "SKETCH_OT_delete";
|
|
|
|
/* api callbacks */
|
|
ot->invoke= sketch_delete;
|
|
|
|
ot->poll= ED_operator_sketch_full_mode;
|
|
|
|
/* flags */
|
|
// ot->flag= OPTYPE_UNDO;
|
|
}
|
|
|
|
void SKETCH_OT_select(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "select";
|
|
ot->idname= "SKETCH_OT_select";
|
|
|
|
/* api callbacks */
|
|
ot->invoke= sketch_select;
|
|
|
|
ot->poll= ED_operator_sketch_full_mode;
|
|
|
|
/* flags */
|
|
// ot->flag= OPTYPE_UNDO;
|
|
}
|
|
|
|
void SKETCH_OT_cancel_stroke(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "cancel stroke";
|
|
ot->idname= "SKETCH_OT_cancel_stroke";
|
|
|
|
/* api callbacks */
|
|
ot->invoke= sketch_cancel;
|
|
|
|
ot->poll= ED_operator_sketch_mode_active_stroke;
|
|
|
|
/* flags */
|
|
// ot->flag= OPTYPE_UNDO;
|
|
}
|
|
|
|
void SKETCH_OT_convert(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "convert";
|
|
ot->idname= "SKETCH_OT_convert";
|
|
|
|
/* api callbacks */
|
|
ot->invoke= sketch_convert;
|
|
|
|
ot->poll= ED_operator_sketch_full_mode;
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_UNDO;
|
|
}
|
|
|
|
void SKETCH_OT_finish_stroke(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "end stroke";
|
|
ot->idname= "SKETCH_OT_finish_stroke";
|
|
|
|
/* api callbacks */
|
|
ot->invoke= sketch_finish;
|
|
|
|
ot->poll= ED_operator_sketch_mode_active_stroke;
|
|
|
|
/* flags */
|
|
// ot->flag= OPTYPE_UNDO;
|
|
}
|
|
|
|
void SKETCH_OT_draw_preview(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "draw preview";
|
|
ot->idname= "SKETCH_OT_draw_preview";
|
|
|
|
/* api callbacks */
|
|
ot->invoke= sketch_draw_preview;
|
|
|
|
ot->poll= ED_operator_sketch_mode_active_stroke;
|
|
|
|
RNA_def_boolean(ot->srna, "snap", 0, "Snap", "");
|
|
|
|
/* flags */
|
|
// ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
}
|
|
|
|
void SKETCH_OT_draw_stroke(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "draw stroke";
|
|
ot->idname= "SKETCH_OT_draw_stroke";
|
|
|
|
/* api callbacks */
|
|
ot->invoke = sketch_draw_stroke;
|
|
ot->modal = sketch_draw_stroke_modal;
|
|
ot->cancel = sketch_draw_stroke_cancel;
|
|
|
|
ot->poll= (int (*)(bContext *))ED_operator_sketch_mode;
|
|
|
|
RNA_def_boolean(ot->srna, "snap", 0, "Snap", "");
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_BLOCKING; // OPTYPE_REGISTER|OPTYPE_UNDO
|
|
}
|
|
|
|
void SKETCH_OT_gesture(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name= "gesture";
|
|
ot->idname= "SKETCH_OT_gesture";
|
|
|
|
/* api callbacks */
|
|
ot->invoke = sketch_draw_gesture;
|
|
ot->modal = sketch_draw_gesture_modal;
|
|
ot->cancel = sketch_draw_gesture_cancel;
|
|
|
|
ot->poll= ED_operator_sketch_mode_gesture;
|
|
|
|
RNA_def_boolean(ot->srna, "snap", 0, "Snap", "");
|
|
|
|
/* flags */
|
|
ot->flag= OPTYPE_BLOCKING; // OPTYPE_UNDO
|
|
}
|
|
|