Clear some compiler warnings by commenting some functions, adding others to headers.
[blender.git] / source / blender / editors / gpencil / editaction_gpencil.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2008, Blender Foundation
21  * This is a new part of Blender
22  *
23  * Contributor(s): Joshua Leung
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27  
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <stddef.h>
32 #include <math.h>
33
34 #include "MEM_guardedalloc.h"
35
36 #include "BLI_blenlib.h"
37 #include "BLI_math.h"
38 #include "BLI_utildefines.h"
39
40 #include "DNA_gpencil_types.h"
41 #include "DNA_scene_types.h"
42
43 #include "BKE_fcurve.h"
44 #include "BKE_gpencil.h"
45
46 #include "ED_anim_api.h"
47 #include "ED_gpencil.h"
48 #include "ED_keyframes_edit.h"
49
50 #include "gpencil_intern.h"
51
52 /* ***************************************** */
53 /* NOTE ABOUT THIS FILE:
54  *      This file contains code for editing Grease Pencil data in the Action Editor
55  *      as a 'keyframes', so that a user can adjust the timing of Grease Pencil drawings.
56  *      Therefore, this file mostly contains functions for selecting Grease-Pencil frames.
57  */
58 /* ***************************************** */
59 /* Generics - Loopers */
60
61 /* Loops over the gp-frames for a gp-layer, and applies the given callback */
62 short gplayer_frames_looper (bGPDlayer *gpl, Scene *scene, short (*gpf_cb)(bGPDframe *, Scene *))
63 {
64         bGPDframe *gpf;
65         
66         /* error checker */
67         if (gpl == NULL)
68                 return 0;
69         
70         /* do loop */
71         for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
72                 /* execute callback */
73                 if (gpf_cb(gpf, scene))
74                         return 1;
75         }
76                 
77         /* nothing to return */
78         return 0;
79 }
80
81 /* ****************************************** */
82 /* Data Conversion Tools */
83
84 /* make a listing all the gp-frames in a layer as cfraelems */
85 void gplayer_make_cfra_list (bGPDlayer *gpl, ListBase *elems, short onlysel)
86 {
87         bGPDframe *gpf;
88         CfraElem *ce;
89         
90         /* error checking */
91         if (ELEM(NULL, gpl, elems))
92                 return;
93         
94         /* loop through gp-frames, adding */
95         for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
96                 if ((onlysel == 0) || (gpf->flag & GP_FRAME_SELECT)) {
97                         ce= MEM_callocN(sizeof(CfraElem), "CfraElem");
98                         
99                         ce->cfra= (float)gpf->framenum;
100                         ce->sel= (gpf->flag & GP_FRAME_SELECT) ? 1 : 0;
101                         
102                         BLI_addtail(elems, ce);
103                 }
104         }
105 }
106
107 /* ***************************************** */
108 /* Selection Tools */
109
110 /* check if one of the frames in this layer is selected */
111 short is_gplayer_frame_selected (bGPDlayer *gpl)
112 {
113         bGPDframe *gpf;
114         
115         /* error checking */
116         if (gpl == NULL) 
117                 return 0;
118         
119         /* stop at the first one found */
120         for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
121                 if (gpf->flag & GP_FRAME_SELECT)
122                         return 1;
123         }
124         
125         /* not found */
126         return 0;
127 }
128
129 /* helper function - select gp-frame based on SELECT_* mode */
130 static void gpframe_select (bGPDframe *gpf, short select_mode)
131 {
132         if (gpf == NULL)
133                 return;
134         
135         switch (select_mode) {
136                 case SELECT_ADD:
137                         gpf->flag |= GP_FRAME_SELECT;
138                         break;
139                 case SELECT_SUBTRACT:
140                         gpf->flag &= ~GP_FRAME_SELECT;
141                         break;
142                 case SELECT_INVERT:
143                         gpf->flag ^= GP_FRAME_SELECT;
144                         break;
145         }
146 }
147
148 /* set all/none/invert select (like above, but with SELECT_* modes) */
149 void select_gpencil_frames (bGPDlayer *gpl, short select_mode)
150 {
151         bGPDframe *gpf;
152         
153         /* error checking */
154         if (gpl == NULL) 
155                 return;
156                 
157         /* handle according to mode */
158         for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
159                 gpframe_select(gpf, select_mode);
160         }
161 }
162
163 /* set all/none/invert select */
164 void set_gplayer_frame_selection (bGPDlayer *gpl, short mode)
165 {
166         /* error checking */
167         if (gpl == NULL) 
168                 return;
169         
170         /* now call the standard function */
171         select_gpencil_frames(gpl, mode);
172 }
173
174 /* select the frame in this layer that occurs on this frame (there should only be one at most) */
175 void select_gpencil_frame (bGPDlayer *gpl, int selx, short select_mode)
176 {
177         bGPDframe *gpf;
178         
179         if (gpl == NULL) 
180                 return;
181         
182         /* search through frames for a match */
183         for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
184                 /* there should only be one frame with this frame-number */
185                 if (gpf->framenum == selx) {
186                         gpframe_select(gpf, select_mode);
187                         break;
188                 }
189         }
190 }
191
192 /* select the frames in this layer that occur within the bounds specified */
193 void borderselect_gplayer_frames (bGPDlayer *gpl, float min, float max, short select_mode)
194 {
195         bGPDframe *gpf;
196         
197         if (gpl == NULL)
198                 return;
199         
200         /* only select those frames which are in bounds */
201         for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
202                 if (IN_RANGE(gpf->framenum, min, max))
203                         gpframe_select(gpf, select_mode);
204         }
205 }
206
207 #if 0 // XXX disabled until grease pencil code stabilises again
208
209 /* De-selects or inverts the selection of Layers for a grease-pencil block
210  *      mode: 0 = default behaviour (select all), 1 = test if (de)select all, 2 = invert all 
211  */
212 void deselect_gpencil_layers (void *data, short mode)
213 {
214         ListBase act_data = {NULL, NULL};
215         bActListElem *ale;
216         int filter, sel=1;
217         
218         /* filter data */
219         filter= ACTFILTER_VISIBLE;
220         actdata_filter(&act_data, filter, data, ACTCONT_GPENCIL);
221         
222         /* See if we should be selecting or deselecting */
223         if (mode == 1) {
224                 for (ale= act_data.first; ale; ale= ale->next) {
225                         if (sel == 0) 
226                                 break;
227                         
228                         if (ale->flag & GP_LAYER_SELECT)
229                                 sel= 0;
230                 }
231         }
232         else
233                 sel= 0;
234                 
235         /* Now set the flags */
236         for (ale= act_data.first; ale; ale= ale->next) {
237                 bGPDlayer *gpl= (bGPDlayer *)ale->data;
238                 
239                 if (mode == 2)
240                         gpl->flag ^= GP_LAYER_SELECT;
241                 else if (sel)
242                         gpl->flag |= GP_LAYER_SELECT;
243                 else
244                         gpl->flag &= ~GP_LAYER_SELECT;
245                         
246                 gpl->flag &= ~GP_LAYER_ACTIVE;
247         }
248         
249         /* Cleanup */
250         BLI_freelistN(&act_data);
251 }
252
253 #endif // XXX disabled until Grease Pencil code stabilises again...
254
255 /* ***************************************** */
256 /* Frame Editing Tools */
257
258 #if 0 // XXX disabled until grease pencil code stabilises again
259 /* Delete selected grease-pencil layers */
260 void delete_gpencil_layers (void)
261 {
262         ListBase act_data = {NULL, NULL};
263         bActListElem *ale, *next;
264         void *data;
265         short datatype;
266         int filter;
267         
268         /* determine what type of data we are operating on */
269         data = get_action_context(&datatype);
270         if (data == NULL) return;
271         if (datatype != ACTCONT_GPENCIL) return;
272         
273         /* filter data */
274         filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_CHANNELS | ACTFILTER_SEL);
275         actdata_filter(&act_data, filter, data, datatype);
276         
277         /* clean up grease-pencil layers */
278         for (ale= act_data.first; ale; ale= next) {
279                 bGPdata *gpd= (bGPdata *)ale->owner;
280                 bGPDlayer *gpl= (bGPDlayer *)ale->data;
281                 next= ale->next;
282                 
283                 /* free layer and its data */
284                 if (SEL_GPL(gpl)) {
285                         free_gpencil_frames(gpl);
286                         BLI_freelinkN(&gpd->layers, gpl);
287                 }
288                 
289                 /* free temp memory */
290                 BLI_freelinkN(&act_data, ale);
291         }
292         
293         BIF_undo_push("Delete GPencil Layers");
294 }
295 #endif // XXX disabled until Grease Pencil code stabilises again...
296
297 /* Delete selected frames */
298 void delete_gplayer_frames (bGPDlayer *gpl)
299 {
300         bGPDframe *gpf, *gpfn;
301         
302         /* error checking */
303         if (gpl == NULL)
304                 return;
305                 
306         /* check for frames to delete */
307         for (gpf= gpl->frames.first; gpf; gpf= gpfn) {
308                 gpfn= gpf->next;
309                 
310                 if (gpf->flag & GP_FRAME_SELECT)
311                         gpencil_layer_delframe(gpl, gpf);
312         }
313 }
314
315 /* Duplicate selected frames from given gp-layer */
316 void duplicate_gplayer_frames (bGPDlayer *gpl)
317 {
318         bGPDframe *gpf, *gpfn;
319         
320         /* error checking */
321         if (gpl == NULL)
322                 return;
323         
324         /* duplicate selected frames  */
325         for (gpf= gpl->frames.first; gpf; gpf= gpfn) {
326                 gpfn= gpf->next;
327                 
328                 /* duplicate this frame */
329                 if (gpf->flag & GP_FRAME_SELECT) {
330                         bGPDframe *gpfd; 
331                         
332                         /* duplicate frame, and deselect self */
333                         gpfd= gpencil_frame_duplicate(gpf);
334                         gpf->flag &= ~GP_FRAME_SELECT;
335                         
336                         BLI_insertlinkafter(&gpl->frames, gpf, gpfd);
337                 }
338         }
339 }
340
341 #if 0 // XXX disabled until grease pencil code stabilises again
342 /* -------------------------------------- */
343 /* Copy and Paste Tools */
344 /* - The copy/paste buffer currently stores a set of GP_Layers, with temporary
345  *      GP_Frames with the necessary strokes
346  * - Unless there is only one element in the buffer, names are also tested to check for compatability.
347  * - All pasted frames are offset by the same amount. This is calculated as the difference in the times of
348  *      the current frame and the 'first keyframe' (i.e. the earliest one in all channels).
349  * - The earliest frame is calculated per copy operation.
350  */
351  
352 /* globals for copy/paste data (like for other copy/paste buffers) */
353 ListBase gpcopybuf = {NULL, NULL};
354 static int gpcopy_firstframe= 999999999;
355
356 /* This function frees any MEM_calloc'ed copy/paste buffer data */
357 void free_gpcopybuf ()
358 {
359         free_gpencil_layers(&gpcopybuf); 
360         
361         gpcopybuf.first= gpcopybuf.last= NULL;
362         gpcopy_firstframe= 999999999;
363 }
364
365 /* This function adds data to the copy/paste buffer, freeing existing data first
366  * Only the selected GP-layers get their selected keyframes copied.
367  */
368 void copy_gpdata ()
369 {
370         ListBase act_data = {NULL, NULL};
371         bActListElem *ale;
372         int filter;
373         void *data;
374         short datatype;
375         
376         /* clear buffer first */
377         free_gpcopybuf();
378         
379         /* get data */
380         data= get_action_context(&datatype);
381         if (data == NULL) return;
382         if (datatype != ACTCONT_GPENCIL) return;
383         
384         /* filter data */
385         filter= (ACTFILTER_VISIBLE | ACTFILTER_SEL);
386         actdata_filter(&act_data, filter, data, datatype);
387         
388         /* assume that each of these is an ipo-block */
389         for (ale= act_data.first; ale; ale= ale->next) {
390                 bGPDlayer *gpls, *gpln;
391                 bGPDframe *gpf, *gpfn;
392                 
393                 /* get new layer to put into buffer */
394                 gpls= (bGPDlayer *)ale->data;
395                 gpln= MEM_callocN(sizeof(bGPDlayer), "GPCopyPasteLayer");
396                 
397                 gpln->frames.first= gpln->frames.last= NULL;
398                 strcpy(gpln->info, gpls->info);
399                 
400                 BLI_addtail(&gpcopybuf, gpln);
401                 
402                 /* loop over frames, and copy only selected frames */
403                 for (gpf= gpls->frames.first; gpf; gpf= gpf->next) {
404                         /* if frame is selected, make duplicate it and its strokes */
405                         if (gpf->flag & GP_FRAME_SELECT) {
406                                 /* add frame to buffer */
407                                 gpfn= gpencil_frame_duplicate(gpf);
408                                 BLI_addtail(&gpln->frames, gpfn);
409                                 
410                                 /* check if this is the earliest frame encountered so far */
411                                 if (gpf->framenum < gpcopy_firstframe)
412                                         gpcopy_firstframe= gpf->framenum;
413                         }
414                 }
415         }
416         
417         /* check if anything ended up in the buffer */
418         if (ELEM(NULL, gpcopybuf.first, gpcopybuf.last))
419                 error("Nothing copied to buffer");
420         
421         /* free temp memory */
422         BLI_freelistN(&act_data);
423 }
424
425 void paste_gpdata (Scene *scene)
426 {
427         ListBase act_data = {NULL, NULL};
428         bActListElem *ale;
429         int filter;
430         void *data;
431         short datatype;
432         
433         const int offset = (CFRA - gpcopy_firstframe);
434         short no_name= 0;
435         
436         /* check if buffer is empty */
437         if (ELEM(NULL, gpcopybuf.first, gpcopybuf.last)) {
438                 error("No data in buffer to paste");
439                 return;
440         }
441         /* check if single channel in buffer (disregard names if so)  */
442         if (gpcopybuf.first == gpcopybuf.last)
443                 no_name= 1;
444         
445         /* get data */
446         data= get_action_context(&datatype);
447         if (data == NULL) return;
448         if (datatype != ACTCONT_GPENCIL) return;
449         
450         /* filter data */
451         filter= (ACTFILTER_VISIBLE | ACTFILTER_SEL | ACTFILTER_FOREDIT);
452         actdata_filter(&act_data, filter, data, datatype);
453         
454         /* from selected channels */
455         for (ale= act_data.first; ale; ale= ale->next) {
456                 bGPDlayer *gpld= (bGPDlayer *)ale->data;
457                 bGPDlayer *gpls= NULL;
458                 bGPDframe *gpfs, *gpf;
459                 
460                 /* find suitable layer from buffer to use to paste from */
461                 for (gpls= gpcopybuf.first; gpls; gpls= gpls->next) {
462                         /* check if layer name matches */
463                         if ((no_name) || (strcmp(gpls->info, gpld->info)==0))
464                                 break;
465                 }
466                 
467                 /* this situation might occur! */
468                 if (gpls == NULL)
469                         continue;
470                 
471                 /* add frames from buffer */
472                 for (gpfs= gpls->frames.first; gpfs; gpfs= gpfs->next) {
473                         /* temporarily apply offset to buffer-frame while copying */
474                         gpfs->framenum += offset;
475                         
476                         /* get frame to copy data into (if no frame returned, then just ignore) */
477                         gpf= gpencil_layer_getframe(gpld, gpfs->framenum, 1);
478                         if (gpf) {
479                                 bGPDstroke *gps, *gpsn;
480                                 ScrArea *sa;
481                                 
482                                 /* get area that gp-data comes from */
483                                 //sa= gpencil_data_findowner((bGPdata *)ale->owner);    
484                                 sa = NULL;
485                                 
486                                 /* this should be the right frame... as it may be a pre-existing frame, 
487                                  * must make sure that only compatible stroke types get copied over 
488                                  *      - we cannot just add a duplicate frame, as that would cause errors
489                                  *      - need to check for compatible types to minimise memory usage (copying 'junk' over)
490                                  */
491                                 for (gps= gpfs->strokes.first; gps; gps= gps->next) {
492                                         short stroke_ok;
493                                         
494                                         /* if there's an area, check that it supports this type of stroke */
495                                         if (sa) {
496                                                 stroke_ok= 0;
497                                                 
498                                                 /* check if spacetype supports this type of stroke
499                                                  *      - NOTE: must sync this with gp_paint_initstroke() in gpencil.c
500                                                  */
501                                                 switch (sa->spacetype) {
502                                                         case SPACE_VIEW3D: /* 3D-View: either screen-aligned or 3d-space */
503                                                                 if ((gps->flag == 0) || (gps->flag & GP_STROKE_3DSPACE))
504                                                                         stroke_ok= 1;
505                                                                 break;
506                                                                 
507                                                         case SPACE_NODE: /* Nodes Editor: either screen-aligned or view-aligned */
508                                                         case SPACE_IMAGE: /* Image Editor: either screen-aligned or view\image-aligned */
509                                                                 if ((gps->flag == 0) || (gps->flag & GP_STROKE_2DSPACE))
510                                                                         stroke_ok= 1;
511                                                                 break;
512                                                                 
513                                                         case SPACE_SEQ: /* Sequence Editor: either screen-aligned or view-aligned */
514                                                                 if ((gps->flag == 0) || (gps->flag & GP_STROKE_2DIMAGE))
515                                                                         stroke_ok= 1;
516                                                                 break;
517                                                 }
518                                         }
519                                         else
520                                                 stroke_ok= 1;
521                                         
522                                         /* if stroke is ok, we make a copy of this stroke and add to frame */
523                                         if (stroke_ok) {
524                                                 /* make a copy of stroke, then of its points array */
525                                                 gpsn= MEM_dupallocN(gps);
526                                                 gpsn->points= MEM_dupallocN(gps->points);
527                                                 
528                                                 /* append stroke to frame */
529                                                 BLI_addtail(&gpf->strokes, gpsn);
530                                         }
531                                 }
532                                 
533                                 /* if no strokes (i.e. new frame) added, free gpf */
534                                 if (gpf->strokes.first == NULL)
535                                         gpencil_layer_delframe(gpld, gpf);
536                         }
537                         
538                         /* unapply offset from buffer-frame */
539                         gpfs->framenum -= offset;
540                 }
541         }
542         
543         /* free temp memory */
544         BLI_freelistN(&act_data);
545         
546         /* undo and redraw stuff */
547         BIF_undo_push("Paste Grease Pencil Frames");
548 }
549
550 /* -------------------------------------- */
551 /* Snap Tools */
552
553 static short snap_gpf_nearest (bGPDframe *gpf, Scene *scene)
554 {
555         if (gpf->flag & GP_FRAME_SELECT)
556                 gpf->framenum= (int)(floor(gpf->framenum+0.5));
557         return 0;
558 }
559
560 static short snap_gpf_nearestsec (bGPDframe *gpf, Scene *scene)
561 {
562         float secf = (float)FPS;
563         if (gpf->flag & GP_FRAME_SELECT)
564                 gpf->framenum= (int)(floor(gpf->framenum/secf + 0.5f) * secf);
565         return 0;
566 }
567
568 static short snap_gpf_cframe (bGPDframe *gpf, Scene *scene)
569 {
570         if (gpf->flag & GP_FRAME_SELECT)
571                 gpf->framenum= (int)CFRA;
572         return 0;
573 }
574
575 static short snap_gpf_nearmarker (bGPDframe *gpf, Scene *scene)
576 {
577         if (gpf->flag & GP_FRAME_SELECT)
578                 gpf->framenum= (int)find_nearest_marker_time(&scene->markers, (float)gpf->framenum);
579         return 0;
580 }
581
582
583 /* snap selected frames to ... */
584 void snap_gplayer_frames (bGPDlayer *gpl, Scene *scene, short mode)
585 {
586         switch (mode) {
587                 case 1: /* snap to nearest frame */
588                         gplayer_frames_looper(gpl, scene, snap_gpf_nearest);
589                         break;
590                 case 2: /* snap to current frame */
591                         gplayer_frames_looper(gpl, scene, snap_gpf_cframe);
592                         break;
593                 case 3: /* snap to nearest marker */
594                         gplayer_frames_looper(gpl, scene, snap_gpf_nearmarker);
595                         break;
596                 case 4: /* snap to nearest second */
597                         gplayer_frames_looper(gpl, scene, snap_gpf_nearestsec);
598                         break;
599                 default: /* just in case */
600                         gplayer_frames_looper(gpl, scene, snap_gpf_nearest);
601                         break;
602         }
603 }
604
605 /* -------------------------------------- */
606 /* Mirror Tools */
607
608 static short mirror_gpf_cframe (bGPDframe *gpf, Scene *scene)
609 {
610         int diff;
611         
612         if (gpf->flag & GP_FRAME_SELECT) {
613                 diff= CFRA - gpf->framenum;
614                 gpf->framenum= CFRA;
615         }
616         
617         return 0;
618 }
619
620 static short mirror_gpf_yaxis (bGPDframe *gpf, Scene *scene)
621 {
622         int diff;
623         
624         if (gpf->flag & GP_FRAME_SELECT) {
625                 diff= -gpf->framenum;
626                 gpf->framenum= diff;
627         }
628         
629         return 0;
630 }
631
632 static short mirror_gpf_xaxis (bGPDframe *gpf, Scene *scene)
633 {
634         int diff;
635         
636         if (gpf->flag & GP_FRAME_SELECT) {
637                 diff= -gpf->framenum;
638                 gpf->framenum= diff;
639         }
640         
641         return 0;
642 }
643
644 static short mirror_gpf_marker (bGPDframe *gpf, Scene *scene)
645 {
646         static TimeMarker *marker;
647         static short initialised = 0;
648         int diff;
649         
650         /* In order for this mirror function to work without
651          * any extra arguments being added, we use the case
652          * of bezt==NULL to denote that we should find the 
653          * marker to mirror over. The static pointer is safe
654          * to use this way, as it will be set to null after 
655          * each cycle in which this is called.
656          */
657         
658         if (gpf) {
659                 /* mirroring time */
660                 if ((gpf->flag & GP_FRAME_SELECT) && (marker)) {
661                         diff= (marker->frame - gpf->framenum);
662                         gpf->framenum= (marker->frame + diff);
663                 }
664         }
665         else {
666                 /* initialisation time */
667                 if (initialised) {
668                         /* reset everything for safety */
669                         marker = NULL;
670                         initialised = 0;
671                 }
672                 else {
673                         /* try to find a marker */
674                         marker= ED_markers_get_first_selected(&scene->markers);
675                         if(marker) {
676                                 initialised= 1;
677                         }
678                 }
679         }
680         
681         return 0;
682 }
683
684
685 /* mirror selected gp-frames on... */
686 void mirror_gplayer_frames (bGPDlayer *gpl, Scene *scene, short mode)
687 {
688         switch (mode) {
689                 case 1: /* mirror over current frame */
690                         gplayer_frames_looper(gpl, scene, mirror_gpf_cframe);
691                         break;
692                 case 2: /* mirror over frame 0 */
693                         gplayer_frames_looper(gpl, scene, mirror_gpf_yaxis);
694                         break;
695                 case 3: /* mirror over value 0 */
696                         gplayer_frames_looper(gpl, scene, mirror_gpf_xaxis);
697                         break;
698                 case 4: /* mirror over marker */
699                         mirror_gpf_marker(NULL, NULL);
700                         gplayer_frames_looper(gpl, scene, mirror_gpf_marker);
701                         mirror_gpf_marker(NULL, NULL);
702                         break;
703                 default: /* just in case */
704                         gplayer_frames_looper(gpl, scene, mirror_gpf_yaxis);
705                         break;
706         }
707 }
708
709 /* ***************************************** */
710 #endif // XXX disabled until Grease Pencil code stabilises again...