Camera tracking integration

===========================

Return non-blocking behavior to grease pencil sketch mode.

It is needed to implement more accurate line drawing based
on using mouse click on where line "knot" should be added
and allowing pan/zoom between such knots selection.

There are still issues with vertex paint/sculpt modes,
but they aren't critical -- just behavior could be
improved here.
This commit is contained in:
Sergey Sharybin
2011-08-11 18:18:46 +00:00
parent a8c2759b97
commit 34ce85571f
6 changed files with 234 additions and 56 deletions

View File

@@ -42,6 +42,7 @@ set(SRC
gpencil_edit.c
gpencil_ops.c
gpencil_paint.c
gpencil_undo.c
gpencil_intern.h
)

View File

@@ -39,6 +39,7 @@
/* ***************************************************** */
/* Operator Defines */
struct bGPdata;
struct wmOperatorType;
/* drawing ---------- */
@@ -63,6 +64,11 @@ void GPENCIL_OT_active_frame_delete(struct wmOperatorType *ot);
void GPENCIL_OT_convert(struct wmOperatorType *ot);
/* undo stack ---------- */
void gpencil_undo_init(struct bGPdata *gpd);
void gpencil_undo_push(struct bGPdata *gpd);
void gpencil_undo_finish(void);
/******************************************************* */
/* FILTERED ACTION DATA - TYPES ---> XXX DEPRECEATED OLD ANIM SYSTEM CODE! */

View File

