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