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