Enabled GCC -Wwrite-strings warning for CMake and replaced many 'char's for 'const...
[blender-staging.git] / source / blender / blenkernel / intern / 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
37 #include "BLI_blenlib.h"
38
39 #include "DNA_gpencil_types.h"
40
41 #include "BKE_global.h"
42 #include "BKE_gpencil.h"
43 #include "BKE_library.h"
44 #include "BKE_main.h"
45 #include "BKE_utildefines.h"
46
47
48 /* ************************************************** */
49 /* GENERAL STUFF */
50
51 /* --------- Memory Management ------------ */
52
53 /* Free strokes belonging to a gp-frame */
54 void free_gpencil_strokes (bGPDframe *gpf)
55 {
56         bGPDstroke *gps, *gpsn;
57         
58         /* error checking */
59         if (gpf == NULL) return;
60         
61         /* free strokes */
62         for (gps= gpf->strokes.first; gps; gps= gpsn) {
63                 gpsn= gps->next;
64                 
65                 /* free stroke memory arrays, then stroke itself */
66                 if (gps->points) MEM_freeN(gps->points);
67                 BLI_freelinkN(&gpf->strokes, gps);
68         }
69 }
70
71 /* Free all of a gp-layer's frames */
72 void free_gpencil_frames (bGPDlayer *gpl)
73 {
74         bGPDframe *gpf, *gpfn;
75         
76         /* error checking */
77         if (gpl == NULL) return;
78         
79         /* free frames */
80         for (gpf= gpl->frames.first; gpf; gpf= gpfn) {
81                 gpfn= gpf->next;
82                 
83                 /* free strokes and their associated memory */
84                 free_gpencil_strokes(gpf);
85                 BLI_freelinkN(&gpl->frames, gpf);
86         }
87 }
88
89 /* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */
90 void free_gpencil_layers (ListBase *list) 
91 {
92         bGPDlayer *gpl, *gpln;
93         
94         /* error checking */
95         if (list == NULL) return;
96         
97         /* delete layers*/
98         for (gpl= list->first; gpl; gpl= gpln) {
99                 gpln= gpl->next;
100                 
101                 /* free layers and their data */
102                 free_gpencil_frames(gpl);
103                 BLI_freelinkN(list, gpl);
104         }
105 }
106
107 /* Free all of GPencil datablock's related data, but not the block itself */
108 void free_gpencil_data (bGPdata *gpd)
109 {
110         /* free layers */
111         free_gpencil_layers(&gpd->layers);
112 }
113
114 /* -------- Container Creation ---------- */
115
116 /* add a new gp-frame to the given layer */
117 bGPDframe *gpencil_frame_addnew (bGPDlayer *gpl, int cframe)
118 {
119         bGPDframe *gpf, *gf;
120         short state=0;
121         
122         /* error checking */
123         if ((gpl == NULL) || (cframe <= 0))
124                 return NULL;
125                 
126         /* allocate memory for this frame */
127         gpf= MEM_callocN(sizeof(bGPDframe), "bGPDframe");
128         gpf->framenum= cframe;
129         
130         /* find appropriate place to add frame */
131         if (gpl->frames.first) {
132                 for (gf= gpl->frames.first; gf; gf= gf->next) {
133                         /* check if frame matches one that is supposed to be added */
134                         if (gf->framenum == cframe) {
135                                 state= -1;
136                                 break;
137                         }
138                         
139                         /* if current frame has already exceeded the frame to add, add before */
140                         if (gf->framenum > cframe) {
141                                 BLI_insertlinkbefore(&gpl->frames, gf, gpf);
142                                 state= 1;
143                                 break;
144                         }
145                 }
146         }
147         
148         /* check whether frame was added successfully */
149         if (state == -1) {
150                 MEM_freeN(gpf);
151                 printf("Error: frame (%d) existed already for this layer \n", cframe);
152         }
153         else if (state == 0) {
154                 /* add to end then! */
155                 BLI_addtail(&gpl->frames, gpf);
156         }
157         
158         /* return frame */
159         return gpf;
160 }
161
162 /* add a new gp-layer and make it the active layer */
163 bGPDlayer *gpencil_layer_addnew (bGPdata *gpd)
164 {
165         bGPDlayer *gpl;
166         
167         /* check that list is ok */
168         if (gpd == NULL)
169                 return NULL;
170                 
171         /* allocate memory for frame and add to end of list */
172         gpl= MEM_callocN(sizeof(bGPDlayer), "bGPDlayer");
173         
174         /* add to datablock */
175         BLI_addtail(&gpd->layers, gpl);
176         
177         /* set basic settings */
178         gpl->color[3]= 0.9f;
179         gpl->thickness = 3;
180         
181         /* auto-name */
182         sprintf(gpl->info, "GP_Layer");
183         BLI_uniquename(&gpd->layers, gpl, "GP_Layer", '.', offsetof(bGPDlayer, info[0]), sizeof(gpl->info));
184         
185         /* make this one the active one */
186         gpencil_layer_setactive(gpd, gpl);
187         
188         /* return layer */
189         return gpl;
190 }
191
192 /* add a new gp-datablock */
193 bGPdata *gpencil_data_addnew (const char name[])
194 {
195         bGPdata *gpd;
196         
197         /* allocate memory for a new block */
198         gpd= alloc_libblock(&G.main->gpencil, ID_GD, name);
199         
200         /* initial settings */
201         gpd->flag = (GP_DATA_DISPINFO|GP_DATA_EXPAND);
202         
203         /* for now, stick to view is also enabled by default
204          * since this is more useful...
205          */
206         gpd->flag |= GP_DATA_VIEWALIGN;
207         
208         return gpd;
209 }
210
211 /* -------- Data Duplication ---------- */
212
213 /* make a copy of a given gpencil frame */
214 bGPDframe *gpencil_frame_duplicate (bGPDframe *src)
215 {
216         bGPDstroke *gps, *gpsd;
217         bGPDframe *dst;
218         
219         /* error checking */
220         if (src == NULL)
221                 return NULL;
222                 
223         /* make a copy of the source frame */
224         dst= MEM_dupallocN(src);
225         dst->prev= dst->next= NULL;
226         
227         /* copy strokes */
228         dst->strokes.first = dst->strokes.last= NULL;
229         for (gps= src->strokes.first; gps; gps= gps->next) {
230                 /* make copy of source stroke, then adjust pointer to points too */
231                 gpsd= MEM_dupallocN(gps);
232                 gpsd->points= MEM_dupallocN(gps->points);
233                 
234                 BLI_addtail(&dst->strokes, gpsd);
235         }
236         
237         /* return new frame */
238         return dst;
239 }
240
241 /* make a copy of a given gpencil layer */
242 bGPDlayer *gpencil_layer_duplicate (bGPDlayer *src)
243 {
244         bGPDframe *gpf, *gpfd;
245         bGPDlayer *dst;
246         
247         /* error checking */
248         if (src == NULL)
249                 return NULL;
250                 
251         /* make a copy of source layer */
252         dst= MEM_dupallocN(src);
253         dst->prev= dst->next= NULL;
254         
255         /* copy frames */
256         dst->frames.first= dst->frames.last= NULL;
257         for (gpf= src->frames.first; gpf; gpf= gpf->next) {
258                 /* make a copy of source frame */
259                 gpfd= gpencil_frame_duplicate(gpf);
260                 BLI_addtail(&dst->frames, gpfd);
261                 
262                 /* if source frame was the current layer's 'active' frame, reassign that too */
263                 if (gpf == dst->actframe)
264                         dst->actframe= gpfd;
265         }
266         
267         /* return new layer */
268         return dst;
269 }
270
271 /* make a copy of a given gpencil datablock */
272 bGPdata *gpencil_data_duplicate (bGPdata *src)
273 {
274         bGPDlayer *gpl, *gpld;
275         bGPdata *dst;
276         
277         /* error checking */
278         if (src == NULL)
279                 return NULL;
280         
281         /* make a copy of the base-data */
282         dst= MEM_dupallocN(src);
283         
284         /* copy layers */
285         dst->layers.first= dst->layers.last= NULL;
286         for (gpl= src->layers.first; gpl; gpl= gpl->next) {
287                 /* make a copy of source layer and its data */
288                 gpld= gpencil_layer_duplicate(gpl);
289                 BLI_addtail(&dst->layers, gpld);
290         }
291         
292         /* return new */
293         return dst;
294 }
295
296 /* -------- GP-Frame API ---------- */
297
298 /* delete the last stroke of the given frame */
299 void gpencil_frame_delete_laststroke (bGPDlayer *gpl, bGPDframe *gpf)
300 {
301         bGPDstroke *gps= (gpf) ? gpf->strokes.last : NULL;
302         int cfra = (gpf) ? gpf->framenum : 0; /* assume that the current frame was not locked */
303         
304         /* error checking */
305         if (ELEM(NULL, gpf, gps))
306                 return;
307         
308         /* free the stroke and its data */
309         MEM_freeN(gps->points);
310         BLI_freelinkN(&gpf->strokes, gps);
311         
312         /* if frame has no strokes after this, delete it */
313         if (gpf->strokes.first == NULL) {
314                 gpencil_layer_delframe(gpl, gpf);
315                 gpencil_layer_getframe(gpl, cfra, 0);
316         }
317 }
318
319 /* -------- GP-Layer API ---------- */
320
321 /* get the appropriate gp-frame from a given layer
322  *      - this sets the layer's actframe var (if allowed to)
323  *      - extension beyond range (if first gp-frame is after all frame in interest and cannot add)
324  */
325 bGPDframe *gpencil_layer_getframe (bGPDlayer *gpl, int cframe, short addnew)
326 {
327         bGPDframe *gpf = NULL;
328         short found = 0;
329         
330         /* error checking */
331         if (gpl == NULL) return NULL;
332         if (cframe <= 0) cframe = 1;
333         
334         /* check if there is already an active frame */
335         if (gpl->actframe) {
336                 gpf= gpl->actframe;
337                 
338                 /* do not allow any changes to layer's active frame if layer is locked from changes
339                  * or if the layer has been set to stay on the current frame
340                  */
341                 if (gpl->flag & (GP_LAYER_LOCKED|GP_LAYER_FRAMELOCK))
342                         return gpf;
343                 /* do not allow any changes to actframe if frame has painting tag attached to it */
344                 if (gpf->flag & GP_FRAME_PAINT) 
345                         return gpf;
346                 
347                 /* try to find matching frame */
348                 if (gpf->framenum < cframe) {
349                         for (; gpf; gpf= gpf->next) {
350                                 if (gpf->framenum == cframe) {
351                                         found= 1;
352                                         break;
353                                 }
354                                 else if ((gpf->next) && (gpf->next->framenum > cframe)) {
355                                         found= 1;
356                                         break;
357                                 }
358                         }
359                         
360                         /* set the appropriate frame */
361                         if (addnew) {
362                                 if ((found) && (gpf->framenum == cframe))
363                                         gpl->actframe= gpf;
364                                 else
365                                         gpl->actframe= gpencil_frame_addnew(gpl, cframe);
366                         }
367                         else if (found)
368                                 gpl->actframe= gpf;
369                         else
370                                 gpl->actframe= gpl->frames.last;
371                 }
372                 else {
373                         for (; gpf; gpf= gpf->prev) {
374                                 if (gpf->framenum <= cframe) {
375                                         found= 1;
376                                         break;
377                                 }
378                         }
379                         
380                         /* set the appropriate frame */
381                         if (addnew) {
382                                 if ((found) && (gpf->framenum == cframe))
383                                         gpl->actframe= gpf;
384                                 else
385                                         gpl->actframe= gpencil_frame_addnew(gpl, cframe);
386                         }
387                         else if (found)
388                                 gpl->actframe= gpf;
389                         else
390                                 gpl->actframe= gpl->frames.first;
391                 }
392         }
393         else if (gpl->frames.first) {
394                 /* check which of the ends to start checking from */
395                 const int first= ((bGPDframe *)(gpl->frames.first))->framenum;
396                 const int last= ((bGPDframe *)(gpl->frames.last))->framenum;
397                 
398                 if (abs(cframe-first) > abs(cframe-last)) {
399                         /* find gp-frame which is less than or equal to cframe */
400                         for (gpf= gpl->frames.last; gpf; gpf= gpf->prev) {
401                                 if (gpf->framenum <= cframe) {
402                                         found= 1;
403                                         break;
404                                 }
405                         }
406                 }
407                 else {
408                         /* find gp-frame which is less than or equal to cframe */
409                         for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
410                                 if (gpf->framenum <= cframe) {
411                                         found= 1;
412                                         break;
413                                 }
414                         }
415                 }
416                 
417                 /* set the appropriate frame */
418                 if (addnew) {
419                         if ((found) && (gpf->framenum == cframe))
420                                 gpl->actframe= gpf;
421                         else
422                                 gpl->actframe= gpencil_frame_addnew(gpl, cframe);
423                 }
424                 else if (found)
425                         gpl->actframe= gpf;
426                 else {
427                         /* unresolved errogenous situation! */
428                         printf("Error: cannot find appropriate gp-frame \n");
429                         /* gpl->actframe should still be NULL */
430                 }
431         }
432         else {
433                 /* currently no frames (add if allowed to) */
434                 if (addnew)
435                         gpl->actframe= gpencil_frame_addnew(gpl, cframe);
436                 else {
437                         /* don't do anything... this may be when no frames yet! */
438                         /* gpl->actframe should still be NULL */
439                 }
440         }
441         
442         /* return */
443         return gpl->actframe;
444 }
445
446 /* delete the given frame from a layer */
447 void gpencil_layer_delframe (bGPDlayer *gpl, bGPDframe *gpf)
448 {
449         /* error checking */
450         if (ELEM(NULL, gpl, gpf))
451                 return;
452                 
453         /* free the frame and its data */
454         free_gpencil_strokes(gpf);
455         BLI_freelinkN(&gpl->frames, gpf);
456         gpl->actframe = NULL;
457 }
458
459 /* get the active gp-layer for editing */
460 bGPDlayer *gpencil_layer_getactive (bGPdata *gpd)
461 {
462         bGPDlayer *gpl;
463         
464         /* error checking */
465         if (ELEM(NULL, gpd, gpd->layers.first))
466                 return NULL;
467                 
468         /* loop over layers until found (assume only one active) */
469         for (gpl=gpd->layers.first; gpl; gpl=gpl->next) {
470                 if (gpl->flag & GP_LAYER_ACTIVE)
471                         return gpl;
472         }
473         
474         /* no active layer found */
475         return NULL;
476 }
477
478 /* set the active gp-layer */
479 void gpencil_layer_setactive (bGPdata *gpd, bGPDlayer *active)
480 {
481         bGPDlayer *gpl;
482         
483         /* error checking */
484         if (ELEM3(NULL, gpd, gpd->layers.first, active))
485                 return;
486                 
487         /* loop over layers deactivating all */
488         for (gpl=gpd->layers.first; gpl; gpl=gpl->next)
489                 gpl->flag &= ~GP_LAYER_ACTIVE;
490         
491         /* set as active one */
492         active->flag |= GP_LAYER_ACTIVE;
493 }
494
495 /* delete the active gp-layer */
496 void gpencil_layer_delactive (bGPdata *gpd)
497 {
498         bGPDlayer *gpl= gpencil_layer_getactive(gpd);
499         
500         /* error checking */
501         if (ELEM(NULL, gpd, gpl)) 
502                 return;
503         
504         /* free layer */        
505         free_gpencil_frames(gpl);
506         BLI_freelinkN(&gpd->layers, gpl);
507 }
508
509 /* ************************************************** */