diff options
Diffstat (limited to 'source/blender/src/editaction_gpencil.c')
-rw-r--r-- | source/blender/src/editaction_gpencil.c | 755 |
1 files changed, 0 insertions, 755 deletions
diff --git a/source/blender/src/editaction_gpencil.c b/source/blender/src/editaction_gpencil.c deleted file mode 100644 index fb070624e8f..00000000000 --- a/source/blender/src/editaction_gpencil.c +++ /dev/null @@ -1,755 +0,0 @@ -/** - * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * The Original Code is Copyright (C) 2008, Blender Foundation - * This is a new part of Blender - * - * Contributor(s): Joshua Leung - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stddef.h> -#include <math.h> - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "MEM_guardedalloc.h" - -#include "BMF_Api.h" - -#include "BLI_arithb.h" -#include "BLI_blenlib.h" - -#include "DNA_listBase.h" -#include "DNA_action_types.h" -#include "DNA_gpencil_types.h" -#include "DNA_scene_types.h" -#include "DNA_screen_types.h" -#include "DNA_space_types.h" -#include "DNA_userdef_types.h" -#include "DNA_view3d_types.h" -#include "DNA_view2d_types.h" - -#include "BKE_global.h" -#include "BKE_utildefines.h" -#include "BKE_blender.h" -#include "BKE_ipo.h" - -#include "BIF_gl.h" -#include "BIF_glutil.h" -#include "BIF_butspace.h" -#include "BIF_graphics.h" -#include "BIF_interface.h" -#include "BIF_mywindow.h" -#include "BIF_resources.h" -#include "BIF_space.h" -#include "BIF_screen.h" -#include "BIF_toolbox.h" -#include "BIF_toets.h" - -#include "BIF_editaction.h" -#include "BSE_editaction_types.h" - -#include "BDR_gpencil.h" -#include "BIF_drawgpencil.h" - -#include "BSE_drawipo.h" -#include "BSE_headerbuttons.h" -#include "BSE_time.h" -#include "BSE_view.h" - -#include "blendef.h" -#include "butspace.h" - -#include "PIL_time.h" -#include "mydevice.h" - -/* ***************************************** */ -/* NOTE ABOUT THIS FILE: - * This file contains code for editing Grease Pencil data in the Action Editor - * as a 'keyframes', so that a user can adjust the timing of Grease Pencil drawings. - * Therefore, this file mostly contains functions for selecting Grease-Pencil frames. - */ -/* ***************************************** */ -/* Generics - Loopers */ - -/* Loops over the gp-frames for a gp-layer, and applies the given callback */ -short gplayer_frames_looper (bGPDlayer *gpl, short (*gpf_cb)(bGPDframe *)) -{ - bGPDframe *gpf; - - /* error checker */ - if (gpl == NULL) - return 0; - - /* do loop */ - for (gpf= gpl->frames.first; gpf; gpf= gpf->next) { - /* execute callback */ - if (gpf_cb(gpf)) - return 1; - } - - /* nothing to return */ - return 0; -} - -/* ****************************************** */ -/* Data Conversion Tools */ - -/* make a listing all the gp-frames in a layer as cfraelems */ -void gplayer_make_cfra_list (bGPDlayer *gpl, ListBase *elems, short onlysel) -{ - bGPDframe *gpf; - CfraElem *ce; - - /* error checking */ - if (ELEM(NULL, gpl, elems)) - return; - - /* loop through gp-frames, adding */ - for (gpf= gpl->frames.first; gpf; gpf= gpf->next) { - if ((onlysel == 0) || (gpf->flag & GP_FRAME_SELECT)) { - ce= MEM_callocN(sizeof(CfraElem), "CfraElem"); - - ce->cfra= (float)gpf->framenum; - ce->sel= (gpf->flag & GP_FRAME_SELECT) ? 1 : 0; - - BLI_addtail(elems, ce); - } - } -} - -/* ***************************************** */ -/* Selection Tools */ - -/* check if one of the frames in this layer is selected */ -short is_gplayer_frame_selected (bGPDlayer *gpl) -{ - bGPDframe *gpf; - - /* error checking */ - if (gpl == NULL) - return 0; - - /* stop at the first one found */ - for (gpf= gpl->frames.first; gpf; gpf= gpf->next) { - if (gpf->flag & GP_FRAME_SELECT) - return 1; - } - - /* not found */ - return 0; -} - -/* helper function - select gp-frame based on SELECT_* mode */ -static void gpframe_select (bGPDframe *gpf, short select_mode) -{ - switch (select_mode) { - case SELECT_ADD: - gpf->flag |= GP_FRAME_SELECT; - break; - case SELECT_SUBTRACT: - gpf->flag &= ~GP_FRAME_SELECT; - break; - case SELECT_INVERT: - gpf->flag ^= GP_FRAME_SELECT; - break; - } -} - -/* set all/none/invert select (like above, but with SELECT_* modes) */ -void select_gpencil_frames (bGPDlayer *gpl, short select_mode) -{ - bGPDframe *gpf; - - /* error checking */ - if (gpl == NULL) - return; - - /* handle according to mode */ - for (gpf= gpl->frames.first; gpf; gpf= gpf->next) { - gpframe_select(gpf, select_mode); - } -} - -/* set all/none/invert select */ -void set_gplayer_frame_selection (bGPDlayer *gpl, short mode) -{ - /* error checking */ - if (gpl == NULL) - return; - - /* convert mode to select_mode */ - switch (mode) { - case 2: - mode= SELECT_INVERT; - break; - case 1: - mode= SELECT_ADD; - break; - case 0: - mode= SELECT_SUBTRACT; - break; - default: - return; - } - - /* now call the standard function */ - select_gpencil_frames (gpl, mode); -} - -/* select the frame in this layer that occurs on this frame (there should only be one at most) */ -void select_gpencil_frame (bGPDlayer *gpl, int selx, short select_mode) -{ - bGPDframe *gpf; - - /* search through frames for a match */ - for (gpf= gpl->frames.first; gpf; gpf= gpf->next) { - /* there should only be one frame with this frame-number */ - if (gpf->framenum == selx) { - gpframe_select(gpf, select_mode); - break; - } - } -} - -/* select the frames in this layer that occur within the bounds specified */ -void borderselect_gplayer_frames (bGPDlayer *gpl, float min, float max, short select_mode) -{ - bGPDframe *gpf; - - /* only select those frames which are in bounds */ - for (gpf= gpl->frames.first; gpf; gpf= gpf->next) { - if (IN_RANGE(gpf->framenum, min, max)) - gpframe_select(gpf, select_mode); - } -} - - -/* De-selects or inverts the selection of Layers for a grease-pencil block - * mode: 0 = default behaviour (select all), 1 = test if (de)select all, 2 = invert all - */ -void deselect_gpencil_layers (void *data, short mode) -{ - ListBase act_data = {NULL, NULL}; - bActListElem *ale; - int filter, sel=1; - - /* filter data */ - filter= ACTFILTER_VISIBLE; - actdata_filter(&act_data, filter, data, ACTCONT_GPENCIL); - - /* See if we should be selecting or deselecting */ - if (mode == 1) { - for (ale= act_data.first; ale; ale= ale->next) { - if (sel == 0) - break; - - if (ale->flag & GP_LAYER_SELECT) - sel= 0; - } - } - else - sel= 0; - - /* Now set the flags */ - for (ale= act_data.first; ale; ale= ale->next) { - bGPDlayer *gpl= (bGPDlayer *)ale->data; - - if (mode == 2) - gpl->flag ^= GP_LAYER_SELECT; - else if (sel) - gpl->flag |= GP_LAYER_SELECT; - else - gpl->flag &= ~GP_LAYER_SELECT; - - gpl->flag &= ~GP_LAYER_ACTIVE; - } - - /* Cleanup */ - BLI_freelistN(&act_data); -} - -/* ***************************************** */ -/* Frame Editing Tools */ - -/* Delete selected grease-pencil layers */ -void delete_gpencil_layers (void) -{ - ListBase act_data = {NULL, NULL}; - bActListElem *ale, *next; - void *data; - short datatype; - int filter; - - /* determine what type of data we are operating on */ - data = get_action_context(&datatype); - if (data == NULL) return; - if (datatype != ACTCONT_GPENCIL) return; - - /* filter data */ - filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_CHANNELS | ACTFILTER_SEL); - actdata_filter(&act_data, filter, data, datatype); - - /* clean up grease-pencil layers */ - for (ale= act_data.first; ale; ale= next) { - bGPdata *gpd= (bGPdata *)ale->owner; - bGPDlayer *gpl= (bGPDlayer *)ale->data; - next= ale->next; - - /* free layer and its data */ - if (SEL_GPL(gpl)) { - free_gpencil_frames(gpl); - BLI_freelinkN(&gpd->layers, gpl); - } - - /* free temp memory */ - BLI_freelinkN(&act_data, ale); - } - - BIF_undo_push("Delete GPencil Layers"); - allspace(REDRAWVIEW3D, 0); - allqueue(REDRAWACTION, 0); -} - -/* Delete selected frames */ -void delete_gplayer_frames (bGPDlayer *gpl) -{ - bGPDframe *gpf, *gpfn; - - /* error checking */ - if (gpl == NULL) - return; - - /* check for frames to delete */ - for (gpf= gpl->frames.first; gpf; gpf= gpfn) { - gpfn= gpf->next; - - if (gpf->flag & GP_FRAME_SELECT) - gpencil_layer_delframe(gpl, gpf); - } -} - -/* Duplicate selected frames from given gp-layer */ -void duplicate_gplayer_frames (bGPDlayer *gpl) -{ - bGPDframe *gpf, *gpfn; - - /* error checking */ - if (gpl == NULL) - return; - - /* duplicate selected frames */ - for (gpf= gpl->frames.first; gpf; gpf= gpfn) { - gpfn= gpf->next; - - /* duplicate this frame */ - if (gpf->flag & GP_FRAME_SELECT) { - bGPDframe *gpfd; - - /* duplicate frame, and deselect self */ - gpfd= gpencil_frame_duplicate(gpf); - gpf->flag &= ~GP_FRAME_SELECT; - - BLI_insertlinkafter(&gpl->frames, gpf, gpfd); - } - } -} - -/* -------------------------------------- */ -/* Copy and Paste Tools */ -/* - The copy/paste buffer currently stores a set of GP_Layers, with temporary - * GP_Frames with the necessary strokes - * - Unless there is only one element in the buffer, names are also tested to check for compatability. - * - All pasted frames are offset by the same amount. This is calculated as the difference in the times of - * the current frame and the 'first keyframe' (i.e. the earliest one in all channels). - * - The earliest frame is calculated per copy operation. - */ - -/* globals for copy/paste data (like for other copy/paste buffers) */ -ListBase gpcopybuf = {NULL, NULL}; -static int gpcopy_firstframe= 999999999; - -/* This function frees any MEM_calloc'ed copy/paste buffer data */ -void free_gpcopybuf () -{ - free_gpencil_layers(&gpcopybuf); - - gpcopybuf.first= gpcopybuf.last= NULL; - gpcopy_firstframe= 999999999; -} - -/* This function adds data to the copy/paste buffer, freeing existing data first - * Only the selected GP-layers get their selected keyframes copied. - */ -void copy_gpdata () -{ - ListBase act_data = {NULL, NULL}; - bActListElem *ale; - int filter; - void *data; - short datatype; - - /* clear buffer first */ - free_gpcopybuf(); - - /* get data */ - data= get_action_context(&datatype); - if (data == NULL) return; - if (datatype != ACTCONT_GPENCIL) return; - - /* filter data */ - filter= (ACTFILTER_VISIBLE | ACTFILTER_SEL); - actdata_filter(&act_data, filter, data, datatype); - - /* assume that each of these is an ipo-block */ - for (ale= act_data.first; ale; ale= ale->next) { - bGPDlayer *gpls, *gpln; - bGPDframe *gpf, *gpfn; - - /* get new layer to put into buffer */ - gpls= (bGPDlayer *)ale->data; - gpln= MEM_callocN(sizeof(bGPDlayer), "GPCopyPasteLayer"); - - gpln->frames.first= gpln->frames.last= NULL; - strcpy(gpln->info, gpls->info); - - BLI_addtail(&gpcopybuf, gpln); - - /* loop over frames, and copy only selected frames */ - for (gpf= gpls->frames.first; gpf; gpf= gpf->next) { - /* if frame is selected, make duplicate it and its strokes */ - if (gpf->flag & GP_FRAME_SELECT) { - /* add frame to buffer */ - gpfn= gpencil_frame_duplicate(gpf); - BLI_addtail(&gpln->frames, gpfn); - - /* check if this is the earliest frame encountered so far */ - if (gpf->framenum < gpcopy_firstframe) - gpcopy_firstframe= gpf->framenum; - } - } - } - - /* check if anything ended up in the buffer */ - if (ELEM(NULL, gpcopybuf.first, gpcopybuf.last)) - error("Nothing copied to buffer"); - - /* free temp memory */ - BLI_freelistN(&act_data); -} - -void paste_gpdata () -{ - ListBase act_data = {NULL, NULL}; - bActListElem *ale; - int filter; - void *data; - short datatype; - - const int offset = (CFRA - gpcopy_firstframe); - short no_name= 0; - - /* check if buffer is empty */ - if (ELEM(NULL, gpcopybuf.first, gpcopybuf.last)) { - error("No data in buffer to paste"); - return; - } - /* check if single channel in buffer (disregard names if so) */ - if (gpcopybuf.first == gpcopybuf.last) - no_name= 1; - - /* get data */ - data= get_action_context(&datatype); - if (data == NULL) return; - if (datatype != ACTCONT_GPENCIL) return; - - /* filter data */ - filter= (ACTFILTER_VISIBLE | ACTFILTER_SEL | ACTFILTER_FOREDIT); - actdata_filter(&act_data, filter, data, datatype); - - /* from selected channels */ - for (ale= act_data.first; ale; ale= ale->next) { - bGPDlayer *gpld= (bGPDlayer *)ale->data; - bGPDlayer *gpls= NULL; - bGPDframe *gpfs, *gpf; - - /* find suitable layer from buffer to use to paste from */ - for (gpls= gpcopybuf.first; gpls; gpls= gpls->next) { - /* check if layer name matches */ - if ((no_name) || (strcmp(gpls->info, gpld->info)==0)) - break; - } - - /* this situation might occur! */ - if (gpls == NULL) - continue; - - /* add frames from buffer */ - for (gpfs= gpls->frames.first; gpfs; gpfs= gpfs->next) { - /* temporarily apply offset to buffer-frame while copying */ - gpfs->framenum += offset; - - /* get frame to copy data into (if no frame returned, then just ignore) */ - gpf= gpencil_layer_getframe(gpld, gpfs->framenum, 1); - if (gpf) { - bGPDstroke *gps, *gpsn; - ScrArea *sa; - - /* get area that gp-data comes from */ - sa= gpencil_data_findowner((bGPdata *)ale->owner); - - /* this should be the right frame... as it may be a pre-existing frame, - * must make sure that only compatible stroke types get copied over - * - we cannot just add a duplicate frame, as that would cause errors - * - need to check for compatible types to minimise memory usage (copying 'junk' over) - */ - for (gps= gpfs->strokes.first; gps; gps= gps->next) { - short stroke_ok; - - /* if there's an area, check that it supports this type of stroke */ - if (sa) { - stroke_ok= 0; - - /* check if spacetype supports this type of stroke - * - NOTE: must sync this with gp_paint_initstroke() in gpencil.c - */ - switch (sa->spacetype) { - case SPACE_VIEW3D: /* 3D-View: either screen-aligned or 3d-space */ - if ((gps->flag == 0) || (gps->flag & GP_STROKE_3DSPACE)) - stroke_ok= 1; - break; - - case SPACE_NODE: /* Nodes Editor: either screen-aligned or view-aligned */ - case SPACE_IMAGE: /* Image Editor: either screen-aligned or view\image-aligned */ - if ((gps->flag == 0) || (gps->flag & GP_STROKE_2DSPACE)) - stroke_ok= 1; - break; - - case SPACE_SEQ: /* Sequence Editor: either screen-aligned or view-aligned */ - if ((gps->flag == 0) || (gps->flag & GP_STROKE_2DIMAGE)) - stroke_ok= 1; - break; - } - } - else - stroke_ok= 1; - - /* if stroke is ok, we make a copy of this stroke and add to frame */ - if (stroke_ok) { - /* make a copy of stroke, then of its points array */ - gpsn= MEM_dupallocN(gps); - gpsn->points= MEM_dupallocN(gps->points); - - /* append stroke to frame */ - BLI_addtail(&gpf->strokes, gpsn); - } - } - - /* if no strokes (i.e. new frame) added, free gpf */ - if (gpf->strokes.first == NULL) - gpencil_layer_delframe(gpld, gpf); - } - - /* unapply offset from buffer-frame */ - gpfs->framenum -= offset; - } - } - - /* free temp memory */ - BLI_freelistN(&act_data); - - /* undo and redraw stuff */ - allqueue(REDRAWVIEW3D, 0); - //allqueue(REDRAWNODES, 0); - allqueue(REDRAWACTION, 0); - BIF_undo_push("Paste Grease Pencil Frames"); -} - -/* -------------------------------------- */ -/* Snap Tools */ - -static short snap_gpf_nearest (bGPDframe *gpf) -{ - if (gpf->flag & GP_FRAME_SELECT) - gpf->framenum= (int)(floor(gpf->framenum+0.5)); - return 0; -} - -static short snap_gpf_nearestsec (bGPDframe *gpf) -{ - float secf = (float)FPS; - if (gpf->flag & GP_FRAME_SELECT) - gpf->framenum= (int)(floor(gpf->framenum/secf + 0.5f) * secf); - return 0; -} - -static short snap_gpf_cframe (bGPDframe *gpf) -{ - if (gpf->flag & GP_FRAME_SELECT) - gpf->framenum= (int)CFRA; - return 0; -} - -static short snap_gpf_nearmarker (bGPDframe *gpf) -{ - if (gpf->flag & GP_FRAME_SELECT) - gpf->framenum= (int)find_nearest_marker_time((float)gpf->framenum); - return 0; -} - - -/* snap selected frames to ... */ -void snap_gplayer_frames (bGPDlayer *gpl, short mode) -{ - switch (mode) { - case 1: /* snap to nearest frame */ - gplayer_frames_looper(gpl, snap_gpf_nearest); - break; - case 2: /* snap to current frame */ - gplayer_frames_looper(gpl, snap_gpf_cframe); - break; - case 3: /* snap to nearest marker */ - gplayer_frames_looper(gpl, snap_gpf_nearmarker); - break; - case 4: /* snap to nearest second */ - gplayer_frames_looper(gpl, snap_gpf_nearestsec); - break; - default: /* just in case */ - gplayer_frames_looper(gpl, snap_gpf_nearest); - break; - } -} - -/* -------------------------------------- */ -/* Mirror Tools */ - -static short mirror_gpf_cframe (bGPDframe *gpf) -{ - int diff; - - if (gpf->flag & GP_FRAME_SELECT) { - diff= CFRA - gpf->framenum; - gpf->framenum= CFRA; - } - - return 0; -} - -static short mirror_gpf_yaxis (bGPDframe *gpf) -{ - int diff; - - if (gpf->flag & GP_FRAME_SELECT) { - diff= -gpf->framenum; - gpf->framenum= diff; - } - - return 0; -} - -static short mirror_gpf_xaxis (bGPDframe *gpf) -{ - int diff; - - if (gpf->flag & GP_FRAME_SELECT) { - diff= -gpf->framenum; - gpf->framenum= diff; - } - - return 0; -} - -static short mirror_gpf_marker (bGPDframe *gpf) -{ - static TimeMarker *marker; - static short initialised = 0; - int diff; - - /* In order for this mirror function to work without - * any extra arguments being added, we use the case - * of bezt==NULL to denote that we should find the - * marker to mirror over. The static pointer is safe - * to use this way, as it will be set to null after - * each cycle in which this is called. - */ - - if (gpf) { - /* mirroring time */ - if ((gpf->flag & GP_FRAME_SELECT) && (marker)) { - diff= (marker->frame - gpf->framenum); - gpf->framenum= (marker->frame + diff); - } - } - else { - /* initialisation time */ - if (initialised) { - /* reset everything for safety */ - marker = NULL; - initialised = 0; - } - else { - /* try to find a marker */ - for (marker= G.scene->markers.first; marker; marker=marker->next) { - if (marker->flag & SELECT) { - initialised = 1; - break; - } - } - - if (initialised == 0) - marker = NULL; - } - } - - return 0; -} - - -/* mirror selected gp-frames on... */ -void mirror_gplayer_frames (bGPDlayer *gpl, short mode) -{ - switch (mode) { - case 1: /* mirror over current frame */ - gplayer_frames_looper(gpl, mirror_gpf_cframe); - break; - case 2: /* mirror over frame 0 */ - gplayer_frames_looper(gpl, mirror_gpf_yaxis); - break; - case 3: /* mirror over value 0 */ - gplayer_frames_looper(gpl, mirror_gpf_xaxis); - break; - case 4: /* mirror over marker */ - mirror_gpf_marker(NULL); - gplayer_frames_looper(gpl, mirror_gpf_marker); - mirror_gpf_marker(NULL); - break; - default: /* just in case */ - gplayer_frames_looper(gpl, mirror_gpf_yaxis); - break; - } -} - -/* ***************************************** */ |