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