|
Blender
V2.59
|
00001 /* 00002 * $Id: editaction_gpencil.c 35242 2011-02-27 20:29:51Z jesterking $ 00003 * 00004 * ***** BEGIN GPL LICENSE BLOCK ***** 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software Foundation, 00018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 * 00020 * The Original Code is Copyright (C) 2008, Blender Foundation 00021 * This is a new part of Blender 00022 * 00023 * Contributor(s): Joshua Leung 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 */ 00027 00033 #include <stdio.h> 00034 #include <string.h> 00035 #include <stdlib.h> 00036 #include <stddef.h> 00037 #include <math.h> 00038 00039 #include "MEM_guardedalloc.h" 00040 00041 #include "BLI_blenlib.h" 00042 #include "BLI_math.h" 00043 #include "BLI_utildefines.h" 00044 00045 #include "DNA_gpencil_types.h" 00046 #include "DNA_scene_types.h" 00047 00048 #include "BKE_fcurve.h" 00049 #include "BKE_gpencil.h" 00050 00051 #include "ED_anim_api.h" 00052 #include "ED_gpencil.h" 00053 #include "ED_keyframes_edit.h" 00054 00055 #include "gpencil_intern.h" 00056 00057 /* ***************************************** */ 00058 /* NOTE ABOUT THIS FILE: 00059 * This file contains code for editing Grease Pencil data in the Action Editor 00060 * as a 'keyframes', so that a user can adjust the timing of Grease Pencil drawings. 00061 * Therefore, this file mostly contains functions for selecting Grease-Pencil frames. 00062 */ 00063 /* ***************************************** */ 00064 /* Generics - Loopers */ 00065 00066 /* Loops over the gp-frames for a gp-layer, and applies the given callback */ 00067 short gplayer_frames_looper (bGPDlayer *gpl, Scene *scene, short (*gpf_cb)(bGPDframe *, Scene *)) 00068 { 00069 bGPDframe *gpf; 00070 00071 /* error checker */ 00072 if (gpl == NULL) 00073 return 0; 00074 00075 /* do loop */ 00076 for (gpf= gpl->frames.first; gpf; gpf= gpf->next) { 00077 /* execute callback */ 00078 if (gpf_cb(gpf, scene)) 00079 return 1; 00080 } 00081 00082 /* nothing to return */ 00083 return 0; 00084 } 00085 00086 /* ****************************************** */ 00087 /* Data Conversion Tools */ 00088 00089 /* make a listing all the gp-frames in a layer as cfraelems */ 00090 void gplayer_make_cfra_list (bGPDlayer *gpl, ListBase *elems, short onlysel) 00091 { 00092 bGPDframe *gpf; 00093 CfraElem *ce; 00094 00095 /* error checking */ 00096 if (ELEM(NULL, gpl, elems)) 00097 return; 00098 00099 /* loop through gp-frames, adding */ 00100 for (gpf= gpl->frames.first; gpf; gpf= gpf->next) { 00101 if ((onlysel == 0) || (gpf->flag & GP_FRAME_SELECT)) { 00102 ce= MEM_callocN(sizeof(CfraElem), "CfraElem"); 00103 00104 ce->cfra= (float)gpf->framenum; 00105 ce->sel= (gpf->flag & GP_FRAME_SELECT) ? 1 : 0; 00106 00107 BLI_addtail(elems, ce); 00108 } 00109 } 00110 } 00111 00112 /* ***************************************** */ 00113 /* Selection Tools */ 00114 00115 /* check if one of the frames in this layer is selected */ 00116 short is_gplayer_frame_selected (bGPDlayer *gpl) 00117 { 00118 bGPDframe *gpf; 00119 00120 /* error checking */ 00121 if (gpl == NULL) 00122 return 0; 00123 00124 /* stop at the first one found */ 00125 for (gpf= gpl->frames.first; gpf; gpf= gpf->next) { 00126 if (gpf->flag & GP_FRAME_SELECT) 00127 return 1; 00128 } 00129 00130 /* not found */ 00131 return 0; 00132 } 00133 00134 /* helper function - select gp-frame based on SELECT_* mode */ 00135 static void gpframe_select (bGPDframe *gpf, short select_mode) 00136 { 00137 if (gpf == NULL) 00138 return; 00139 00140 switch (select_mode) { 00141 case SELECT_ADD: 00142 gpf->flag |= GP_FRAME_SELECT; 00143 break; 00144 case SELECT_SUBTRACT: 00145 gpf->flag &= ~GP_FRAME_SELECT; 00146 break; 00147 case SELECT_INVERT: 00148 gpf->flag ^= GP_FRAME_SELECT; 00149 break; 00150 } 00151 } 00152 00153 /* set all/none/invert select (like above, but with SELECT_* modes) */ 00154 void select_gpencil_frames (bGPDlayer *gpl, short select_mode) 00155 { 00156 bGPDframe *gpf; 00157 00158 /* error checking */ 00159 if (gpl == NULL) 00160 return; 00161 00162 /* handle according to mode */ 00163 for (gpf= gpl->frames.first; gpf; gpf= gpf->next) { 00164 gpframe_select(gpf, select_mode); 00165 } 00166 } 00167 00168 /* set all/none/invert select */ 00169 void set_gplayer_frame_selection (bGPDlayer *gpl, short mode) 00170 { 00171 /* error checking */ 00172 if (gpl == NULL) 00173 return; 00174 00175 /* now call the standard function */ 00176 select_gpencil_frames(gpl, mode); 00177 } 00178 00179 /* select the frame in this layer that occurs on this frame (there should only be one at most) */ 00180 void select_gpencil_frame (bGPDlayer *gpl, int selx, short select_mode) 00181 { 00182 bGPDframe *gpf; 00183 00184 if (gpl == NULL) 00185 return; 00186 00187 /* search through frames for a match */ 00188 for (gpf= gpl->frames.first; gpf; gpf= gpf->next) { 00189 /* there should only be one frame with this frame-number */ 00190 if (gpf->framenum == selx) { 00191 gpframe_select(gpf, select_mode); 00192 break; 00193 } 00194 } 00195 } 00196 00197 /* select the frames in this layer that occur within the bounds specified */ 00198 void borderselect_gplayer_frames (bGPDlayer *gpl, float min, float max, short select_mode) 00199 { 00200 bGPDframe *gpf; 00201 00202 if (gpl == NULL) 00203 return; 00204 00205 /* only select those frames which are in bounds */ 00206 for (gpf= gpl->frames.first; gpf; gpf= gpf->next) { 00207 if (IN_RANGE(gpf->framenum, min, max)) 00208 gpframe_select(gpf, select_mode); 00209 } 00210 } 00211 00212 #if 0 // XXX disabled until grease pencil code stabilises again 00213 00214 /* De-selects or inverts the selection of Layers for a grease-pencil block 00215 * mode: 0 = default behaviour (select all), 1 = test if (de)select all, 2 = invert all 00216 */ 00217 void deselect_gpencil_layers (void *data, short mode) 00218 { 00219 ListBase act_data = {NULL, NULL}; 00220 bActListElem *ale; 00221 int filter, sel=1; 00222 00223 /* filter data */ 00224 filter= ACTFILTER_VISIBLE; 00225 actdata_filter(&act_data, filter, data, ACTCONT_GPENCIL); 00226 00227 /* See if we should be selecting or deselecting */ 00228 if (mode == 1) { 00229 for (ale= act_data.first; ale; ale= ale->next) { 00230 if (sel == 0) 00231 break; 00232 00233 if (ale->flag & GP_LAYER_SELECT) 00234 sel= 0; 00235 } 00236 } 00237 else 00238 sel= 0; 00239 00240 /* Now set the flags */ 00241 for (ale= act_data.first; ale; ale= ale->next) { 00242 bGPDlayer *gpl= (bGPDlayer *)ale->data; 00243 00244 if (mode == 2) 00245 gpl->flag ^= GP_LAYER_SELECT; 00246 else if (sel) 00247 gpl->flag |= GP_LAYER_SELECT; 00248 else 00249 gpl->flag &= ~GP_LAYER_SELECT; 00250 00251 gpl->flag &= ~GP_LAYER_ACTIVE; 00252 } 00253 00254 /* Cleanup */ 00255 BLI_freelistN(&act_data); 00256 } 00257 00258 #endif // XXX disabled until Grease Pencil code stabilises again... 00259 00260 /* ***************************************** */ 00261 /* Frame Editing Tools */ 00262 00263 #if 0 // XXX disabled until grease pencil code stabilises again 00264 /* Delete selected grease-pencil layers */ 00265 void delete_gpencil_layers (void) 00266 { 00267 ListBase act_data = {NULL, NULL}; 00268 bActListElem *ale, *next; 00269 void *data; 00270 short datatype; 00271 int filter; 00272 00273 /* determine what type of data we are operating on */ 00274 data = get_action_context(&datatype); 00275 if (data == NULL) return; 00276 if (datatype != ACTCONT_GPENCIL) return; 00277 00278 /* filter data */ 00279 filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_CHANNELS | ACTFILTER_SEL); 00280 actdata_filter(&act_data, filter, data, datatype); 00281 00282 /* clean up grease-pencil layers */ 00283 for (ale= act_data.first; ale; ale= next) { 00284 bGPdata *gpd= (bGPdata *)ale->owner; 00285 bGPDlayer *gpl= (bGPDlayer *)ale->data; 00286 next= ale->next; 00287 00288 /* free layer and its data */ 00289 if (SEL_GPL(gpl)) { 00290 free_gpencil_frames(gpl); 00291 BLI_freelinkN(&gpd->layers, gpl); 00292 } 00293 00294 /* free temp memory */ 00295 BLI_freelinkN(&act_data, ale); 00296 } 00297 00298 BIF_undo_push("Delete GPencil Layers"); 00299 } 00300 #endif // XXX disabled until Grease Pencil code stabilises again... 00301 00302 /* Delete selected frames */ 00303 void delete_gplayer_frames (bGPDlayer *gpl) 00304 { 00305 bGPDframe *gpf, *gpfn; 00306 00307 /* error checking */ 00308 if (gpl == NULL) 00309 return; 00310 00311 /* check for frames to delete */ 00312 for (gpf= gpl->frames.first; gpf; gpf= gpfn) { 00313 gpfn= gpf->next; 00314 00315 if (gpf->flag & GP_FRAME_SELECT) 00316 gpencil_layer_delframe(gpl, gpf); 00317 } 00318 } 00319 00320 /* Duplicate selected frames from given gp-layer */ 00321 void duplicate_gplayer_frames (bGPDlayer *gpl) 00322 { 00323 bGPDframe *gpf, *gpfn; 00324 00325 /* error checking */ 00326 if (gpl == NULL) 00327 return; 00328 00329 /* duplicate selected frames */ 00330 for (gpf= gpl->frames.first; gpf; gpf= gpfn) { 00331 gpfn= gpf->next; 00332 00333 /* duplicate this frame */ 00334 if (gpf->flag & GP_FRAME_SELECT) { 00335 bGPDframe *gpfd; 00336 00337 /* duplicate frame, and deselect self */ 00338 gpfd= gpencil_frame_duplicate(gpf); 00339 gpf->flag &= ~GP_FRAME_SELECT; 00340 00341 BLI_insertlinkafter(&gpl->frames, gpf, gpfd); 00342 } 00343 } 00344 } 00345 00346 #if 0 // XXX disabled until grease pencil code stabilises again 00347 /* -------------------------------------- */ 00348 /* Copy and Paste Tools */ 00349 /* - The copy/paste buffer currently stores a set of GP_Layers, with temporary 00350 * GP_Frames with the necessary strokes 00351 * - Unless there is only one element in the buffer, names are also tested to check for compatability. 00352 * - All pasted frames are offset by the same amount. This is calculated as the difference in the times of 00353 * the current frame and the 'first keyframe' (i.e. the earliest one in all channels). 00354 * - The earliest frame is calculated per copy operation. 00355 */ 00356 00357 /* globals for copy/paste data (like for other copy/paste buffers) */ 00358 ListBase gpcopybuf = {NULL, NULL}; 00359 static int gpcopy_firstframe= 999999999; 00360 00361 /* This function frees any MEM_calloc'ed copy/paste buffer data */ 00362 void free_gpcopybuf () 00363 { 00364 free_gpencil_layers(&gpcopybuf); 00365 00366 gpcopybuf.first= gpcopybuf.last= NULL; 00367 gpcopy_firstframe= 999999999; 00368 } 00369 00370 /* This function adds data to the copy/paste buffer, freeing existing data first 00371 * Only the selected GP-layers get their selected keyframes copied. 00372 */ 00373 void copy_gpdata () 00374 { 00375 ListBase act_data = {NULL, NULL}; 00376 bActListElem *ale; 00377 int filter; 00378 void *data; 00379 short datatype; 00380 00381 /* clear buffer first */ 00382 free_gpcopybuf(); 00383 00384 /* get data */ 00385 data= get_action_context(&datatype); 00386 if (data == NULL) return; 00387 if (datatype != ACTCONT_GPENCIL) return; 00388 00389 /* filter data */ 00390 filter= (ACTFILTER_VISIBLE | ACTFILTER_SEL); 00391 actdata_filter(&act_data, filter, data, datatype); 00392 00393 /* assume that each of these is an ipo-block */ 00394 for (ale= act_data.first; ale; ale= ale->next) { 00395 bGPDlayer *gpls, *gpln; 00396 bGPDframe *gpf, *gpfn; 00397 00398 /* get new layer to put into buffer */ 00399 gpls= (bGPDlayer *)ale->data; 00400 gpln= MEM_callocN(sizeof(bGPDlayer), "GPCopyPasteLayer"); 00401 00402 gpln->frames.first= gpln->frames.last= NULL; 00403 strcpy(gpln->info, gpls->info); 00404 00405 BLI_addtail(&gpcopybuf, gpln); 00406 00407 /* loop over frames, and copy only selected frames */ 00408 for (gpf= gpls->frames.first; gpf; gpf= gpf->next) { 00409 /* if frame is selected, make duplicate it and its strokes */ 00410 if (gpf->flag & GP_FRAME_SELECT) { 00411 /* add frame to buffer */ 00412 gpfn= gpencil_frame_duplicate(gpf); 00413 BLI_addtail(&gpln->frames, gpfn); 00414 00415 /* check if this is the earliest frame encountered so far */ 00416 if (gpf->framenum < gpcopy_firstframe) 00417 gpcopy_firstframe= gpf->framenum; 00418 } 00419 } 00420 } 00421 00422 /* check if anything ended up in the buffer */ 00423 if (ELEM(NULL, gpcopybuf.first, gpcopybuf.last)) 00424 error("Nothing copied to buffer"); 00425 00426 /* free temp memory */ 00427 BLI_freelistN(&act_data); 00428 } 00429 00430 void paste_gpdata (Scene *scene) 00431 { 00432 ListBase act_data = {NULL, NULL}; 00433 bActListElem *ale; 00434 int filter; 00435 void *data; 00436 short datatype; 00437 00438 const int offset = (CFRA - gpcopy_firstframe); 00439 short no_name= 0; 00440 00441 /* check if buffer is empty */ 00442 if (ELEM(NULL, gpcopybuf.first, gpcopybuf.last)) { 00443 error("No data in buffer to paste"); 00444 return; 00445 } 00446 /* check if single channel in buffer (disregard names if so) */ 00447 if (gpcopybuf.first == gpcopybuf.last) 00448 no_name= 1; 00449 00450 /* get data */ 00451 data= get_action_context(&datatype); 00452 if (data == NULL) return; 00453 if (datatype != ACTCONT_GPENCIL) return; 00454 00455 /* filter data */ 00456 filter= (ACTFILTER_VISIBLE | ACTFILTER_SEL | ACTFILTER_FOREDIT); 00457 actdata_filter(&act_data, filter, data, datatype); 00458 00459 /* from selected channels */ 00460 for (ale= act_data.first; ale; ale= ale->next) { 00461 bGPDlayer *gpld= (bGPDlayer *)ale->data; 00462 bGPDlayer *gpls= NULL; 00463 bGPDframe *gpfs, *gpf; 00464 00465 /* find suitable layer from buffer to use to paste from */ 00466 for (gpls= gpcopybuf.first; gpls; gpls= gpls->next) { 00467 /* check if layer name matches */ 00468 if ((no_name) || (strcmp(gpls->info, gpld->info)==0)) 00469 break; 00470 } 00471 00472 /* this situation might occur! */ 00473 if (gpls == NULL) 00474 continue; 00475 00476 /* add frames from buffer */ 00477 for (gpfs= gpls->frames.first; gpfs; gpfs= gpfs->next) { 00478 /* temporarily apply offset to buffer-frame while copying */ 00479 gpfs->framenum += offset; 00480 00481 /* get frame to copy data into (if no frame returned, then just ignore) */ 00482 gpf= gpencil_layer_getframe(gpld, gpfs->framenum, 1); 00483 if (gpf) { 00484 bGPDstroke *gps, *gpsn; 00485 ScrArea *sa; 00486 00487 /* get area that gp-data comes from */ 00488 //sa= gpencil_data_findowner((bGPdata *)ale->owner); 00489 sa = NULL; 00490 00491 /* this should be the right frame... as it may be a pre-existing frame, 00492 * must make sure that only compatible stroke types get copied over 00493 * - we cannot just add a duplicate frame, as that would cause errors 00494 * - need to check for compatible types to minimise memory usage (copying 'junk' over) 00495 */ 00496 for (gps= gpfs->strokes.first; gps; gps= gps->next) { 00497 short stroke_ok; 00498 00499 /* if there's an area, check that it supports this type of stroke */ 00500 if (sa) { 00501 stroke_ok= 0; 00502 00503 /* check if spacetype supports this type of stroke 00504 * - NOTE: must sync this with gp_paint_initstroke() in gpencil.c 00505 */ 00506 switch (sa->spacetype) { 00507 case SPACE_VIEW3D: /* 3D-View: either screen-aligned or 3d-space */ 00508 if ((gps->flag == 0) || (gps->flag & GP_STROKE_3DSPACE)) 00509 stroke_ok= 1; 00510 break; 00511 00512 case SPACE_NODE: /* Nodes Editor: either screen-aligned or view-aligned */ 00513 case SPACE_IMAGE: /* Image Editor: either screen-aligned or view\image-aligned */ 00514 if ((gps->flag == 0) || (gps->flag & GP_STROKE_2DSPACE)) 00515 stroke_ok= 1; 00516 break; 00517 00518 case SPACE_SEQ: /* Sequence Editor: either screen-aligned or view-aligned */ 00519 if ((gps->flag == 0) || (gps->flag & GP_STROKE_2DIMAGE)) 00520 stroke_ok= 1; 00521 break; 00522 } 00523 } 00524 else 00525 stroke_ok= 1; 00526 00527 /* if stroke is ok, we make a copy of this stroke and add to frame */ 00528 if (stroke_ok) { 00529 /* make a copy of stroke, then of its points array */ 00530 gpsn= MEM_dupallocN(gps); 00531 gpsn->points= MEM_dupallocN(gps->points); 00532 00533 /* append stroke to frame */ 00534 BLI_addtail(&gpf->strokes, gpsn); 00535 } 00536 } 00537 00538 /* if no strokes (i.e. new frame) added, free gpf */ 00539 if (gpf->strokes.first == NULL) 00540 gpencil_layer_delframe(gpld, gpf); 00541 } 00542 00543 /* unapply offset from buffer-frame */ 00544 gpfs->framenum -= offset; 00545 } 00546 } 00547 00548 /* free temp memory */ 00549 BLI_freelistN(&act_data); 00550 00551 /* undo and redraw stuff */ 00552 BIF_undo_push("Paste Grease Pencil Frames"); 00553 } 00554 00555 /* -------------------------------------- */ 00556 /* Snap Tools */ 00557 00558 static short snap_gpf_nearest (bGPDframe *gpf, Scene *scene) 00559 { 00560 if (gpf->flag & GP_FRAME_SELECT) 00561 gpf->framenum= (int)(floor(gpf->framenum+0.5)); 00562 return 0; 00563 } 00564 00565 static short snap_gpf_nearestsec (bGPDframe *gpf, Scene *scene) 00566 { 00567 float secf = (float)FPS; 00568 if (gpf->flag & GP_FRAME_SELECT) 00569 gpf->framenum= (int)(floor(gpf->framenum/secf + 0.5f) * secf); 00570 return 0; 00571 } 00572 00573 static short snap_gpf_cframe (bGPDframe *gpf, Scene *scene) 00574 { 00575 if (gpf->flag & GP_FRAME_SELECT) 00576 gpf->framenum= (int)CFRA; 00577 return 0; 00578 } 00579 00580 static short snap_gpf_nearmarker (bGPDframe *gpf, Scene *scene) 00581 { 00582 if (gpf->flag & GP_FRAME_SELECT) 00583 gpf->framenum= (int)find_nearest_marker_time(&scene->markers, (float)gpf->framenum); 00584 return 0; 00585 } 00586 00587 00588 /* snap selected frames to ... */ 00589 void snap_gplayer_frames (bGPDlayer *gpl, Scene *scene, short mode) 00590 { 00591 switch (mode) { 00592 case 1: /* snap to nearest frame */ 00593 gplayer_frames_looper(gpl, scene, snap_gpf_nearest); 00594 break; 00595 case 2: /* snap to current frame */ 00596 gplayer_frames_looper(gpl, scene, snap_gpf_cframe); 00597 break; 00598 case 3: /* snap to nearest marker */ 00599 gplayer_frames_looper(gpl, scene, snap_gpf_nearmarker); 00600 break; 00601 case 4: /* snap to nearest second */ 00602 gplayer_frames_looper(gpl, scene, snap_gpf_nearestsec); 00603 break; 00604 default: /* just in case */ 00605 gplayer_frames_looper(gpl, scene, snap_gpf_nearest); 00606 break; 00607 } 00608 } 00609 00610 /* -------------------------------------- */ 00611 /* Mirror Tools */ 00612 00613 static short mirror_gpf_cframe (bGPDframe *gpf, Scene *scene) 00614 { 00615 int diff; 00616 00617 if (gpf->flag & GP_FRAME_SELECT) { 00618 diff= CFRA - gpf->framenum; 00619 gpf->framenum= CFRA; 00620 } 00621 00622 return 0; 00623 } 00624 00625 static short mirror_gpf_yaxis (bGPDframe *gpf, Scene *scene) 00626 { 00627 int diff; 00628 00629 if (gpf->flag & GP_FRAME_SELECT) { 00630 diff= -gpf->framenum; 00631 gpf->framenum= diff; 00632 } 00633 00634 return 0; 00635 } 00636 00637 static short mirror_gpf_xaxis (bGPDframe *gpf, Scene *scene) 00638 { 00639 int diff; 00640 00641 if (gpf->flag & GP_FRAME_SELECT) { 00642 diff= -gpf->framenum; 00643 gpf->framenum= diff; 00644 } 00645 00646 return 0; 00647 } 00648 00649 static short mirror_gpf_marker (bGPDframe *gpf, Scene *scene) 00650 { 00651 static TimeMarker *marker; 00652 static short initialised = 0; 00653 int diff; 00654 00655 /* In order for this mirror function to work without 00656 * any extra arguments being added, we use the case 00657 * of bezt==NULL to denote that we should find the 00658 * marker to mirror over. The static pointer is safe 00659 * to use this way, as it will be set to null after 00660 * each cycle in which this is called. 00661 */ 00662 00663 if (gpf) { 00664 /* mirroring time */ 00665 if ((gpf->flag & GP_FRAME_SELECT) && (marker)) { 00666 diff= (marker->frame - gpf->framenum); 00667 gpf->framenum= (marker->frame + diff); 00668 } 00669 } 00670 else { 00671 /* initialisation time */ 00672 if (initialised) { 00673 /* reset everything for safety */ 00674 marker = NULL; 00675 initialised = 0; 00676 } 00677 else { 00678 /* try to find a marker */ 00679 marker= ED_markers_get_first_selected(&scene->markers); 00680 if(marker) { 00681 initialised= 1; 00682 } 00683 } 00684 } 00685 00686 return 0; 00687 } 00688 00689 00690 /* mirror selected gp-frames on... */ 00691 void mirror_gplayer_frames (bGPDlayer *gpl, Scene *scene, short mode) 00692 { 00693 switch (mode) { 00694 case 1: /* mirror over current frame */ 00695 gplayer_frames_looper(gpl, scene, mirror_gpf_cframe); 00696 break; 00697 case 2: /* mirror over frame 0 */ 00698 gplayer_frames_looper(gpl, scene, mirror_gpf_yaxis); 00699 break; 00700 case 3: /* mirror over value 0 */ 00701 gplayer_frames_looper(gpl, scene, mirror_gpf_xaxis); 00702 break; 00703 case 4: /* mirror over marker */ 00704 mirror_gpf_marker(NULL, NULL); 00705 gplayer_frames_looper(gpl, scene, mirror_gpf_marker); 00706 mirror_gpf_marker(NULL, NULL); 00707 break; 00708 default: /* just in case */ 00709 gplayer_frames_looper(gpl, scene, mirror_gpf_yaxis); 00710 break; 00711 } 00712 } 00713 00714 /* ***************************************** */ 00715 #endif // XXX disabled until Grease Pencil code stabilises again...