@@ -895,8 +895,10 @@ static void gp_session_validatebuffer (tGPsdata *p)
/* clear memory of buffer (or allocate it if starting a new session) */
if (gpd->sbuffer)
memset(gpd->sbuffer, 0, sizeof(tGPspoint)*GP_STROKE_BUFFER_MAX);
else
else {
//printf("\t\tGP - allocate sbuffer\n");
gpd->sbuffer= MEM_callocN(sizeof(tGPspoint)*GP_STROKE_BUFFER_MAX, "gp_session_strokebuffer");
}
/* reset indices */
gpd->sbuffer_size = 0;
@@ -1075,7 +1077,12 @@ static tGPsdata *gp_session_initpaint (bContext *C)
}
/* set edit flags - so that buffer will get drawn */
G.f |= G_GREASEPENCIL;
if((G.f & G_GREASEPENCIL)==0) {
G.f |= G_GREASEPENCIL;
/* initialize undo stack */
gpencil_undo_init(p->gpd);
}
/* clear out buffer (stored in gp-data), in case something contaminated it */
gp_session_validatebuffer(p);
@@ -1101,6 +1108,7 @@ static void gp_session_cleanup (tGPsdata *p)
/* free stroke buffer */
if (gpd->sbuffer) {
//printf("\t\tGP - free sbuffer\n");
MEM_freeN(gpd->sbuffer);
gpd->sbuffer= NULL;
}
@@ -1276,7 +1284,8 @@ static void gp_paint_strokeend (tGPsdata *p)
static void gp_paint_cleanup (tGPsdata *p)
{
/* finish off a stroke */
gp_paint_strokeend(p);
if(p->gpd)
gp_paint_strokeend(p);
/* "unlock" frame */
if (p->gpf)
@@ -1292,6 +1301,9 @@ static void gpencil_draw_exit (bContext *C, wmOperator *op)
/* clear edit flags */
G.f &= ~G_GREASEPENCIL;
/* clear undo stack */
gpencil_undo_finish();
/* restore cursor to indicate end of drawing */
WM_cursor_restore(CTX_wm_window(C));
@@ -1621,6 +1633,7 @@ static int gpencil_draw_invoke (bContext *C, wmOperator *op, wmEvent *event)
//printf("\tGP - hotkey invoked... waiting for click-drag\n");
}
WM_event_add_notifier(C, NC_SCREEN|ND_GPENCIL, NULL);
/* add a modal handler for this operator, so that we can then draw continuous strokes */
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -1638,16 +1651,60 @@ static int gpencil_area_exists(bContext *C, ScrArea *satest)
return 0;
}
static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
{
tGPsdata *p= op->customdata;
/* we must check that we're still within the area that we're set up to work from
* otherwise we could crash (see bug #20586)
*/
if (CTX_wm_area(C) != p->sa) {
printf("\t\t\tGP - wrong area execution abort! \n");
p->status= GP_STATUS_ERROR;
}
/* free pointer used by previous stroke */
if(p)
MEM_freeN(p);
//printf("\t\tGP - start stroke \n");
/* we may need to set up paint env again if we're resuming */
// XXX: watch it with the paintmode! in future, it'd be nice to allow changing paint-mode when in sketching-sessions
// XXX: with tablet events, we may event want to check for eraser here, for nicer tablet support
gpencil_draw_init(C, op);
p= op->customdata;
if(p->status != GP_STATUS_ERROR)
p->status= GP_STATUS_PAINTING;
return op->customdata;
}
static void gpencil_stroke_end(wmOperator *op)
{
tGPsdata *p= op->customdata;
gp_paint_cleanup(p);
gpencil_undo_push(p->gpd);
gp_session_cleanup(p);
p->status= GP_STATUS_IDLING;
p->gpd= NULL;
p->gpl= NULL;
p->gpf= NULL;
}
/* events handling during interactive drawing part of operator */
static int gpencil_draw_modal (bContext *C, wmOperator *op, wmEvent *event)
{
tGPsdata *p= op->customdata;
//int estate = OPERATOR_PASS_THROUGH; /* default exit state - not handled, so let others have a share of the pie */
/* currently, grease pencil conflicts with such operators as undo and set object mode
which makes behavior of operator totally unpredictable and crash for some cases.
the only way to solve this proper is to ger rid of pointers to data which can
chage stored in operator custom data (sergey) */
int estate = OPERATOR_RUNNING_MODAL;
int estate = OPERATOR_PASS_THROUGH; /* default exit state - not handled, so let others have a share of the pie */
// if (event->type == NDOF_MOTION)
// return OPERATOR_PASS_THROUGH;
@@ -1681,11 +1738,13 @@ static int gpencil_draw_modal (bContext *C, wmOperator *op, wmEvent *event)
if (GPENCIL_SKETCH_SESSIONS_ON(p->scene)) {
/* end stroke only, and then wait to resume painting soon */
//printf("\t\tGP - end stroke only\n");
gp_paint_cleanup(p);
p->status= GP_STATUS_IDLING;
gpencil_stroke_end(op);
/* we've just entered idling state, so this event was processed (but no others yet) */
estate = OPERATOR_RUNNING_MODAL;
/* stroke could be smoothed, send notifier to refresh screen */
ED_region_tag_redraw(p->ar);
}
else {
//printf("\t\tGP - end of stroke + op\n");
@@ -1693,35 +1752,19 @@ static int gpencil_draw_modal (bContext *C, wmOperator *op, wmEvent *event)
estate = OPERATOR_FINISHED;
}
}
else {
else if (event->val == KM_PRESS) {
/* not painting, so start stroke (this should be mouse-button down) */
/* we must check that we're still within the area that we're set up to work from
* otherwise we could crash (see bug #20586)
*/
if (CTX_wm_area(C) != p->sa) {
//printf("\t\t\tGP - wrong area execution abort! \n");
p->status= GP_STATUS_ERROR;
p= gpencil_stroke_begin(C, op);
if (p->status == GP_STATUS_ERROR) {
estate = OPERATOR_CANCELLED;
}
else {
//printf("\t\tGP - start stroke \n");
p->status= GP_STATUS_PAINTING;
/* we may need to set up paint env again if we're resuming */
// XXX: watch it with the paintmode! in future, it'd be nice to allow changing paint-mode when in sketching-sessions
// XXX: with tablet events, we may event want to check for eraser here, for nicer tablet support
gp_paint_initstroke(p, p->paintmode);
if (p->status == GP_STATUS_ERROR) {
estate = OPERATOR_CANCELLED;
}
}
} else {
p->status = GP_STATUS_IDLING;
}
}
/* handle mode-specific events */
if (p->status == GP_STATUS_PAINTING) {
/* handle painting mouse-movements? */
@@ -1733,7 +1776,7 @@ static int gpencil_draw_modal (bContext *C, wmOperator *op, wmEvent *event)
/* finish painting operation if anything went wrong just now */
if (p->status == GP_STATUS_ERROR) {
//printf("\t\t\t\tGP - add error done! \n");
printf("\t\t\t\tGP - add error done! \n");
estate = OPERATOR_CANCELLED;
}
else {
@@ -1750,28 +1793,6 @@ static int gpencil_draw_modal (bContext *C, wmOperator *op, wmEvent *event)
estate = OPERATOR_RUNNING_MODAL;
}
}
else if (p->status == GP_STATUS_IDLING) {
/* standard undo/redo shouldn't be allowed to execute or else it causes crashes, so catch it here */
// FIXME: this is a hardcoded hotkey that can't be changed
// TODO: catch redo as well, but how?
if (event->type == ZKEY && event->val == KM_RELEASE) {
/* oskey = cmd key on macs as they seem to use cmd-z for undo as well? */
if ((event->ctrl) || (event->oskey)) {
/* just delete last stroke, which will look like undo to the end user */
//printf("caught attempted undo event... deleting last stroke \n");
gpencil_frame_delete_laststroke(p->gpl, p->gpf);
/* undoing the last line can free p->gpf
* note, could do this in a bit more of an elegant way then a search but it at least prevents a crash */
if(BLI_findindex(&p->gpl->frames, p->gpf) == -1) {
p->gpf= NULL;
}
/* event handled, so force refresh */
ED_region_tag_redraw(p->ar); /* just active area for now, since doing whole screen is too slow */
estate = OPERATOR_RUNNING_MODAL;
}
}
}
/* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
if(0==gpencil_area_exists(C, p->sa))

View File

@@ -0,0 +1,142 @@
/*
* $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.
*
* The Original Code is Copyright (C) 2011 Blender Foundation.
* All rights reserved.
*
*
* Contributor(s): Blender Foundation,
* Sergey Sharybin
*
* ***** END GPL LICENSE BLOCK *****
*/
#include <stdlib.h>
#include "MEM_guardedalloc.h"
#include "DNA_gpencil_types.h"
#include "DNA_listBase.h"
#include "DNA_windowmanager_types.h"
#include "BKE_context.h"
#include "BKE_gpencil.h"
#include "BLI_listbase.h"
#include "ED_gpencil.h"
#include "WM_api.h"
#include "WM_types.h"
#include "gpencil_intern.h"
typedef struct bGPundonode {
struct bGPundonode *next, *prev;
struct bGPdata *gpd;
} bGPundonode;
static ListBase undo_nodes = {NULL, NULL};
static bGPundonode *cur_node = NULL;
int ED_undo_gpencil_step(bContext *C, int step, const char *name)
{
bGPdata **gpd_ptr= NULL, *new_gpd= NULL;
PointerRNA ptr;
if(name) /* currently unsupported */
return OPERATOR_CANCELLED;
gpd_ptr= gpencil_data_get_pointers(C, NULL);
(void) step;
if(step==1) { /* undo */
//printf("\t\tGP - undo step\n");
if(cur_node->prev) {
cur_node= cur_node->prev;
new_gpd= cur_node->gpd;
}
}
else if (step==-1) {
//printf("\t\tGP - redo step\n");
if(cur_node->next) {
cur_node= cur_node->next;
new_gpd= cur_node->gpd;
}
}
if(new_gpd) {
if(gpd_ptr) {
if(*gpd_ptr) {
bGPdata *gpd= *gpd_ptr;
bGPDlayer *gpl, *gpld;
free_gpencil_layers(&gpd->layers);
/* copy layers */
gpd->layers.first= gpd->layers.last= NULL;
for (gpl= new_gpd->layers.first; gpl; gpl= gpl->next) {
/* make a copy of source layer and its data */
gpld= gpencil_layer_duplicate(gpl);
BLI_addtail(&gpd->layers, gpld);
}
}
}
}
WM_event_add_notifier(C, NC_SCREEN|ND_GPENCIL|NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
void gpencil_undo_init(bGPdata *gpd)
{
gpencil_undo_push(gpd);
}
void gpencil_undo_push(bGPdata *gpd)
{
bGPundonode *undo_node= MEM_callocN(sizeof(bGPundonode), "gpencil undo node");
//printf("\t\tGP - undo push\n");
undo_node->gpd= gpencil_data_duplicate(gpd);
cur_node= undo_node;
BLI_addtail(&undo_nodes, undo_node);
}
void gpencil_undo_finish(void)
{
bGPundonode *undo_node= undo_nodes.first;
while (undo_node) {
free_gpencil_data(undo_node->gpd);
MEM_freeN(undo_node->gpd);
undo_node= undo_node->next;
}
BLI_freelistN(&undo_nodes);
cur_node= NULL;
}

View File

@@ -108,4 +108,7 @@ void paste_gpdata(void);
void snap_gplayer_frames(struct bGPDlayer *gpl, short mode);
void mirror_gplayer_frames(struct bGPDlayer *gpl, short mode);
/* ------------ Grease-Pencil Undo System ------------------ */
int ED_undo_gpencil_step(struct bContext *C, int step, const char *name);
#endif /* ED_GPENCIL_H */

View File

@@ -54,6 +54,7 @@
#include "ED_armature.h"
#include "ED_particle.h"
#include "ED_curve.h"
#include "ED_gpencil.h"
#include "ED_mball.h"
#include "ED_mesh.h"
#include "ED_object.h"
@@ -126,6 +127,10 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
Object *obact= CTX_data_active_object(C);
ScrArea *sa= CTX_wm_area(C);
if(G.f & G_GREASEPENCIL) {
return ED_undo_gpencil_step(C, step, undoname);
}
if(sa && sa->spacetype==SPACE_IMAGE) {
SpaceImage *sima= (SpaceImage *)sa->spacedata.first;